Skip to content
Klozzo API
OpenAPI Postman

Errors

Every failure comes back as JSON with the same two keys, whatever went wrong:

{
  "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
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.

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.