Skip to Content

The full error code reference lives in API errors. This page maps the codes to specific symptoms and fixes — useful when you have a 4xx/5xx in front of you and want to act fast.

All errors return the same envelope:

{ "error": { "code": "unprocessable_entity", "message": "Invalid input: 'amount' must be a positive integer", "doc_url": "https://revroute.ru/docs/api-reference/errors#unprocessable-entity" } }

Always read error.message first — it usually names the offending field.

400 bad_request

Malformed request — invalid JSON, missing required headers, or unparseable parameters.

CauseFix
Body is not valid JSONPretty-print and validate the body before sending
Content-Type missingAlways send Content-Type: application/json
Query parameter has wrong type (e.g. ?limit=abc)Cast to the right type before stringifying

401 unauthorized

Authentication failed.

CauseFix
Missing Authorization headerAdd Authorization: Bearer <token>
Wrong token formatServer-to-server keys are dub_*; publishable keys dub_pk_*; OAuth dub_access_token_*
Token revoked or expiredGenerate a new one in Settings → Tokens
Mixed up secret and publishable keyServer endpoints want dub_*; client endpoints want dub_pk_*

See Authentication for the full reference.

403 forbidden

Token is valid but does not grant the required scope / role.

CauseFix
Token has read-only scope but you’re writingGenerate a token with the corresponding *.write scope
Workspace member lacks the role for this actionAsk an owner to upgrade your role or perform the action
OAuth app wasn’t granted the scope by the userRe-run the consent flow requesting the scope

404 not_found

The resource doesn’t exist or your token can’t see it.

CauseFix
Wrong resource idDouble-check the id — lnk_*, cus_*, prog_* prefixes have to match the endpoint
Resource lives in another workspaceYour token is scoped to one workspace; switch tokens
Soft-deleted resourceSome endpoints return 404 instead of 410 for archived resources

not_found and forbidden are intentionally indistinguishable for some endpoints — we don’t reveal that a resource exists if you can’t see it.

422 unprocessable_entity

The request is well-formed but failed validation.

CauseFix
Wrong field type (string where number expected, etc.)Read the message — it names the field
Required field missingAdd it
Value outside allowed range (e.g. amount: -1)Provide a valid value
currency not in the allowed setUse a 3-letter ISO code that your workspace has enabled
Duplicate unique field (e.g. domain already exists)Check before creating, or handle the conflict

This is the most informative error — the body’s message field tells you exactly what’s wrong.

429 rate_limited

You exceeded the API rate limit. The response includes:

Retry-After: 30 X-RateLimit-Limit: 600 X-RateLimit-Remaining: 0 X-RateLimit-Reset: 1716729600
Fix
Implement client-side rate limiting before you hit the wall
Respect Retry-After — back off for that many seconds, then retry
Batch requests where possible (/links/bulk instead of N x /links)
Spread workload over time — don’t hammer the API in tight loops

See Rate limits for current limits per endpoint group.

5xx server errors

CodeMeaningFix
500 internal_server_errorUnexpected error in our systemRetry with exponential backoff
502 bad_gatewayUpstream temporarily unreachableRetry
503 service_unavailableCapacity / maintenanceRetry. Check status.revroute.ru 
504 gateway_timeoutOperation took too longRetry once; if it persists, contact support

All 5xx responses include an x-request-id header — capture it. Sending us that id makes investigations 10x faster.

const res = await fetch(url, opts); if (!res.ok) { const requestId = res.headers.get("x-request-id"); const body = await res.json(); log.error("RevRoute API error", { status: res.status, code: body.error?.code, message: body.error?.message, requestId, }); }

Retry strategy

A robust retry policy:

  • Retry: 408, 425, 429, 500, 502, 503, 504, network errors
  • Do not retry: 400, 401, 403, 404, 422 — these won’t succeed on retry, you have a bug
  • Backoff: exponential with jitter, e.g. min(64s, 2^attempt + random(0..1))
  • Cap: stop after 5–8 attempts, surface the error to the operator

Most HTTP clients (axios, got, httpx) have a retry middleware that handles this — use it.

Idempotency

Mutating endpoints (POST /links, POST /track/sale, etc.) accept an Idempotency-Key header:

curl -X POST https://api.revroute.ru/track/sale \ -H "Authorization: Bearer $REVROUTE_API_KEY" \ -H "Idempotency-Key: order_8912" \ -d '{ "customerExternalId": "user_42", "amount": 9900, ... }'

A retry with the same key returns the original response without creating duplicates. Use a stable per-operation key (order id, invoice id, etc.).

See also: Authentication, Rate limits, API errors reference.

Last updated on