Guides

Idempotency

Use one key per intended change so a retry does not repeat an action.

A request can succeed even if your connection drops before the response arrives. An idempotency key tells a supported endpoint, “This is the same change I already asked for,” so retrying does not repeat that change.

Generate a hard-to-guess value such as a random UUID and save it with the change you intend to make. Reuse that key only for the same operation with identical inputs. A new change needs a new key.

Response-replay operations

Use the Idempotency-Key header for these operations. Save one key for one intended change and reuse it with the identical method, path, body, and store. Successful response receipts are retained for 24 hours; this is separate from the ledger and action keys listed below.

OperationKey requirementRecovery
Create an order (POST /v2/orders), create a wallet order (POST /v2/orders/wallet), or pay an existing order (POST /v2/orders/{order}/wallet-payments)RequiredReplay the same key to recover the result without another debit. Changed input returns 409.
Create a wallet top-up payment linkRequiredReplay recovers the same charge and checkout URL for identical input within 24 hours. Inspect charges after an uncertain provider failure before starting a new top-up.
Create a storeRequiredA successful replay returns the original store without consuming the one-new-store-per-60-seconds allowance.
Create an exportRequiredReplay recovers the original job; it does not restart a failed job.
Upsert a customer by external IDOptionalThe same external ID preserves identity; a keyed replay also preserves the response.
Close, reopen, or archive a ticketOptionalA keyed replay recovers the original response after a lost connection.

Follow the operation reference for other supported writes. A known 429 is not a successful replay receipt: honor Retry-After and retain the same key and inputs. MCP also retains the same invocation key after a known throttled outcome. An uncertain MCP outcome requires inspection before retrying.

Ledger and action keys

OperationTransportRequiredReuse behavior
POST /v2/affiliates/{affiliate}/payoutsIdempotency-Key header, max 100 charactersYesSame affiliate returns the existing payout; another affiliate is rejected.
POST /v2/wallets/{customer}/adjustmentsJSON idempotency_key, max 128YesIdentical input returns 200 with the existing ledger entry; different input is rejected.
POST /v2/credit-transactionsJSON idempotency_key, 1–128 charactersYesIdentical input returns 200; conflicting reuse and reserved internal prefixes are rejected.
Subscription cancellation and lifecycle writesIdempotency-Key header or JSON idempotency_key, max 128No, strongly recommendedThe header takes precedence. A confirmed replay returns the persisted action; conflicting reuse is rejected.

Keys are stored with the related ledger, payout, or subscription action. SellApp does not currently expire these saved keys automatically, so do not recycle them for another operation.

Inherently idempotent operations

  • POST /v2/reward-grants is unique per reward rule and customer. A repeat returns the existing grant.
  • PUT /v2/groups/{group}/products replaces the ordered membership. The same list has the same result; [] clears it. It does not provide a stored response receipt.
  • Updating an affiliate payout to the status it already has is a no-op.
  • Fulfillment retry endpoints reset the same retryable effects instead of creating another effect.

These guarantees apply only to the listed operations. A write is not safe to repeat just because another endpoint accepts an idempotency key.

Replay rules

Operations that mark Idempotency-Key as required in their reference reject requests without it. For operations using response replay, an identical retry returns the stored response with Idempotent-Replayed: true. Different input returns 409 idempotency_key_mismatch; concurrent reuse returns 409 idempotency_in_progress.

Customer-session creation is the deliberate exception: its one-time plaintext token and redemption URL are never cached or replayed.

Supported operations save successful results and return the existing resource when you repeat the same request. Validation, authentication, authorization, rate-limit, and server failures are not cached as idempotent successes.

If a connection fails after sending a keyed request, resend the exact method, path, body, store slug, and key. Never generate a new key merely because the first response was lost.

Set SELLAPP_API_BASE_URL, SELLAPP_API_KEY, and SELLAPP_STORE as shown in the quickstart.

Idempotent affiliate payout
curl --request POST \
  --url "${SELLAPP_API_BASE_URL}/v2/affiliates/42/payouts" \
  --header "Authorization: Bearer ${SELLAPP_API_KEY}" \
  --header "X-STORE: ${SELLAPP_STORE}" \
  --header 'Idempotency-Key: 01992a65-e064-71ba-b38f-902b7966a6be' \
  --header 'Accept: application/json'

On this page