Docs
Dashboard
View as Markdown
On this page
  1. The Idempotency-Key header
  2. Refunds
  3. Without a key
  4. Receiving events

Idempotency

How to retry safely: the Idempotency-Key header on every write, refund keys, and how webhooks and plugin callbacks dedupe.

Networks fail after a request reaches us but before you read the answer. Retrying must never refund twice or create two products.

The Idempotency-Key header

Send Idempotency-Key with any write made with an API key or an OAuth token, or with a storefront key. The first answer is kept for 24 hours; sending the same request with the same key again returns that answer, with Idempotent-Replayed: true, and changes nothing.

curl -X POST https://api.shopfa.st/v1/store/products \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1b7c2e-launch-pack" \
  -d '{"name":"Launch Pack","type":"service","priceMinor":2500,"compareAtMinor":null,"description":"","delivers":"","status":"draft","lowStockThreshold":0}'
  • Make the key once per intent (a UUID stored with your record), not per HTTP attempt.
  • Keys belong to the key or app that sent them (and, on the Storefront API, to the signed-in buyer): another key never sees them.
  • The same key with a different method, path or body answers 422 idempotency-key-reused.
  • While the first request still runs, a retry answers 409 idempotency-key-in-use with Retry-After: 1.
  • Answers that never began (401, 403, 429, 503) are not kept: retry them with the same key.

Refunds

Refunds also take an idempotencyKey in the body: 8 to 80 letters, numbers, dashes or underscores, one per refund attempt. A repeat with the same key is a no-op that answers the same order.

curl -X POST https://api.shopfa.st/v1/store/orders/$ORDER/refunds \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"amountMinor":1200,"reason":"Duplicate purchase","destination":"original","idempotencyKey":"refund-ord123-1"}'

Without a key

  • PUT and PATCH set state: sending the same body twice leaves the same result.
  • DELETE of something already gone answers 404; treat it as done.
  • A POST that creates (a product, a discount) without Idempotency-Key creates twice if you send it twice.

AI tools connected over MCP get the same protection through each change tool’s idempotencyKey.

Receiving events

  • Webhooks keep the same webhook-id across retries and replays. Store the ids you processed and skip repeats.
  • Plugin callbacks apply each event_id a payment plugin returns once: ShopFast keeps an inbox of processed provider events per plugin, so a provider retrying its notification never pays an order twice.
  • The sandbox and real gateways follow the same rule with their own event ids.
Was this page helpful?