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

# API conventions

> The rules every endpoint follows — versioning, authentication, errors, pagination, streaming — plus where the authoritative reference lives.

The authoritative reference is **generated from the shared contract** by the
running API, and rendered into this site from the committed specification:

| | |
| - | - |
| Rendered reference | `http://localhost:4000/api/docs` (Swagger UI) |
| Specification | `http://localhost:4000/api/openapi.json` |
| Committed snapshot | [`openapi.json`](/reference/openapi.json) |
| Base URL | `http://localhost:4000/api/v1` |

Both are generated by `buildOpenApiDocument()` in
`packages/contracts/src/http/openapi.ts` from the same zod schemas the API
validates with and the browser validates against. Every endpoint appears
automatically in the **API** group of this tab, one page per operation, with its
request, response and error schemas. Regenerate the snapshot with
`pnpm openapi:write`.

## Versioning

`v1` is in the path of every endpoint. Every response carries `x-api-version: v1`.
See [versioning](/explanation/api-versioning).

## Authentication

`Authorization: Bearer <access token>`, from `auth.signIn`. Two endpoints are
public: `auth.signIn` and `auth.refresh`. An expired access token is refreshed
once and the call is replayed; concurrent calls share a single refresh. See
[sessions](/explanation/authentication).

## Errors

An [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) problem document. Match on
`code`, not `title`. See [errors](/reference/errors).

## Pagination

List endpoints take `page` (1-based, default 1) and `limit` (default 50, maximum
200\) and answer with:

```json theme={null}
{ "items": [], "total": 0, "page": 1, "limit": 50 }
```

## Unknown fields

Ignored, not rejected, so a newer client can talk to an older API. Within `v1`
this is what makes additive change safe.

## Streaming

`chat.messages.stream` answers `text/event-stream`. Each frame is a `data:` line
holding one JSON event: `start`, `delta` (repeated), then `done` or `error`. The
contract's schema for the stream can be found under the operation in the rendered
reference. See [stream a reply](/how-to/stream-a-reply).

## Using the typed client

In the web app, call operations by name. Types come from the registry:

```ts theme={null}
const page = await apiClient.call('customers.list', { query: { page: 2, limit: 20 } })
```

Outside the web app, the same registry generates a client for any language from
the published specification.

## Keeping the reference honest

`packages/contracts/test/openapi.test.mjs` asserts that every registered operation
appears in the document, that each declared error code is documented, that public
operations opt out of bearer security, and that no reference dangles. Run it with
`pnpm --filter @dme/contracts test`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.