Skip to content

Errors & reliability

The SDK is built for a payments flow, so it handles transient failures safely and gives you precise errors to act on.

Retries

Transient failures are retried automatically with exponential backoff and jitter:

  • Network errors and timeouts
  • 429 Too Many Requests (honors the Retry-After header)
  • 5xx server errors

Only safe requests retry: reads (GET), and mutations that carry an idempotency key. Default is 2 retries; configure with maxRetries.

new ShoppableCheckout({ token: "pk_live_…", maxRetries: 3, timeout: 15000 });

Idempotency

Every mutating call (prepareCheckout, createIntent, updateCheckout, completeCheckout) sends an auto-generated Idempotency-Key, so an automatic retry can never create a duplicate order or charge. Pass your own key to make a retry idempotent across separate invocations (e.g. a user-triggered retry):

await checkout.prepareCheckout(cart, { idempotencyKey: myStableKey });

Timeouts and cancellation

Each request times out after timeout ms (default 30000) and accepts an AbortSignal:

const controller = new AbortController();
const promise = checkout.completeCheckout(id, { signal: controller.signal });
controller.abort(); // rejects with an AbortError, never retried

Error types

All API failures throw a subclass of ShoppableApiError. Catch the base to handle everything, or a subclass for finer control. Every error carries status, the encrypted support ref (when present), the server requestId, and the raw body.

ErrorWhen
ShoppableAuthError401 token missing/invalid/expired
ShoppableValidationError400 / 422 invalid request
ShoppableNotFoundError404
ShoppableRateLimitError429 (has retryAfter in ms)
ShoppableServerError5xx
ShoppableNetworkErrorno response (offline, DNS, TLS)
ShoppableTimeoutErrorexceeded the timeout
ShoppableConfigErrorSDK misconfiguration (not an API error)
import { ShoppableApiError, ShoppableRateLimitError } from "@shoppable/checkout";
try {
await checkout.prepareCheckout(cart);
} catch (err) {
if (err instanceof ShoppableRateLimitError) {
// back off and retry later
} else if (err instanceof ShoppableApiError) {
showError(err.message, err.ref); // quote err.ref / err.requestId to support
}
}