Idempotency and retries
Retry create, verify, status, and webhook work without duplicate money movement.
Deposit creation
merchant_id is unique within an organization.
For H2H, a repeated request returns the existing deposit with HTTP 200 only
when these immutable fields match:
- numeric amount;
- requested payment method;
- normalized payer phone;
- redirect URL;
- metadata, compared with object keys canonically sorted.
The original creation returns 201. Reusing the ID with different immutable
fields returns 409 merchant_id_exists.
{
"error": {
"code": "merchant_id_exists",
"message": "Merchant ID already exists with different immutable deposit fields."
}
}If another request is actively creating the same H2H ID, OmniPay can return
409 asking you to retry shortly. Retry the exact request; do not generate a
second merchant ID unless you intend to create a second payment.
Redirect checkout retains its previous uniqueness behavior and does not use the H2H immutable-field replay contract.
Verification transaction IDs
The tuple of payment method and normalized payment transaction ID is unique. Retrying the same transaction ID for the same deposit returns its existing attempt and does not consume another of the three allowed attempts.
After a network failure:
- keep the same request JSON and payment transaction ID;
- generate a fresh current timestamp;
- recompute the signature;
- retry;
- accept either
200or202and continue from the returned attempt/deposit state.
Status reads
GET requests are safe to retry. H2H status reads may also persist a clock-driven
terminal transition after a deadline, so two consecutive reads can legitimately
show a pending state followed by expired or failed.
Webhook consumers
Treat delivery as at least once. Persist the verified Svix message ID and apply
your business transition in one transaction. A duplicate should return 2xx
without repeating fulfillment.
Retry matrix
| Result | Retry? | Strategy |
|---|---|---|
| Network timeout / connection reset | Yes | Same business ID/body; fresh timestamp and signature for H2H |
400 invalid_request | No | Correct the request |
401 stale_signature | Yes | Correct clock, then re-sign |
401 invalid_signature | No, unchanged | Fix canonicalization/raw bytes |
403 forbidden | No | Enable feature/permission |
409 during identical creation | Yes, briefly | Same request after short backoff |
409 immutable fields differ | No | Investigate ID reuse |
409 verification already processing | Poll | Do not submit a new transaction ID |
503 temporary service failure | Yes | Exponential backoff with the same idempotency data |