Appearance
Idempotency
POST /api/v1/merchant/orders requires:
http
Idempotency-Key: <deterministic-caller-key>The key is scoped to your API key and this operation. Store a hash of the request body with it.
Callers must reuse the same key for retries of the same logical request. Do not generate a random UUID on every attempt.
| Retry | Result |
|---|---|
| Same key, same body, completed | Original successful response |
| Same key, different body | 409 MERCHANT_API_IDEMPOTENCY_CONFLICT |
| Concurrent same key, fresh STARTED | One execute; the other waits (~2s) and replays or gets 409 MERCHANT_API_IDEMPOTENCY_IN_PROGRESS |
| Stale STARTED (lease expired), same hash | Atomic reclaim; request runs again |
| Failed request (4xx/5xx after start) | The STARTED row is deleted; you may retry |
externalOrderId is a second safety net. The same id on this API client cannot create two Chuchu orders. A later request with the same id and incompatible commercial data returns 409 EXTERNAL_ORDER_CONFLICT.
You may use your order number as the idempotency key, but it is a request-retry key, not a substitute for externalOrderId.
Crash recovery
A process crash can leave STARTED. Each STARTED row has startedAt, lastAttemptAt, and leaseExpiresAt (30 seconds from the last attempt).
Reclaim is a single UPDATE ... WHERE status = STARTED AND leaseExpiresAt <= now AND requestHash = :hash. Two retries cannot both win.
Retention
Completed records and abandoned (lease-expired) STARTED rows are kept for 7 days, then may be deleted. Fresh STARTED rows whose lease has not expired are never deleted.
bash
pnpm merchant-api:idempotency-cleanup -- --dry-run
pnpm merchant-api:idempotency-cleanup -- --retention-days=7Do not delete rows with ad-hoc SQL.