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

# Conventions

> Pagination, errors, idempotency and rate limits — the same everywhere.

# Conventions

## Pagination

List responses share one envelope:

```json theme={null}
{ "count": 10, "limit": 50, "next_page_token": "…", "inboxes": […] }
```

`limit` defaults to 50 (max 100; search caps at 100). Pass
`?limit=&page_token=` to walk. Ordering is newest-first unless `ascending=true`.

## Errors

```json theme={null}
{ "name": "not_found", "code": "not_found", "message": "…",
  "fix": "…", "docs": "https://docs.lupin.sh/error-reference" }
```

Branch on `code`. Validation failures come back as `validation_error` with an
`errors` payload. Common codes: `unauthenticated` (401), `missing_permission`
(403), `not_found` (404), `rate_limited` (429 + `Retry-After` header).

## Idempotency

* Sends: `Idempotency-Key` header on `POST …/emails/send` — replays return
  the original email.
* Creates (inbox, draft, webhook, domain, project): pass `client_id` — replays
  return the original object.

## Rate limits

600 requests/minute per key. Exceeding it returns 429 `rate_limited` with a
`Retry-After` header. Back off and retry.

## Wire format

snake\_case everywhere, ISO-8601 timestamps, `200` on creates (not `201`),
empty `{}` on deletes. The machine-readable route list lives at
`GET /v0/openapi.json` (138 entries).
