> ## Documentation Index
> Fetch the complete documentation index at: https://docs.trylath.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Every Lath operation is POST https://platform.trylath.com/<operation name with dots replaced by slashes>, with a JSON body and `Authorization: Bearer <key>`. `email.send` is POST /email/send.
> Branch on `error.code`, never on `error.message`. Every refusal also carries `error.fix`, which names the next step.
> Send an `Idempotency-Key` header on any operation that is not retry-safe, so a retry cannot run it twice.
> A `lath_test_` key emails only the account's own members and sends no SMS; a `lath_live_` key reaches real recipients and is billed.
> The OpenAPI document, generated from the same registry as the routes, is at https://platform.trylath.com/openapi.json.

# Errors

> Every error says what happened and what to do about it, in a shape meant to be read by whatever is calling.

## The shape

An error carries a `code` to branch on, a `message` describing what happened, and a `fix` describing the way out. The HTTP status matches the class of problem.

The `fix` exists because most callers are not sitting at a terminal. An agent that receives one has its next step named for it.

```json theme={null}
{
  "error": {
    "code": "unauthenticated",
    "message": "No valid key was presented.",
    "fix": "Send `Authorization: Bearer <key>` with a key from Developers → Keys."
  }
}
```

## Ones you will meet

`unauthenticated` — no valid key. `spending_cap_reached` — the send would cross the cap and nothing was queued. `missing_variables` — the template references variables the call did not supply, and names them. `sms_too_long` — the body exceeds the segment limit, with the count and the encoding that decided it.

`invalid_input` names the field. `not_found` names the thing.

## A success is not always a delivery

This is the one worth reading twice. `sms.send` can answer 200 with `status: "suppressed"` and a `blocked` object — the message was accepted and stored, and has not left.

Today that is what a new project gets, because no carrier registration has been filed. Check `blocked` before reporting a message as delivered; a status that cannot change yet is not one to wait on.

```json theme={null}
"blocked": {
  "reason": "No carrier registration has been filed for this project yet.",
  "fix": "Check sms.registration.get for where it has got to."
}
```
