# Conventions

> Source: https://elaichi.ai/docs/api-reference/overview/conventions/

The API follows the same handful of patterns everywhere, so once you've used one resource you can predict the rest.

## URL patterns

| Pattern | Shape | Examples |
| --- | --- | --- |
| **Standard CRUD** | `GET`/`POST /resource`, `GET`/`PATCH`/`DELETE /resource/:id` | `/role`, `/toolbox`, `/connection` |
| **Actions** | `POST /resource/:id/<verb>` | `verify`, `reconnect`, `execute`, `test`, `rotate` |
| **Nested collections** | `/resource/:id/<collection>[/:childId]` | `members`, `share`, `mcp` |

Update fields with `PATCH /resource/:id` and send only what changed. Actions are reserved for things that *do* something rather than edit a field — verifying a domain, rotating a token.

## Pagination

List endpoints return a page of results with cursors:

```json
{
  "result": [],
  "next_cursor": "opaque-string-or-null",
  "prev_cursor": "opaque-string-or-null"
}
```

Pass `limit` (default 50, maximum 200) and `cursor` as query parameters. Treat cursors as opaque — pass back exactly what you received, and stop when `next_cursor` is `null`.

## Errors

Failures use standard HTTP status codes with a consistent body:

```json
{
  "error": {
    "message": "human readable explanation",
    "code": "machine_code"
  }
}
```

Branch on `code`, and surface `message` when you need to show something to a person.

| Code | Usually means |
| --- | --- |
| `bad_request` | The request was malformed |
| `validation_error` | A field failed validation |
| `unauthorized` | Missing or invalid token |
| `forbidden` | Valid token, but not allowed to do this |
| `not_found` | No such resource, or not visible to you |
| `conflict` | Clashes with the current state |
| `rate_limited` | Slow down and retry |
| `internal_error` | Something went wrong on our side |

## OpenAPI

The machine-readable description is available at `GET /schema/openapi.yml` and `GET /schema/openapi.json` — useful for generating clients or importing into API tooling.
