@agentaos/pay, a bad request, an auth problem, a network blip, throws a subclass of AgentaOSError. Retries for transient failures (5xx, network errors, some 429s) happen automatically inside the SDK before anything is thrown, so if you see an error, it’s already survived the retry budget.
Hierarchy
AgentaOSError, so err instanceof AgentaOSError catches all of them, err.status, err.code, and err.requestId (from the response’s x-request-id header, when present) are always there for logging.
Catching errors
Catch specific subclasses before the genericAgentaOSError, they all extend it, so a broad catch first would shadow the specific ones:
Retry behavior
Retries are controlled by themaxRetries client option (default 2), and only apply to checkouts, paymentLinks, transactions, invoices, subscriptions, and customers, webhooks.verify() never touches the network.
1
5xx responses
Retried with exponential backoff:
min(1000 × 2^attempt, 10000) ms, so 1s, 2s, 4s, 8s, capped at 10s. After maxRetries is exhausted, throws ApiError.2
429 (rate limited)
Retried once inline, and only if the response’s
Retry-After header is 60 seconds or less and a retry attempt remains. If Retry-After exceeds 60s, or retries are exhausted, it throws RateLimitError immediately with retryAfter set from the header (in ms, defaulting to 60000 if the header is missing).3
Network errors
Same exponential backoff as
5xx. After maxRetries, throws a generic AgentaOSError (code: 'network_error', status: 0).4
Timeouts
Never retried. Each attempt (including retries of other error types) gets its own
timeout-ms AbortController; if it fires, TimeoutError is thrown immediately, no backoff, no further attempts.Idempotency
EveryPOST the SDK sends (checkouts.create(), paymentLinks.create(), subscriptions.cancel(), and the rest) automatically carries an idempotency-key header, a random UUID generated fresh per call. Retry the same call with the same key and the server does not reject it: it replays the original success and hands back the same resource, including its already-issued invoice, if any, instead of creating a second one. There is no global 409 on a duplicate key.
subscriptions.cancel() is a POST, so it carries an auto-generated key like any other. You rarely need to think about it: the call is safe to retry because cancelling an already-cancelled subscription is a no-op on the server, not an error. The key is sent, but the operation is naturally idempotent either way.
GET reads carry no key, they’re naturally idempotent.
Debugging
Setdebug: true on the client to log every request and retry to stderr (or your own logger):
Debug logs are sanitized: they never include your API key or request/response bodies, only method, path, status, timing, and retry/backoff notices.
Next steps
Overview
Client options, auth, and the resource map.
Webhooks
WebhookVerificationError and signature verification in detail.