Miracle Docs

Idempotency

Use the Idempotency-Key header to safely retry requests without creating duplicate operations.


Why idempotency matters

Network errors, timeouts, and client-side retries can leave you unsure whether a request succeeded. Without idempotency, retrying a failed request could create duplicate payments, double-charge a customer, or issue a refund twice. The Idempotency-Key header ensures each operation happens exactly once — even if you send the same request multiple times.


How to use

Send an Idempotency-Key header on every write request (POST, PUT, PATCH, DELETE). The value should be a UUID — this is the recommended format. Any unique string is accepted, but UUID is preferred.

If you retry a request with the same key, Miracle returns the original response without executing the operation again.

curl -X POST https://api.miracle.com/v1/payments \
  -H "Authorization: Bearer sk_test_your_secret_key" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order_12345_payment" \
  -d '{
    "amount": { "currency": "USD", "valueMinor": 5000 },
    "merchantReference": "order-12345",
    "paymentMethod": { "type": "card", "token": "tok_xxx" }
  }'
const response = await fetch('https://api.miracle.com/v1/payments', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer sk_test_your_secret_key',
    'Content-Type': 'application/json',
    'Idempotency-Key': 'order_12345_payment',
  },
  body: JSON.stringify({
    amount: { currency: 'USD', valueMinor: 5000 },
    merchantReference: 'order-12345',
    paymentMethod: { type: 'card', token: 'tok_xxx' },
  }),
});

const { data: payment } = await response.json();

Behavior

ScenarioResult
Same key + same request bodyReturns the cached original response. No new operation is created.
Same key + different request bodyReturns 409 Conflict with error code DUPLICATE_TRANSACTION.
Key not provided on a write endpointReturns 400 Bad Request.

Keys expire after 24 hours by default. The TTL is configurable at the platform level with a minimum of 24 hours. After expiration, the same key can be reused for a new request.

Keys are scoped per merchant and per endpoint — the same key used by different merchants or on different endpoints will not conflict.


When to use

The Idempotency-Key header is required on all write operations. The most important endpoints:

EndpointOperation
POST /v1/paymentsCreate a payment
POST /v1/payments/{id}/captureCapture an authorized payment
POST /v1/payments/{id}/refundRefund a payment
POST /v1/payments/{id}/cancelCancel / void a payment
POST /v1/checkout-sessionsCreate a checkout session
POST /v1/hpp/sessionsCreate a hosted payment page session

Best practices

  • Always send an idempotency key on write operations. Requests without a key are rejected.
  • Use deterministic keys tied to your business logic rather than random UUIDs. For example, {orderId}_payment for payment creation and {orderId}_refund for refunds. This way, retries happen naturally even if your client crashes and restarts.
  • Don't reuse keys across different operations. A key used for payment creation should not be reused for a refund — even after the 24-hour expiration.
  • Store the key alongside your order record so you can retry with the same value if needed.

On this page