# Errors Every failure comes back as JSON with the same two keys, whatever went wrong: ```json { "message": "Falta la lada del país. Manda el número como «+525555555555», o añade «phone_country» (por ejemplo «MX»). Sin lada no podemos enviarle WhatsApp ni llamarle.", "errors": { "phone": ["Falta la lada del país. Manda el número como «+525555555555», o añade «phone_country» (por ejemplo «MX»). Sin lada no podemos enviarle WhatsApp ni llamarle."] } } ``` - `message` is one sentence, safe to log and safe to show a person. - `errors` maps each field that failed to the reasons it failed. It is present on every `4xx` this API produces, so you can read `errors` without checking first. - Messages are in **Spanish** by default, because the people who read them in the CRM are. Send `Accept-Language: en` for English where a translation exists. Never match on the text: match on the status code and the field name. ### The codes | Code | What happened | Retry? | |---|---|---| | `400` | A required header is missing — in practice, `Idempotency-Key` on an endpoint that demands it | Only after fixing the request | | `401` | No token, an expired token, or one that was revoked | No. Issue a new token | | `403` | The token is valid but lacks the ability for this location, or the role cannot do this | No. See [Authenticating requests](https://klozzo.com/docs/guides/authenticating-requests) | | `404` | Nothing here matches — **including a record that exists in another location** | No. Check the reference | | `409` | Two calls raced on the same `Idempotency-Key`, **or** a person here already closed the deal | No. Read the body before deciding | | `422` | The request was understood and rejected. Read `errors` | Only after fixing the payload | | `429` | Over the rate limit | **Yes**, after `Retry-After` | | `5xx` | Our fault | **Yes**, with backoff | ### Why a `404` and not a `403` A record that belongs to another location answers `404`, exactly as if it had never existed. Answering `403` would confirm that the id is real, which is information an outsider should not be able to collect one request at a time. So `404` means "not yours or not there" and there is no way to tell the two apart. That is deliberate. ### What to do with a `429` Every response carries `X-RateLimit-Limit` and `X-RateLimit-Remaining`, so you can slow down **before** being cut off rather than after. When you do go over, the `429` carries `Retry-After` in seconds: wait that long, then continue. Do not retry a `429` immediately, and do not spread the same work across more tokens to get around it — the budget is per token precisely so that one runaway loop cannot starve the rest of your integration. ### What is safe to retry - **`5xx` and `429` are always safe to retry.** Nothing was recorded. - **`4xx` is never worth retrying unchanged.** The same request will fail the same way; something in it has to change first. - **Anything that moves money must carry an `Idempotency-Key`** so that a retry after a timeout — where you never saw the answer — cannot charge twice. See [Idempotency](https://klozzo.com/docs/guides/idempotency). A timeout is the one case where you do not know which of the two you had. Retry it with the same key: if the first call landed, you get its answer back instead of doing the work again.