Key concepts

Idempotency

Qualy supports idempotent requests for financial mutation endpoints, allowing you to safely retry requests without the risk of performing the same operation twice. This is especially important for payment operations where network issues or timeouts may leave you uncertain whether a request was processed.


How it works

Financial endpoints such as transactions, payment intents, payment splits, and orders support idempotency. Qualy uses two mechanisms to prevent duplicates:

  1. Idempotency key (recommended) -- You provide an explicit key via the Idempotency-Key header.
  2. Automatic fingerprinting -- If no key is provided, Qualy automatically generates a fingerprint based on the request body to detect identical requests.

When an idempotency key is provided, it takes precedence over automatic fingerprinting.


Using the Idempotency-Key header

Include the Idempotency-Key header in your request with a unique value (e.g. a UUID) that identifies the intended operation:

try {
  const response = await fetch('https://api.qualyhq.com/v1/payment-intents/create', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'ApiKey your-api-key-here',
      'X-TENANT-ID': 'your-tenant-id-here',
      'Idempotency-Key': '550e8400-e29b-41d4-a716-446655440000',
    },
    body: JSON.stringify({
      "intentType": "ad-hoc",
      "contact": "656b9ef1a3258074a705433b",
      "dueAt": "2025-05-10T14:26:07.369Z",
      "currency": "AUD",
      "items": [
        {
          "name": "Tuition fee",
          "description": "",
          "category": "Course",
          "amount": 100000
        }
      ],
    }),
  });

  if (response.ok) {
    const data = await response.json();

    console.log(data);
  } else {
    throw new Error(`Request failed with status: ${response.status}`);
  }
} catch (error) {
  console.error(error);
}

Behavior

ScenarioResult
First request with a given keyRequest is processed normally and the response is cached.
Retry with the same key and the same bodyThe cached response from the original request is returned. The operation is not executed again.
Same key but different request bodyHTTP 422 Unprocessable Entity is returned. This prevents replay attacks where a previously used key is reused with a modified amount or other parameters.
No Idempotency-Key header providedQualy automatically detects duplicate requests by fingerprinting the request body. Identical requests within the deduplication window are treated as retries.

Key reuse with different body

If you send a request with the same Idempotency-Key but a different request body, Qualy will reject it with HTTP 422. Always generate a new key for each unique operation.


Supported endpoints

Idempotency is enforced on all financial mutation endpoints:

  • Payment intents -- POST /v1/payment-intents/create
  • Transactions -- POST /v1/transactions/create
  • Payment splits -- POST /v1/payment-splits/create
  • Orders -- POST /v1/orders/create

Best practices

  • Generate a unique key per operation -- Use a UUID or another unique identifier for each distinct payment or transaction. Do not reuse keys across different operations.
  • Store keys alongside your records -- Save the idempotency key with the corresponding record in your system so you can reliably retry with the same key if needed.
  • Retry safely on network errors -- If a request times out or you receive a network error, retry with the same Idempotency-Key to safely determine whether the original request was processed.
  • Keys expire after 24 hours -- Idempotency keys are valid for 24 hours after the first request. After that, the same key can be reused for a new operation.
Previous
Querying data