Every error response uses the same envelope:
{
  "error": "snake_case_machine_code",
  "message": "Human-readable summary.",
  "details": {
    /* optional, route-specific */
  },
  "request_id": "01HVTQX4GZTH8XK1F2JZ7N5WJ4"
}
error is the contract. message and details may evolve; error is stable across versions and is what your code should branch on.

Common errors

HTTPerrorWhen
400invalid_requestBody fails Zod validation. details.issues matches the Zod issue array.
401missing_api_keyNo Authorization header.
401invalid_api_keyKey not found, revoked, or wrong prefix.
403wrong_networkTried to read a row outside the key’s network.
404agent_not_foundThe asset is not a registered agent on this network.
404event_not_foundEvent id does not exist for this key’s network.
404receipt_not_foundHash lookup miss on this network.
409idempotency_body_mismatchReplay with the same Idempotency-Key but a different body.
409event_already_submittedPOST /v1/submit for a different signed tx on the same event_id.
422receipt_agent_mismatchreceipt.agent does not equal the {agent} path parameter.
422receipt_chain_invalidprev_receipt_hash does not match the most recent stored receipt for the agent.
429rate_limitedSee Rate limits — body has retry_after_ms.
500internal_errorBug. Always paired with a request_id we can search for.
502rpc_unavailableUpstream RPC failed. Safe to retry.
504submit_timeoutsendRawTransaction did not return in time. The tx may still land — poll the event.
Submit is the only endpoint where a 5xx does not unambiguously mean “nothing happened” — the transaction may have reached a validator before the API timed out. Always recover by polling GET /v1/events/{id} rather than retrying blindly. The event id stays stable across retries.

request_id

Every response — success or error — includes X-Leash-Request-Id. Quote it when reporting issues; we keep request logs for 30 days indexed on it.

Validation details

Validation errors bundle every Zod issue verbatim:
{
  "error": "invalid_request",
  "message": "Body validation failed.",
  "details": {
    "issues": [
      { "path": ["allowance"], "message": "Required", "code": "invalid_type" },
      {
        "path": ["stable_symbol"],
        "message": "Invalid enum value. Expected 'USDC' | 'USDT' | 'USDG', received 'EUR'",
        "code": "invalid_enum_value"
      }
    ]
  }
}
First-party polyglot SDKs that surface these as field-level errors automatically are on the roadmap. Until they ship, generate a typed client from the OpenAPI spec (see API reference) and inspect details.issues directly.