Resource methods raise a RequestError for any non-2xx response, so you handle
failures with try/catch rather than inspecting each result. On success, a
method returns its typed payload.
RequestError exposes:
-
code: a stable error category, so you can branch on it instead of
matching on message text. Route errors use INVALID_REQUEST, NOT_FOUND,
INSUFFICIENT_BALANCE, IDEMPOTENCY_CONFLICT, ORDER_NOT_CANCELLABLE,
ORDER_RECONCILIATION_REQUIRED and INTERNAL_ERROR; signed-auth rejections
use UNAUTHORIZED, FORBIDDEN, AUTH_UNAVAILABLE, RATE_LIMITED and
BAD_CONTENT_HASH. It is absent for a response that carries no error
envelope.
A write that takes an idempotency key can also answer 400 with
IDEMPOTENCY_KEY_REQUIRED (the Idempotency-Key header is absent, or empty
after trimming whitespace) or IDEMPOTENCY_KEY_INVALID (the key is longer
than 255 characters or is not printable ASCII). The clients generate a key
only when you pass none, so you see these only for a key you supplied. An
empty string is sent as is and gets IDEMPOTENCY_KEY_REQUIRED.
-
status: the HTTP status code.
-
message: a human-readable explanation.
-
retryAfterSeconds in TypeScript, retry_after_seconds in Python:
how long to wait, taken from the response’s Retry-After header. Rate-limit
refusals and temporarily unavailable market-discovery responses can carry it.
It is absent when the header is missing or unreadable, so keep a fallback.
Python also carries body, the parsed error envelope.
code is the wire string in both languages, so the examples above compare
against it directly. Python also exports ApiErrorCode, AuthErrorCode and
IdempotencyBadRequestErrorCode, which subclass StrEnum and so compare equal
to those strings. Their members are named in lower case
(ApiErrorCode.not_found, value "NOT_FOUND"), which is worth knowing before
you reach for ApiErrorCode.NOT_FOUND.
Authentication failures arrive in the same envelope as route errors, so code is
populated: a rejected signature is a 401 with UNAUTHORIZED, and a key without
the capability for a route is a 403 with FORBIDDEN.
Retrying a rate-limited request
RATE_LIMITED means your organization has spent its request budget. Every key your
organization holds draws on the same budget, so opening more keys does not raise it.
Wait for the time the error names, then retry. Do not sleep for a fixed
interval: the budget refills continuously, so the value is the time until your
next request can succeed rather than the length of a window. Both examples fall
back to one second, because the header can be absent.
retry_after_seconds needs parlayx 1.1.0 or newer.
Every authenticated response also carries RateLimit-Limit,
RateLimit-Remaining and RateLimit-Reset, so pacing your own calls before
being refused is more reliable than reacting to a refusal.
See Rate limits.