Error Response Format
Every Fetchin API error returns the same JSON shape: a human-readableerror string and a stable, machine-readable code. Branch your integration
on code (and the HTTP status) — never on the error text, which may change.
details object (or, for the multi-profile
endpoint, top-level fields such as creditsNeeded) with extra context.
Authentication errors (
401, 403) additionally include legacy message and
statusCode fields for backward compatibility. New integrations should rely on
error and code.Error Code Reference
HTTP Status Codes
400 Bad Request
The request itself is malformed — a missing parameter (MISSING_PARAMETER), an
invalid value (INVALID_PARAMETER), or an unparseable professional URL/URN
(INVALID_URN).
401 Unauthorized
TheX-API-Key header is missing (UNAUTHENTICATED) or invalid
(INVALID_API_KEY).
A sudden
INVALID_API_KEY on a previously working integration usually means
the key was revoked from the dashboard. A revoked key never comes back — create
a new one, deploy it, and check the Last used column before revoking
anything else. See Rotating your API key.404 Not Found
We reached the service successfully, but the requested profile, post, or company genuinely does not exist.410 Gone
The path you called was a real endpoint and has been retired (code: "ENDPOINT_REMOVED"). It is deliberately not a 404: a 404 would
read as “you mistyped the URL”, when in fact the URL was right and the endpoint
is gone.
error text says what replaced it, when something did. A 410 consumes no
credits and never will — it does no work.
Solution: Don’t retry; the answer will not change. Move to the replacement
named in the message, or contact support. Nothing currently listed in this
reference returns a 410; you will only meet it on an integration written
against a path we no longer publish.
402 Payment Required
You are out of credits (code: "QUOTA_EXHAUSTED"). Usually this means every
balance is empty: your plan allowance for the current period is spent, and no
pay-as-you-go credits are left. There is no Retry-After
— waiting for the next second does not help.
A request that costs more than 1 credit is checked against its full price
before it runs, so it also gets a 402 when what is left is positive but below
that price. With 1 credit left, for example, /post/engagement and /profile
with fullProfile=true are refused while a 1-credit request still goes through.
The
error text is unchanged and stays byte-for-byte what it has always been —
it says nothing about which balance ran out. That breakdown is in details,
which is additive: read it for diagnostics, but branch on code and never
require a details field to be present. For live figures at any time, call
GET /api/v1/subscription, which
keeps answering while you are blocked.429 Too Many Requests
You exceeded your per-second request rate (code: "RATE_LIMITED"). A
Retry-After header tells you how long to wait.
POST /api/v1/posts/search, whose
allowance follows your plan’s rate limit and is set so that sending that rate
does not reach it. The error text says which one you hit:
Retry-After. If the text points at
requests in flight, lower your concurrency rather than your rate — see
Concurrency limits.
503 Service Unavailable
Our API is temporarily unable to serve your request — we’re at capacity or overloaded. This is on our side. It is not your request’s fault and not an upstream service outage.Retry-After header.
The same request will typically succeed shortly after.
500 Internal Server Error
An unexpected bug occurred in our API.502 / 504 Upstream Errors
UPSTREAM_ERROR (502) and UPSTREAM_TIMEOUT (504) indicate a genuine failure or
timeout on the upstream service’s side (as opposed to our capacity, which is 503). Retry
with backoff.
Error Handling Examples
JavaScript/TypeScript
Python
Best Practices
Branch on code, not the message
Branch on code, not the message
The
error string is for humans and may change. The code is a stable
contract — switch on it to decide how to react.Retry 503, 500, and 429 — but not 4xx
Retry 503, 500, and 429 — but not 4xx
503, 500, 429, 502, and 504 are transient and safe to retry with
exponential backoff. A 400/401/404/410 will keep failing until you
change the request.Honor Retry-After
Honor Retry-After
429 and 503 responses include a Retry-After header (seconds). Wait at
least that long before retrying.Distinguish RATE_LIMITED from QUOTA_EXHAUSTED
Distinguish RATE_LIMITED from QUOTA_EXHAUSTED
They now have different HTTP statuses:
QUOTA_EXHAUSTED is 402 (you need
more credits — buy pay as you go, upgrade, or wait
for renewal), RATE_LIMITED is 429 (slow down and honor Retry-After). The
code field carries the same distinction. They require different handling:
more credits will never clear a 429, and backing off will never clear a
402.Treat 503 as 'try again', not 'no data'
Treat 503 as 'try again', not 'no data'
503 SERVICE_UNAVAILABLE means we couldn’t serve you right now — it does not
mean the profile/post is empty or gone. Retry shortly.Quota & Credits
Failing requests do not consume credits, with one exception: a404 costs 1
credit, because the lookup ran to completion before it could report the absence.
Everything else is free, including 400, 401, 403, 410, 429, 402
itself and every 5xx on our side.
What a successful request costs is the endpoint’s own price — one credit on
every endpoint documented here except /post/engagement (2 credits) and
/profile with fullProfile=true (2 credits, or 1 when its extra page could not
be read), unless that endpoint’s reference page states otherwise.
Credits come from your monthly plan allowance and from any
pay-as-you-go credits you hold; requests spend the plan
first, then pay as you go by soonest expiry, and a 402 arrives once both are
empty, or once what is left is below the price of the request.
See Quotas, Pay as you go and
Rate Limits for details, or the full per-endpoint
breakdown at fetchin.io/pricing/credits.