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

# Conventions

> How every endpoint behaves — the envelope, ids, auth, versioning, pagination, and idempotency.

New here? Start with the [Quick start](/quickstart). This section is the exhaustive reference.

## Base URL

```
https://api.usepatchwork.co
```

Resource-oriented URLs, JSON in and out, standard verbs and status codes.

## The envelope

Every response is wrapped:

```json theme={null}
{ "status": "success", "data": { } }
```

```json theme={null}
{ "status": "error", "error": { "message": "…", "code": "…" } }
```

Unknown fields are omitted — we do not send nulls. Branch on `error.code`, never on `error.message`. See [Errors](/api-reference/errors).

## Objects

```
Thread                       one conversation, owned by one subject
  ├── Message[]              what was said
  └── Run[]                  one turn each
        └── Turn[]           one model call each
              └── Tool call[]  what the agent did
```

| Object | Id format |
| - | - |
| [Agent](/api-reference/agent) | `agent_` + 32 hex — names one exact published version |
| [Patch](/api-reference/patch) | `key@version`, e.g. `send_payment@3` |
| [Connection](/api-reference/connection) | UUID, or its name in relay |
| [Subject](/guides/subjects) | any non-empty string you choose |
| [Event](/api-reference/event) | `evt_` + hex |
| Threads, runs, turns, tool calls, messages | UUID |

## Authentication

Bearer token on every request.

```bash theme={null}
Authorization: Bearer <credential>
```

| Surface | Credential |
| - | - |
| Workbench (`identify`) | Workspace API key (`sk_…`) |
| Loom, relay | Workspace API key plus `Patchwork-Subject` |
| Loom, direct | A [session token](/guides/session-tokens) your backend signs |

The credential's form selects the Loom mode: a JWT is direct, anything else is relay. See [Authentication](/authentication).

## Headers

| Header | Used by |
| - | - |
| `Patchwork-Subject` | Relay. The [subject](/guides/subjects) this call acts for — **required** on threads, messages, runs and realtime. A session token carries its subject in `sub` instead. |
| `Patchwork-Connection` | Either mode. Which [connection](/guides/connections) the agent may call. |
| `Idempotency-Key` | Any `POST`. Makes the call safe to retry. See [Idempotency](#idempotency). |
| `Idempotency-Replayed` | On a response. `true` when you are seeing a stored result rather than fresh work. |

## Versioning

Public endpoints live under `/v1`. Breaking changes get a new prefix; additive fields may appear on existing objects without one.

Agent ids pin one exact version, so a published agent's behaviour does not change under you.

## Pagination

Every collection is paginated the same way. Pass `limit` and `cursor`; read `pagination` beside `data`.

```json theme={null}
{
  "status": "success",
  "data": [ ],
  "pagination": { "next_cursor": "eyJ2Ijoi…", "has_more": true, "limit": 25 }
}
```

| Parameter | Default | Notes |
| - | - | - |
| `limit` | `25` (messages: `50`) | Clamped to `100`. |
| `cursor` | — | Opaque. Pass back `next_cursor` verbatim; do not construct one. |

Walk a collection by following `next_cursor` until `has_more` is `false`, at which point `next_cursor` is `null`. Cursors are stable under writes: new rows arriving mid-walk will not shift a page and cause you to skip or repeat a row, which is why there is no `page` or `offset`, and no total count.

Messages are ordered oldest-to-newest **within** the page, while the pages themselves walk backwards from the most recent — so opening a thread costs one request, and following the cursor loads older history.

## Idempotency

Send an `Idempotency-Key` on any `POST` and the call becomes safe to retry. The key is yours to choose; a UUID per logical operation is the usual shape. Our SDKs generate one for every `POST` automatically.

The first request with a given key does the work and its response is stored. A retry with the same key returns that stored response, carrying `Idempotency-Replayed: true` — it does not run again, and it does not charge again.

| Situation | Response |
| - | - |
| Same key, same body, first call finished | The stored response, with `Idempotency-Replayed: true`. |
| Same key, same body, first call still running | `409 idempotency_in_flight`. Honour `Retry-After`. |
| Same key, different body | `422 idempotency_key_reuse`. Use a new key. |
| Same key, after a `5xx` | The key is released, so the retry genuinely re-runs. |

A replay is still a request, so it appears in your activity log with `Idempotency-Replayed`. It is left out of the Identify dashboard's counts, which report lookups performed and therefore match what you were charged.

Keys are scoped to your workspace and expire after 24 hours. Without a key, a `POST` behaves as it always has: repeating it repeats the work, so `POST /v1/identify` re-resolves and charges again, and a second `POST …/messages` starts a second turn.

## Rate limits and credits

Requests are metered per workspace — all API keys share one allowance. Every response carries `RateLimit-Limit`, `RateLimit-Remaining`, and `RateLimit-Reset`; a rejection is `429` with `Retry-After`.

Credits are prepaid and spent per run. An empty balance returns `402`. See [Rate limits and credits](/guides/limits).


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