Idempotency & Retry¶
batch_id is the idempotency key¶
- Every write request (
PUT/POST) must include abatch_id(UUID v4). - If the same
batch_idis sent again, the API returns200with"status": "ALREADY_RECEIVED"and writes nothing. The content is not compared — the first request received with thatbatch_idis the one kept.
So:
| Situation | batch_id |
|---|---|
Network timeout, 5xx, 429 |
Resend with the same batch_id |
400 / 413 and you fixed the content |
Generate a new batch_id |
Correcting data already sent (transaction version + 1, resending a daily close) |
Generate a new batch_id |
Warning
Generate the batch_id once per batch and store it with the batch before the first attempt. If you generate a new one on every retry, a timed-out request that actually succeeded will be stored twice.
Retry strategy¶
| Situation | Strategy |
|---|---|
429 |
Wait Retry-After seconds, then retry |
500 / 503 / network timeout |
Exponential backoff: 1, 2, 4, 8, 16… minutes, same batch_id, for up to 24 hours |
401 |
Do not retry. Check the API key; contact HQ if it was changed |
400 / 403 / 413 |
Do not retry. Fix the problem and send with a new batch_id. |
Recommended flow¶
for each batch in batches_for(store, business_date):
batch_id = uuid4() # generate once, keep for retries
loop:
resp = POST /trade-records (batch_id, batch)
if resp.status in (200, 202): break
if resp.status == 401: raise check_api_key()
if resp.status == 429: sleep(resp.Retry-After); continue
if resp.status >= 500: sleep(backoff()); continue
raise fix_required(resp.error) # 4xx: fix, then use a new batch_id
POST /daily-close (new batch_id, control totals)
sleep(30 min)
GET /daily-close/{store}/{business_date} # MISMATCHED: resend missing data, then the daily close
A runnable version is in Sample Client.