Appearance
REST endpoints
Every endpoint lives under /api/v1 and answers JSON. This page is what they all have in common. The details of one endpoint — its parameters, its response fields, the codes it can answer with — are on its own page, and those pages come straight out of the OpenAPI description.
| Endpoint | What it does | Scope |
|---|---|---|
GET /meetings | List meetings | meetings:read |
GET /meetings/{id} | One meeting with its minutes and tasks | meetings:read |
GET /meetings/{id}/action-items | Tasks of one meeting | action_items:read |
GET /meetings/{id}/participants | Participants of one meeting | meetings:read |
GET /action-items | Tasks across meetings | action_items:read |
GET /search | Full-text search | meetings:read |
GET /customers | Companies of the workspace | meetings:read |
GET /meetings/{id}/transcript | Transcript segments | transcripts:read |
What holds everywhere
One workspace. A key belongs to one workspace and never sees another. A personal key narrows that again to the meetings its owner sees in the app. The shape of the answer is the same either way — only the set of rows differs.
Filters run on the server. You are not meant to fetch everything and sort it out afterwards. An invalid value comes back as 400 with the field named in the text; it is never silently ignored.
Pagination, where there is any. limit and offset go in, and a pagination object comes back with total — the number of hits without limit and offset. Three endpoints have no pagination at all: search, participants and companies. They answer in full.
/meetings/{id}/action-items is the one exception you have to know about: it reports the number of rows delivered in pagination.limit and always 0 in pagination.offset. Only total is the real total there. It is written that way on its page too, because the endpoint really does behave that way.
A meeting you may not see is a 404, not a 403 — otherwise the existence of other people's meetings would show through. On the two list endpoints the same thing shows up as an empty list.
An example
http
GET /api/v1/meetings?from=2026-08-01&to=2026-08-07&q=Quarterly&order=starts_at
Authorization: Bearer pk_live_your_keyjson
{
"data": [
{ "id": "…", "title": "Quarterly review", "platform": "teams",
"status": "ready", "starts_at": "2026-08-04T08:00:00Z", "…": "…" }
],
"pagination": { "limit": 50, "offset": 0, "total": 3 }
}The interesting query is usually not "list my meetings" but GET /action-items: everything still open and due by Friday, across meetings, without loading the meetings first.