Failures use the same envelope as successes. status becomes "error", data becomes null,
and error carries one sentence written for a human:
{
"status": "error",
"error": "The 'email' parameter is required.",
"data": null
}Read the HTTP status to decide what kind of problem it is, and error to decide what to
change. The sentence names the parameter; it is not a generic code you have to look up.
Statuses
| Status | Meaning | Retry? |
|---|---|---|
200 | Success | — |
400 | The request is wrong — bad parameter, missing field, or an upload over the plan's size limit | Not until it changes |
401 | Key is well-formed but not recognised | No |
403 | Key is valid but not allowed to make this call | No |
404 | No such source on this door | No |
429 | Rate limited or out of credits | Sometimes — see below |
500 | Something failed on our side | Yes, with backoff |
503 | Upstream source is unavailable | Yes, with backoff |
Two of these do not mean what their names suggest, and both are worth reading carefully.
403 is not an authentication failure
401 is the only status that means "we do not accept this key". If you get one, the credential
is wrong — check it before anything else.
403 means the opposite: the key is real and accepted, but it is not permitted to make this
particular call. There are three causes, and the error sentence tells you which:
error says | Cause | Fix |
|---|---|---|
Access to <api> is blocked for this API key | Key scoping blocks this source | Adjust the key's restrictions |
IP address not allowed for this API key | The caller's IP is not on the key's allow-list | Add the IP, or use a different key |
API key has been revoked. | The key was rotated or deleted | Use the current key |
Treating a 403 as "sign in again" sends someone to fix something that is not broken. See
key scoping.
429 is two different problems
A 429 is either slow down or the month is spent, and they need opposite responses. The
discriminator is the credit header, not the message:
if (res.status === 429) {
if (Number(res.headers.get('x-api-remaining-credits')) === 0) {
// Out of credits. Retrying cannot help.
} else {
// Rate limited. Wait retry-after and repeat.
}
}Full treatment, including backoff that does not make it worse, is on rate limits.
404 means "not on this door"
A 404 is returned both for an source that does not exist and for one that exists but is not
part of this product's catalog. That is deliberate — the response does not reveal that an
source you cannot call exists elsewhere.
If a call worked yesterday and 404s today, check you are calling the host that matches your account rather than assuming the source was removed.
Validation errors
A 400 names what to change:
{
"status": "error",
"error": "The 'dob' parameter must be a valid date in YYYY-MM-DD format.",
"data": null
}Undeclared parameters are a special case worth knowing: a parameter the source does not declare is dropped silently rather than rejected. The call succeeds and quietly ignores your input. If a parameter appears to have no effect, check its spelling against the reference page before assuming it is broken.
What the agent sees
A failed tool call does not come back as a protocol error. The server returns a normal result
with isError: true and a text block explaining what went wrong, so the model can read it and
either fix its arguments or tell the user.
That has one consequence worth designing around: an agent will retry a 400 by guessing
differently. A wrong parameter, a badly formatted date, a value outside the allowed set — the
model sees a sentence saying so and tries again, sometimes several times, each attempt spending
credits. Two things keep that bounded:
- Scope the key so an agent can only reach the tools it is for; see key scoping.
- Give each agent its own sub-key, which gives it its own rate limit and its own line in the usage breakdown — a retry loop shows up as one agent, not as a mystery in the account total.
Connection-level failures behave differently from call-level ones. A rejected credential does not produce a failed tool call; it produces a client that lists no tools at all. If an agent claims a capability does not exist, check the connection before the catalog.
What is worth retrying
- Retry with backoff:
500,503, and a429that still has credits left. - Never retry unchanged:
400,401,403,404, and a429with zero credits. Nothing about the next attempt will be different, and repeated identical failures get their own throttle.
Next
Ceilings and backoff are in rate limits; the server itself is documented in MCP server.
If a failure here is not the one you expected, the FAQ covers the common surprises.