orkasa

Concepts

Errors

The error envelope, the stable codes, and what to do with each.

Every error comes out in the same shape:

{
  "error": {
    "code": "validation_error",
    "message": "…",
    "details": []
  }
}

code is the contract. Branch on it, never on the HTTP status or the message: the message is written for a person and its wording can change without notice.

codeHTTPwhen
unauthorized401missing, malformed, unknown or revoked credential
forbidden403the credential lacks the required permission
not_found404no such row in this brokerage
validation_error422bad payload, unknown field, illegal transition
rate_limited429over the credential's budget
internal_error500unexpected failure (no details echoed)

404 instead of 403, deliberately

An id that exists in another brokerage is answered 404 not_found, never 403. A 403 would confirm that the row exists somewhere, and that is already information: you could walk an id space and learn the size of a competitor's book. The API confirms nothing outside your own brokerage.

Bodies are strict

A field the API does not know is a 422, not a silently ignored key. A misspelled budget_maxx fails now, instead of being half-saved and discovered three weeks later when the funnel stops adding up.

System columns — brokerage_id, id, timestamps, public_slug — are not reachable from any payload.

When a stage is blocked

It is the most frequent 422, and the one that carries the most information:

{
  "error": {
    "code": "validation_error",
    "message": "La etapa actual tiene 4 paso(s) pendiente(s).",
    "details": {
      "reason": "stage_gate_blocked",
      "pending_actions": [
        { "id": "ofertaPreparada", "label": "Oferta preparada con el comprador" },
        { "id": "ofertaEnviada",   "label": "Oferta enviada al vendedor" },
        { "id": "respuestaVendedor", "label": "Respuesta del vendedor recibida" },
        { "id": "precioAcordado",  "label": "Precio acordado" }
      ]
    }
  }
}

Nothing was written. The transition is validated before the row is touched, so a refusal leaves the operation exactly where it was. See Stages.

Action labels come back in the brokerage's own language — they are the same strings the app shows its agents, not a translation layer.

In MCP, errors have two levels

The connector separates two things that do not mean the same:

  • a JSON-RPC error — the frame makes no sense: unknown method, malformed params. That is a protocol failure.
  • isError: true inside the result — the call worked, and the answer is "no, and here is why": a file that does not exist, a stage gate, a permission that was not granted.

The second form is deliberate: the caller is a language model, and a protocol code hides the reason from it. Told the reason, it can explain to the agent what is missing instead of retrying the same thing.