Skip to main content
Use bounded retries only for failures that can recover. Persist the request, its idempotency key, and the attempt state before the first POST.

Retry classification

An HTTP response proves Skinloop returned that status, but it does not authorize fulfillment. A transport failure after bytes may have reached Skinloop leaves a POST result unknown. Never switch to a new idempotency key merely because the response was lost.

Backoff and jitter

For ordinary API requests, use at most five attempts and a 30-second retry budget. Before attempt number n after the first failure, calculate:
This produces a random delay between zero and approximately 500 ms, 1 s, 2 s, 4 s, and 8 s. Stop when either the attempt limit or total retry budget is exhausted. A background reconciliation process can continue later; do not keep a customer request open indefinitely.

Retry-After

For 429, use Retry-After instead of the calculated delay when present. The header can be:
  • an integer number of seconds, or
  • an HTTP date.
Wait until the indicated time, add small random jitter, and still enforce your overall deadline. If the value is missing or malformed, use exponential backoff. Do not retry earlier than a valid Retry-After.

Idempotency rules

Reuse the same idempotency key when:
  • a checkout-create request times out or loses its connection,
  • a retryable 429 or 503 is returned,
  • your process crashes before storing a successful response, or
  • you are recovering the result of the same logical order attempt.
The body must remain logically identical. Skinloop returns 409 if the same key is reused with different effective input. Create a new key only for a genuinely new customer attempt after a safe terminal result such as pre-trade expired, canceled, declined, or failed. Do not create a new key to replace pending, active, hold, completed, reverted, or reconciliation_required.

Polling retries

GET status requests are safe to retry after transport failures, 429, or 503. Apply the same attempt and time limits to each polling cycle. The next scheduled cycle is a new retry budget. For checkout-deposit status, never poll faster than its returned pollAfterSeconds. For hosted checkout status, use the schedule in Checkout status.

Operator intervention

Stop automatic retries and alert an operator when:
  • the bounded retry budget is exhausted,
  • a response identity, amount, currency, or order ID conflicts with stored data,
  • a 409 cannot be explained by an identical idempotent replay,
  • status becomes reconciliation_required,
  • a completed payment is later reverted, or
  • an external fulfillment timeout may have delivered but cannot be confirmed using the destination idempotency key.
Retain the checkout ID, merchant order ID, idempotency key, latest status, request ID, webhook event ID, and timestamps. Never include API keys or webhook secrets in logs or support messages.