Error Response Format
Upwell API errors are flat JSON objects — a message string, sometimes with a machine code alongside it:details object, and no timestamp field. Parse
error as the human-readable message and treat code (when present, e.g.
constraint-violation, bad-request) as the machine-readable category.
HTTP Status Codes
The codes you will actually encounter:
Two codes conspicuously absent, on purpose:
201is not used — successful creates return200.429is not used — see Rate limiting below.
Business errors inside a 200
The approval action endpoints report failure in the response body, not the HTTP status. APOST /api/rest/invoices/{id}/approve that can’t proceed still returns 200:
Always check the nested
success / error fields on action endpoints — checking only the
HTTP status will miss these.
Real error messages and their fixes
The messages you’ll actually see in400 responses, and what each one means:
Not-found semantics
A lookup by an id that doesn’t exist — deleted, mistyped, or belonging to a different organization — is not an HTTP error. The single-resourceGETs declare a nullable
resource and return it inside a 200:
- Check the body, not just the status, when verifying a record exists.
- A real
404means the path is wrong, not that the record is missing. - Remember Upwell ids are prefixed strings (
cus_…,inv_…,cari_…) — a truncated or unprefixed id is a common cause of “exists in the dashboard but null over the API.” - To find records by your own keys instead, use the
POST /<resource>/searchendpoints (see Integration patterns).
Rate limiting
The Upwell API does not currently enforce rate limits. There are no429 responses, no
X-RateLimit-* headers, and no Retry-After header — don’t build handling machinery for
them. If you do observe a 429, it originated from infrastructure on your side (a proxy
or gateway), not from Upwell.
That’s a description of today’s behavior, not an invitation: keep client concurrency
bounded and batch with the bulk-* endpoints where they exist. If limits are introduced,
they’ll be announced in the changelog.
What is safe to retry
- Network failures and
5xx— retry with exponential backoff and jitter. POSTretries need per-resource care. A retried create is not uniformly safe: customers/shipments/invoices reject duplicates with400 Uniqueness violation, carriers silently no-op, and carrier invoices deduplicate asynchronously — read idempotent upserts before writing retry logic.400is never retryable as-is — the request itself is wrong; fix the payload.401is not retryable — fix the credential.
Getting Help
If an error doesn’t match anything on this page:- Capture the full exchange — endpoint, HTTP method, request body (redact the API key), the complete response body, and the timestamp.
- Note the last 4 characters of the API key you used (never send the full key).
- Contact support at support@upwell.com.

