Host-to-Host

Reliability

Idempotency, retries, webhook delivery and reconciliation — how not to charge twice and how not to miss a payment.

Idempotency

Send Idempotency-Key on every call that moves money. A repeat with the same key and the same body returns the original response with Idempotent-Replayed: true — no second charge. The same key with a different body is a bug on your side and we say so: 409 idempotency_conflict.

Derive the key from your order, not from the attempt. A fresh UUID per retry defeats the whole mechanism — that is exactly the request that produces a double charge. Something like order-88213-attempt-1 is stable across a timeout, a process restart and a token refresh.

The scope is your merchant, so a retry keeps deduplicating even if your bearer token rotated in between. Records live for 24 hours.

Rate limits

Limits are per merchant and follow your tier — your traffic is never affected by another merchant's. Rejections return 429 with Retry-After and the X-RateLimit-* headers. Back off on the header; do not retry immediately.

Webhook delivery

Attempts19
BackoffExponential (2^n minutes), capped at 6 hours
Total window~74 hours
Timeout per attempt10 seconds

Return 2xx as soon as you have persisted the event and do the real work asynchronously. Anything slower than 10 seconds is recorded as a failure and retried, which is how an endpoint that is merely slow ends up processing the same event repeatedly.

After the window an event is parked rather than dropped: when your endpoint starts responding again we drain what accumulated. You will not silently lose the events from an outage.

Make your handler idempotent. A network hiccup after you returned 200 means the same X-Key2Pay-Delivery arrives twice. Deduplicate on it, or on the transaction id plus the event name.

Reconciliation

Poll GET /payments/{id} for anything still pending after its due date. It is authoritative — we query the provider behind it — and it is what closes the gap when a webhook is lost.

GET/api/v1/payments/{id}secret key

Authoritative status of one charge. Use it as your reconciliation backstop.

Request
curl https://sandbox.key2pay.ai/api/v1/payments/TXN-MT8E00EB-V5OK \
  -H "Authorization: Bearer sk_test_…"
Response
{
  "id": "TXN-MT8E00EB-V5OK",
  "status": "completed",
  "amount": 100,
  "currency": "USD",
  "amountLocal": 1820.50,
  "currencyLocal": "MXN",
  "merchantOrderId": "order-88213",
  "timestamps": { "created": "…", "paymentReceived": "…" }
}