Idempotency-Key header on every money-moving call. AptaPay claims
the key before making any provider call, so a network failure mid-request
can never leave you unable to tell whether money moved.
What the key guarantees
The second row is the one that protects you. A key is bound to a fingerprint
of the request — the amount, the destination, the currency and the other
money-determining fields. If those differ, it is not a retry, so we refuse it
rather than guessing which one you meant.
Keys are scoped to your tenant
Your keys are yours. Another tenant using the same string cannot collide with you, and cannot probe whether one of your keys exists.Choosing a key
Derive it from the operation in your own system, not from the clock:idempotency.ts
Recovering from an unknown outcome
Because the key is claimed before the provider is contacted, “no record” genuinely means the provider was never called. That makes recovery deterministic:1
Retry with the same key
If nothing moved, you get a fresh attempt. If it did move, you get the
original response replayed rather than a second charge.
2
If the error is ambiguous, poll instead
Call
GET /v1/collections/{reference} or GET /v1/payouts/{reference}
until it reaches a terminal status. Do not reverse. See
Errors.Where it applies
Every money-moving endpoint:POST /v1/collections, POST /v1/payouts, and
POST /v1/fx/exchange. Quotes and reads do not need a key, though sending
one is harmless.