Errors and limits
Stable error codes to switch on, why 402 and 429 differ, what an error never contains, and the rate limits that exist today.
Every failure has the same shape, on both APIs and in MCP tool results:
{ "error": { "code": "forbidden", "message": "…", "details": {} } }Switch on code. The codes are stable across versions; the message is a sentence for a person
and may be reworded.
Codes
| Code | HTTP | Means |
|---|---|---|
unauthenticated | 401 | No usable credential, or one from the other plane |
forbidden | 403 | Your permissions or your credential’s scopes do not cover this |
not_found | 404 | No such thing, or none you can see |
conflict | 409 | Something changed underneath you, or an idempotency key was reused for another request |
validation_failed | 422 | The request is wrong; the message names the parameter or key |
rate_limited | 429 | Too many requests: wait and retry |
payment_required | 402 | The plan or the credit does not allow it: waiting will not help |
not_implemented | 501 | Not available on this deployment |
internal | 500 | Our fault. Retry with the same Idempotency-Key |
What an error never contains
The name of a field you cannot read. “You cannot read salary” tells you a field called
salary exists, which is exactly what the rule was hiding. Errors name the operation, never
the thing being protected, and a hidden field gets the same answer as a field that never
existed.
Likewise, something you cannot reach (missing, deleted, another organisation’s) is the same
404 with the same sentence, whichever it is.
Saved, with warnings
Email, URL and phone fields keep the text you send. A suspect format still succeeds, and the
response carries a warnings array (code: "suspect_format", with the record, the field and a
message) for the fields you can see. Do not retry a write because it has warnings.
Invalid numbers, impossible dates, unknown choices and values over a field’s limit fail with
validation_failed. Send numbers or numeric strings, and ISO dates such as 2026-09-22;
timestamps must carry a timezone. A failed create batch saves none of its rows.
Why 402 and 429 differ
A rate limit is about speed and clears on its own. A spend limit is about money and does not. Conflating them would tell someone who ran out of credit to wait, and they would wait forever.
Rate limits today
- Signing in and the OAuth endpoints are limited per address per minute and answer
429withrate_limitedbeyond that. /v1and MCP, on both planes, are limited per credential (per person for a browser session): 1,200 requests a minute and 300 per 10 seconds. A request with no credential is limited per address, 600 a minute. Beyond that the answer is429withrate_limitedand aRateLimit-Policyheader describing the limit. A well-behaved client backs off and retries; with anIdempotency-Key, a retried write is safe.