Orders & Postbacks › Retries & Idempotency
Retries & Idempotency
PriceFirst automatically retries failed postbacks with exponential backoff. Every attempt is logged on the order, and every retry carries the same order_code / X-PriceFirst-Idempotency so your handler can safely dedupe.
Attempt schedule
The first delivery is immediate (background task kicked off on order creation). If it fails, subsequent attempts are scheduled with the following delays:
| Attempt | Delay from previous failure |
|---|---|
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 15 minutes |
| 5 | 1 hour |
| 6 | 6 hours |
| 7 | 24 hours |
Retries stop as soon as:
- The marchant responds HTTP 200 with a valid JSON body
{ status: 200, order_id }, or - The attempt count reaches (default
6), or - An admin manually marks the order
delivered, or postbackRetryEnabledis toggledfalse. Existing retries are left in place — they will either succeed or hit the attempt ceiling.
Admins can still manually trigger a resend at any time.
Idempotency
Every attempt for the same order sends:
- The same JSON payload (
order_codestays constant). - The same
X-PriceFirst-Idempotencyheader (equal toorder_code). - A different
X-PriceFirst-Timestampand therefore a differentX-PriceFirst-Signature.
Dedupe on order_code (or X-PriceFirst-Idempotency), not on the signature. If you see the same order_code twice, return the same transaction ID you returned the first time — don't create a new internal record.
Attempt history on the order
Each order stores a full append-only log under Order.attempts in dashboard that is provided to marchat:
{
"attemptNumber": 3,
"startedAt": "2026-04-22T10:02:00.000Z",
"finishedAt": "2026-04-22T10:02:01.187Z",
"status": "failure",
"httpStatus": 502,
"responseBody": "<html><body>Bad Gateway</body></html>",
"error": "HTTP 502: Bad Gateway",
"durationMs": 1187
}statusispending,success, orfailure.responseBodyis truncated to 512 characters.
Failure classification
Any of the following marks an attempt as failure:
- Non-
2xxHTTP status. - Connection error (refused, DNS, TLS).
- Timeout ( > 30 s).
- Empty response body.
- Body isn't valid JSON, or isn't a JSON object.
- JSON body missing
status: 200or missing / emptyorder_idstring. - Unhandled exception before the response is received.