Error catalog

Every error response carries a stable string code in error.code. Branch your client on that: search by code, filter by domain, or open any row for the full explanation and how to fix it.

How error codes are structured 2-digit domain prefix + 4-digit condition

Each error.legacyCode is a six-digit number. The first two digits identify the domain of the error (authentication, rate limiting, a specific product module, etc.) and the remaining four digits identify the specific condition inside that domain. Recognising the prefix is enough to know which part of the API misbehaved, even before reading the stable string error.code.

PrefixDomainCovers
01xxxxAUTH API key, tokens, source IP, identity.
02xxxxRATE DDoS, TPS, per-minute / per-hour quotas.
03xxxxVALIDATION Request shape, JSON, params, types.
04xxxxACCOUNT Organization info, state, fraud, blocks.
05xxxxBILLING Balance, payments, currency, exchange rate.
06xxxxSMS Errors specific to the SMS module.
07xxxxWHATSAPP WhatsApp module.
08xxxxEMAIL Email module.
09xxxxCALLBLASTING Callblasting module.
10xxxxURL_SHORTENER URL Shortener module.
11xxxxUTILITIES Ping and other diagnostic endpoints.
12xxxxTOOLS Tools module (catalogs, lookups).
13xxxx–89xxxxreservedHeld for future modules without renumbering.
90xxxxINFRA Cache, database, network, dependency failures.
99xxxxINTERNAL Uncaught exceptions, unexpected bugs.
AUTH_REQUIRED 401 Auth No bearer token was sent, and every call needs one.

We didn't see a Bearer token on your request. Every call to the v6 API needs an API key in the Authorization header. Without it we can't tell which organization is asking.

How to fix it

Send Authorization: Bearer hk_YOUR_API_KEY on every request. The bearer scheme is the only accepted way to authenticate. Earlier styles that put the key in the URL or the request body are no longer supported.

legacyCode 40002 slug auth-required
AUTH_INVALID_KEY 401 Auth The API key isn't recognised: wrong format, revoked, or expired.

The API key you sent isn't recognised. Three things produce this code: a key with the wrong shape, a key that was rotated or revoked, or a key that has reached its expiration date.

How to fix it

Double-check that your client is using the exact value shown when the key was first created, since keys are displayed only once. If you've rotated keys recently, make sure the new one is in use. If the key has expired, issue a fresh one from your dashboard.

legacyCode 40003 slug auth-invalid-key
AUTH_COST_CENTER_DISABLED 401 Auth The cost center attached to this key is disabled.

Every API key is attached to a cost center so usage can be billed and reported correctly. The cost center attached to this key is currently disabled.

How to fix it

Re-enable the cost center from your dashboard, or issue a fresh key attached to one that is active.

slug auth-cost-center-disabled
AUTH_SERVICE_NOT_ALLOWED 401 Auth This key isn't scoped for the product behind this endpoint.

This key isn't scoped to call the product behind this endpoint. Keys can be restricted to specific products (SMS, WhatsApp, e-mail, …) so a leaked or misused key can only do what it was meant to.

How to fix it

Issue a new key with the right product enabled, or switch to a key that already has access. Diagnostic endpoints under /api/v6/utilities/* are always available regardless of scope.

slug auth-service-not-allowed
AUTH_SOURCE_IP_UNKNOWN 400 Auth Reserved, kept only as a bridge from v5.

Reserved code, kept as a bridge for callers migrating from v5. The v6 API doesn't use the source-IP override mechanism that produced this error, so you should not see it on v6 traffic.

legacyCode 40015 slug auth-source-ip-unknown
ACCOUNT_NOT_ACTIVE 403 Organization Your organization is suspended or closed.

Your organization is not in an active state right now, typically because it has been suspended or closed. While that's the case, every endpoint will reject calls, even diagnostic ones.

How to fix it

Contact support so we can review the situation and restore the organization. The state can't be lifted via the API itself.

slug account-not-active
ACCOUNT_BLOCKED 403 Organization A hard block is in place: every call is rejected.

Your organization is currently subject to a hard block from our side. Every call is rejected (including read operations) until the block is removed.

How to fix it

Open a support ticket so we can review the case. Blocks are removed once the underlying issue has been addressed.

slug account-blocked
ACCOUNT_READ_ONLY 403 Organization Read-only mode: only GET/HEAD/OPTIONS succeed.

Your organization is in read-only mode. Requests that only fetch information (GET, HEAD, OPTIONS) still succeed, but anything that creates or changes data is rejected.

How to fix it

Until the block is lifted, pause any code path that mutates data. Contact support to find out why the block is in place and what's needed to clear it.

slug account-read-only
ACCOUNT_CONFIG_NOT_FOUND 403 Organization We couldn't load the organization for your key.

Your API key authenticated correctly, but we couldn't load the organization it points to. This indicates an internal data issue on our side, not a problem with your request.

How to fix it

Contact support and include the meta.requestId value from the response. That id lets us trace the exact lookup that failed.

legacyCode 4002 slug account-config-not-found
RATE_DDOS_EXCEEDED 429 Rate Unusually high traffic from your source IP.

Your source IP has produced an unusually high volume of requests in the past minute. This protection is meant to absorb attack and scanner traffic; legitimate integrations very rarely come close to it.

How to fix it

Wait the number of seconds indicated by the Retry-After header before retrying. If you're a legitimate caller behind a shared NAT or aggregator and you're consistently hitting this, contact support so we can discuss your traffic shape.

legacyCode 40001 slug rate-ddos-exceeded
RATE_TPS_EXCEEDED 429 Rate You've exceeded this endpoint's quota for your organization.

You've sent more requests to this specific endpoint than your organization's quota allows within the current window. Each endpoint has its own quota; hitting the wall on one doesn't affect the others.

How to fix it

Pause your client for the number of seconds shown in Retry-After, then resume. To avoid hitting the wall at all, watch the RateLimit-Remaining and RateLimit-Reset headers we return on every response and pace your client accordingly. See the Rate limiting guide.

legacyCode 40001 slug rate-tps-exceeded
INFRA_DB_CONNECTION_ERROR 503 Infra A backing service was momentarily unreachable.

One of the services we rely on internally was temporarily unreachable when your request arrived. This is a problem on our side, not in your request.

How to fix it

Retry the request after the Retry-After seconds, ideally with a small random jitter. If it persists for more than a couple of minutes, check the status page or open a support ticket.

legacyCode 40011 slug infra-db-connection-error
INFRA_CACHE_UNAVAILABLE 503 Infra An internal cache component is temporarily unavailable.

Same shape as the previous one, for a different piece of our internal infrastructure. The failure is transient and recovers on our side without any change on yours.

How to fix it

Retry after Retry-After with a small jitter. If you keep seeing it, the status page usually has the picture, and support can help triage.

slug infra-cache-unavailable
INFRA_DB_QUERY_TIMEOUT 504 Infra An internal query took too long and was cut short.

An internal query took longer than we allow before returning a response, so we cut it short rather than leaving your client hanging.

How to fix it

Retry immediately, since single occurrences are usually transient. If you see several in a row, our backend is likely degraded; open a support ticket and quote the meta.requestId so we can correlate logs.

slug infra-db-query-timeout
URL_INVALID 400 URL shortener The destination URL is malformed.

The url you sent isn't a valid absolute URL: we couldn't parse a scheme and host out of it.

How to fix it

Send an absolute http/https URL including the host, e.g. https://example.com/path.

slug url-invalid
URL_SCHEME_NOT_ALLOWED 400 URL shortener Only http/https destinations are allowed.

The destination uses a scheme we don't shorten (e.g. javascript:, data:, ftp:, file:).

How to fix it

Only http and https destinations are accepted.

slug url-scheme-not-allowed
URL_TOO_LONG 400 URL shortener The destination URL exceeds the maximum length.

The destination URL is longer than the 2048-character maximum.

How to fix it

Shorten the destination (drop unnecessary query parameters) so it fits within 2048 characters.

slug url-too-long
URL_BLOCKED_HOST 400 URL shortener The destination host is private or reserved.

The destination points at a private/reserved address or an internal hostname (e.g. 127.0.0.1, 10.0.0.0/8, localhost). We block these so short links can't be used to reach internal endpoints.

How to fix it

Point the link at a publicly reachable host.

slug url-blocked-host
ALIAS_INVALID 400 URL shortener The custom alias doesn't match the allowed format.

The alias isn't 3-32 characters of lowercase letters, digits, hyphen or underscore.

How to fix it

Use a value matching ^[a-z0-9_-]{3,32}$, or omit alias to let the API generate a code.

slug alias-invalid
ALIAS_TAKEN 409 URL shortener The alias is already used on this domain.

Another link on the same domain already uses that alias. Codes are unique per domain.

How to fix it

Pick a different alias, use a different domain, or omit alias for an auto-generated code.

slug alias-taken
ALIAS_RESERVED 409 URL shortener The alias is a reserved word.

The alias collides with a reserved word (e.g. api, stats, admin, docs).

How to fix it

Choose a non-reserved alias.

slug alias-reserved
EXPIRES_AT_INVALID 400 URL shortener expiresAt must be a future ISO date-time.

expiresAt couldn't be parsed as an ISO-8601 date-time, or it is in the past.

How to fix it

Send a future ISO-8601 value, e.g. 2026-12-31T23:59:59Z, or omit it for a link that never expires.

slug expires-at-invalid
NOTHING_TO_UPDATE 400 URL shortener No updatable fields were sent.

The PATCH body had none of the updatable fields (active, expiresAt, longUrl).

How to fix it

Send at least one updatable field.

slug nothing-to-update
CODE_GENERATION_FAILED 500 URL shortener Could not allocate a unique code.

We couldn't allocate a unique random code after several attempts. This is rare.

How to fix it

Retry the request. If it persists, quote the meta.requestId in a support ticket.

slug code-generation-failed
STATS_RANGE_INVALID 400 URL shortener The stats range or granularity is invalid.

The statistics window is inconsistent: from after to, a range above the cap (1 year for day, 31 days for hour), or hour requested outside the ~90-day hourly retention.

How to fix it

Use a preset range or a valid from/to, and keep hourly queries within 31 days and the retention window.

slug stats-range-invalid
DOMAIN_NOT_ALLOWED 400 URL shortener The chosen domain isn't available to your account.

The domain you requested isn't a platform-global domain nor one owned by your account (or your account has no default domain configured).

How to fix it

Call GET /api/v6/urlshortener/domains to see the domains you can use, or omit domain to use your default.

slug domain-not-allowed
BAD_REQUEST 400 Generic Your request couldn't be parsed.

We could not parse your request. The usual culprits are malformed JSON in the body, a Content-Type header that doesn't match the payload, or a path with invalid characters.

How to fix it

Inspect the raw payload your client is sending; validating the JSON locally before the call usually surfaces the issue immediately.

slug bad-request
UNAUTHORIZED 401 Generic Generic 401: prefer the AUTH_* codes when present.

Generic 401 returned by the framework before our authentication logic could give you a more specific code. When you see this code, the request was rejected at a layer above the API key check.

slug unauthorized
FORBIDDEN 403 Generic Generic 403: fallback when no ACCOUNT_* code applies.

The request authenticated correctly but isn't allowed to access this resource. Whenever the cause is a known organization state, you'll receive an ACCOUNT_* code instead. This generic one is the fallback.

slug forbidden
NOT_FOUND 404 Generic The path you requested doesn't exist on this API.

The path you requested doesn't exist on this API. We also return this code (intentionally indistinguishable from a normal 404) for requests whose Host header isn't on our allowlist, so the API surface can't be probed by spelling guesses.

How to fix it

Compare the path against the reference. Watch out for trailing slashes and case, since paths are case-sensitive.

slug not-found
METHOD_NOT_ALLOWED 405 Generic The path exists but doesn't accept this HTTP method.

The path exists but it doesn't accept the HTTP method you used (for example, sending a POST to a read-only endpoint). The response includes an Allow header listing the methods that are valid for that path.

slug method-not-allowed
TOO_MANY_REQUESTS 429 Generic Generic 429: prefer the RATE_* codes when present.

Generic 429. Whenever the limit you hit is one of ours, we return RATE_DDOS_EXCEEDED or RATE_TPS_EXCEEDED instead, since those carry richer context. Branch on the specific codes when present.

slug too-many-requests
INTERNAL_SERVER_ERROR 500 Generic Something unexpected went wrong on our side.

Something unexpected went wrong on our side while handling your request. The full trace is stored against the same meta.requestId we returned, so we can investigate without you having to reproduce the failure.

How to fix it

Retry once with a small backoff. If you keep seeing it, open a support ticket and include the requestId so we can find the matching log entry quickly.

slug internal-server-error
SERVICE_UNAVAILABLE 503 Generic Generic 503: a backing service isn't responding.

A backing service we depend on isn't responding. The INFRA_* codes above are more specific when we can name the failing component; this one is the fallback otherwise.

How to fix it

Retry after Retry-After with a small jitter. Persistent occurrences point to a broader incident. Check the status page.

slug service-unavailable
GATEWAY_TIMEOUT 504 Generic Generic 504: an upstream took too long.

An upstream we depend on took too long to respond. When the slow component was the database, you'll see INFRA_DB_QUERY_TIMEOUT instead, which carries the same meaning with more context.

How to fix it

Retry with exponential backoff. Several in a row usually point to a wider degradation. Open a support ticket with the requestId.

slug gateway-timeout