# The model: reads, commands and idempotency

The HeadHoncho API model is the app's own: reads over its read models, commands through its command names, and every command safe to repeat.

Page: https://headhoncho.app/docs/api/model | Part of the HeadHoncho API docs: https://headhoncho.app/docs/api | Machine-readable: https://headhoncho.app/docs/api/openapi.json

## Reads and commands

The HeadHoncho API model is the app's own, in two halves. A **read** is a `GET` over a read model the app already draws, so a number in the API is the number on the screen. A **command** is a `POST` that runs one of the app's own commands and answers with an acknowledgement. Nothing is computed in the API that the app does not compute.

Commands are posted to `/api/v1/commands/<verb>`, where the verb is the app's own command name:

| Verb | Endpoint | Call |
| --- | --- | --- |
| `create-job` | [Create job](https://headhoncho.app/docs/api/create_job) | `POST /api/v1/commands/create-job` |
| `update-job` | [Update job](https://headhoncho.app/docs/api/update_job) | `POST /api/v1/commands/update-job` |
| `change-job-status` | [Change job status](https://headhoncho.app/docs/api/change_job_status) | `POST /api/v1/commands/change-job-status` |
| `assign-worker` | [Assign worker](https://headhoncho.app/docs/api/assign_worker) | `POST /api/v1/commands/assign-worker` |
| `unassign-worker` | [Unassign worker](https://headhoncho.app/docs/api/unassign_worker) | `POST /api/v1/commands/unassign-worker` |
| `add-job-note` | [Add job note](https://headhoncho.app/docs/api/add_job_note) | `POST /api/v1/commands/add-job-note` |

## Every command needs an Idempotency-Key

Send an `Idempotency-Key` header with every command. Any unique string works, and a new random UUID per intended action is the usual choice.

- The same key with the same body returns the first answer and runs nothing twice. A retry after a dropped connection is safe.
- The same key with a different body is refused with status 409 and [`idempotency_mismatch`](https://headhoncho.app/docs/api/errors#idempotency_mismatch).
- No key at all is refused with status 400 and [`missing_idempotency_key`](https://headhoncho.app/docs/api/errors#missing_idempotency_key).

## See your own write

Every command answer carries a `position`: where the change landed in the event log. A read accepts `?after=<position>` and waits up to two seconds for the read model to catch up, so the next read shows what you just wrote. [Get job history](https://headhoncho.app/docs/api/get_job_history) returns the same positions beside each event.

```bash
curl -X POST ".../commands/add-job-note" ...
# answer: {"accepted": true, "job_id": "job_1203", "position": 88411, ...}
curl ".../jobs/job_1203?after=88411" ...
```

## Lists, cursors and counts

A list answers `{items, next, count}`. `items` is the page, `count` is how many match in all, and `next` is an opaque cursor for the following page, or `null` at the end. Pass the cursor back as `cursor` and change nothing else. Do not read inside it: it is not a promise about how paging works. [List jobs](https://headhoncho.app/docs/api/list_jobs) is the example; [Read table](https://headhoncho.app/docs/api/read_table) pages with `limit` and `offset` instead, because a raw table has a stable order.

## Ids, dates and money

- Ids are opaque text such as `cmp_14f5` or `job_1138`. Keep them exactly as given.
- Dates and times are ISO 8601. A date range is read in the company's time zone.
- Money is a plain number in the company's currency, and the answer says which currency.

## Building blocks, never the app

The API offers records, raw rows and single commands. It never offers a board, a question, a dashboard, a widget, a layout or an automation. The purpose is to let you build your own tool on top of the same facts, not to rebuild HeadHoncho from outside. The one report in the API, the Google Click ID report, is there because the customer hands its file to Google and it must exist outside the app. The [roadmap](https://headhoncho.app/docs/api/roadmap) lists what is planned and what is never offered.

Next: [API keys](https://headhoncho.app/docs/api/keys) for access, [errors and rate limits](https://headhoncho.app/docs/api/errors) for what a refusal looks like, and [the MCP server](https://headhoncho.app/docs/api/mcp) for AI apps. The records themselves are described on [the Jobs panel](https://headhoncho.app/docs/jobs) and [the Raw data board](https://headhoncho.app/docs/marketing/raw-data).
