# Errors, limits, and what to do about each one Every immut API error returns the same JSON shape. Read the `code`, not the message. Messages get reworded. Codes do not. ```json { "success": false, "code": "SCOPE_NOT_PERMITTED", "message": "This key cannot write documents" } ``` The rule that matters most: **most errors are not worth retrying.** Only two are. Retrying the rest just burns your rate limit and hides the real problem from the person who can fix it. ## Which errors should an agent retry? Two, and only two. | Status | Code | Retry? | |---|---|---| | `429` | `RATE_LIMIT_EXCEEDED` | Yes. Wait for `Retry-After`, then retry once. | | `500` | none | Yes, once, if the call is idempotent. | | `502` | `PROOF_NOT_RECORDED` | No. The file stays queued. See below. | | `4xx` | anything else | No. Nothing changes if you send it again. | ## What do the authentication errors mean? These four mean stop and tell the person. None of them clear on their own. | Status | Code | What happened | What to do | |---|---|---|---| | `401` | `INVALID_API_KEY` | The key is missing, malformed, revoked, or expired. | Stop. Ask the person for a new key. | | `403` | `SCOPE_NOT_PERMITTED` | The key is valid but lacks the scope for this call. | Stop. Report which call failed. | | `403` | `API_ACCESS_DISABLED` | The organisation turned API access off. | Stop. An admin re-enables it in the app. | | `403` | `COMPANY_SUSPENDED` | The account is suspended, usually billing. | Stop. Only a person can fix this. | **Never ask a customer to widen an API key.** If a call needs a scope the key does not have, that call is not yours to make. Report it and move on. ## What happens when the upload allowance runs out? You get a `403` with the code `ENTITLEMENT_EXCEEDED` and a `usage` object. ```json { "success": false, "code": "ENTITLEMENT_EXCEEDED", "message": "Upload limit reached", "usage": { "used": 100, "limit": 100, "remaining": 0 } } ``` This is not a failure to retry. It is a budget that has run out. Stop uploading, record the remaining files as waiting, and tell the person how many are queued and what it would take to clear them. Billing is not readable by an agent key. You learn the limit from this response, or from the person. Do not guess it. ## What are the rate limits? 60 requests per minute and 10,000 per day, per key. Some keys have higher limits. Do not plan against those numbers. Trust the `429` and its `Retry-After` header instead. A key with a custom limit will tell you the truth in the response. ## Why would a proof return 502? `PROOF_NOT_RECORDED` means immut could not confirm the permanent record. This is deliberate and it is a safe answer. The file stays where it was. Nothing is shown to the customer as protected. A proof that cannot be confirmed is worse than no proof, so immut refuses rather than guesses. Report it and try that file on the next run. ## What does a 400 tell you? A field is missing or malformed. The message names it. Fix the request before sending it again. The two caught most often are a missing `workspace` on `POST /proofs` and a missing `runId` on `POST /agent/runs`. Both read as optional if you skim. Neither is. ## What does a 404 mean here? Either the record does not exist, or it belongs to another organisation. immut does not distinguish between the two on purpose. Telling you which one it was would leak whether a record exists in someone else's account. ## Full endpoint list Every endpoint and its exact responses: [API reference](/docs/api). Everything in one file for an agent: [llms-full.txt](https://www.immut.io/llms-full.txt).