These are the rules for resending each kind of call, what to do after each failure, and the timeout and backoff Snapcaster recommends.

When a call times out or its connection drops, you cannot tell whether Snapcaster applied it. Each kind of call has one thing that makes resending it safe.

CallResend it withWhat the resend returns
Any GETNothing extra, because a read changes nothingThe current state, so a GET is always safe to retry
A listing writeThe same body and the same asOf on every itemnoop for an item Snapcaster already applied and applied for one it did not. See Retry a write whose response was lost
A store updateThe same bodyThe same result, because the update sets values rather than adding to them
An order commandThe same Idempotency-Key, order, operation and bodyThe original HTTP status and the same JSON value, under the rules in Calls with an Idempotency-Key
A sandbox buyer operationThe same Idempotency-Key and bodyThe original HTTP status and the same JSON value
The webhook testThe same Idempotency-KeyThe same event_id, and Snapcaster sends nothing more
The sandbox test purchaseThe same Idempotency-Key and bodyThe same test_purchase_ref, and the sandbox buyer never pays twice

The listing writes are POST /listings, POST /listings/bulk, DELETE /listings and POST /listings/purge. They take no Idempotency-Key, because the asOf on each item does that job. The store update is PATCH /me, which takes no Idempotency-Key either. The order commands include PATCH /orders/{orderId}/fulfillment, POST /orders/{orderId}/cancel and POST /orders/{orderId}/refunds, and every other order operation that is not a GET. The webhook test is POST /webhooks/test, and the test purchase is POST /sandbox/test-purchases.

Every order command, every sandbox buyer operation, POST /webhooks/test and POST /sandbox/test-purchases require a UUID Idempotency-Key. A call without one returns HTTP 400 IDEMPOTENCY_KEY_REQUIRED.

  • Choose a new UUID for each new operation, and keep it for every retry of that operation.
  • Before the first send, save the key with the operation in durable storage, such as the database row that records the command. A retry after a crash or restart then reads it back and sends the same key.
  • A replay returns the original HTTP status and the same JSON value, even if the order has changed since. A replayed command that already went through returns its first success, so it never returns HTTP 422 INVALID_TRANSITION.
  • The replayed JSON can list object keys in a different order, so compare parsed values, not raw bytes.
  • Read the current state with GET /orders/{orderId}, not from a replay.
  • Keys remain valid for the lifetime of the order.
  • The same key with changed contents returns HTTP 409 IDEMPOTENCY_CONFLICT. A key the seller already used for a command in the Snapcaster dashboard also returns HTTP 409 IDEMPOTENCY_CONFLICT.
  • A concurrent request with the same key returns HTTP 409 REQUEST_IN_PROGRESS with Retry-After.
FailureWhat to do
No response, a timeout, or a dropped connectionAfter a backoff, resend the same call the way Each kind of call gives for its kind
HTTP 429 RATE_LIMITEDWait Retry-After seconds, then resend the same call
HTTP 409 REQUEST_IN_PROGRESSWait Retry-After seconds, then resend with the same key
HTTP 429 ADDRESS_VERIFICATION_RETRY_TOO_SOONWait until a minute has passed since the failed check, then retry it
HTTP 500 INTERNAL_ERROR or another 5xxResend the same call after a backoff. If it keeps failing, email info@snapcaster.gg with the X-Correlation-ID response header
HTTP 503 TEST_PURCHASE_NOT_AVAILABLEDo not retry. Email info@snapcaster.gg to place the test purchase
Any other 4xxDo not resend it unchanged. Fix the request using the error’s code and the operation’s reference
A per-item rejected result on a listing writeDo not resend the item unchanged. Act on its code from the per-item failures in Error codes

Snapcaster sends Retry-After, a whole number of seconds, with every HTTP 429 RATE_LIMITED and HTTP 409 REQUEST_IN_PROGRESS. On a metered listing write, Retry-After is the time left in the current one-minute window of the listing rate limit. If a RATE_LIMITED or REQUEST_IN_PROGRESS response reaches you without Retry-After, for example because a proxy dropped the header, fall back to the backoff below. HTTP 429 ADDRESS_VERIFICATION_RETRY_TOO_SOON carries no Retry-After, and its message says how many seconds remain. Every response carries an X-Correlation-ID header, which identifies the request when you contact support.

Neither the contract nor Snapcaster sets a client timeout, an attempt count, or a backoff. These values are recommendations, not server rules, and the catalog sync sample uses them.

  • A 30-second timeout on each request.
  • At most 5 attempts per request, the first included.
  • After a timeout, a dropped connection, or a 5xx, a random wait of up to 2, 4, 8, and then 16 seconds before attempts 2 to 5. If you allow more attempts, cap the wait at 30 seconds.
  • After HTTP 429 RATE_LIMITED or HTTP 409 REQUEST_IN_PROGRESS, Retry-After plus up to 1 random second.
  • After HTTP 429 RATE_LIMITED that reached you without Retry-After, the same wait as after a 5xx.

When the attempts run out, stop and report the error. A later resend with the same key, or the same body and asOf, is still safe.

Need help?

Email Marketplace support.

The email includes this page and selects sandbox as the environment. Update it if you need help with production.

Never include an API key or signing secret in the message.