Appearance
One meeting with its minutes and tasks
GET /api/v1/meetings/{id} meetings:read
One meeting, with its participants and the times they were present, the current minutes and the tasks.
⚠️ The participant shape here is NARROWER than under /participants: no domain, no attended. If you need the company or "invited, did not turn up", call /participants.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | uuid | yes | The meeting, by the id from /meetings. |
Response 200
The meeting.
Example response
json
{
"id": "8f14e45f-ceea-467a-9e2b-1d3f5c0a7b21",
"title": "Quarterly review",
"platform": "teams",
"source": "calendar",
"status": "ready",
"starts_at": "2026-08-04T08:00:00Z",
"ends_at": "2026-08-04T09:00:00Z",
"join_url": "https://teams.microsoft.com/l/meetup-join/…",
"organizer_email": "anna@company.example",
"created_at": "2026-08-01T09:12:44Z",
"template_id": "e07b6d13-84af-4c92-b5d7-0a9e1f83c246",
"participants": [
{
"display_name": "Anna Weber",
"email": "anna@company.example",
"is_internal": true,
"source": "calendar",
"approx_joined_at": "2026-08-04T08:01:37Z",
"approx_left_at": "2026-08-04T08:58:02Z"
}
],
"protocol": {
"id": "3b1f7c02-5d64-4c1a-9f88-2ac0e6b41d77",
"tldr": "Quote goes out by Friday, engineering clarifies the interface.",
"content_md": "# Quarterly review\n\n## Decisions\n…",
"generated_at": "2026-08-04T09:04:12Z",
"edited_at": null,
"action_items": [
{
"id": "c4d9f0a1-72be-4e35-8f10-6d2a5b8c9e04",
"task": "Send the quote",
"owner_name": "Anna Weber",
"due": "2026-08-15",
"verdict": "open",
"status": "open"
}
]
}
}| Field | Type | Required | Description |
|---|---|---|---|
id | uuid | yes | Identifies the meeting everywhere in this API. |
title | string | yes | Subject, as the calendar or the upload spelled it. |
platform | string | yes | Where it took place. upload means there was no live meeting — a recording came in. Values: teams, meet, zoom, upload. |
source | string | yes | How the meeting reached Protoki. Values: calendar, url, upload. |
status | string | yes | Where it stands. Only ready promises minutes; no_speech means nobody said anything worth writing down, and no_bot that no recorder ever joined. Values: scheduled, live, processing, ready, failed, no_bot, no_speech. |
starts_at | date-time | null | — | Start of the appointment. null for an upload, which has none. |
ends_at | date-time | null | — | End of the appointment. null for an upload. |
join_url | string | null | — | The link the recorder used to join. null for an upload. |
organizer_email | email | null | — | Who invited. null when the calendar gave nothing. |
created_at | date-time | yes | When the meeting was first recorded in Protoki. |
template_id | uuid | null | — | The template these minutes were written against. null when the default was used. |
participants | object[] | yes | Everyone the meeting knows about — present or only invited. |
participants[].display_name | string | yes | The name as the calendar or the meeting platform spelled it. |
participants[].email | email | null | — | Email address. null when neither source gave one. |
participants[].is_internal | boolean | yes | The email domain belongs to your own house. |
participants[].source | string | yes | Where this person came from: the invitation, the meeting platform, or a correction by hand. Values: calendar, platform, manual. |
participants[].approx_joined_at | date-time | null | — | When this person was first there. Approximate — it comes from the recording, not from a join event. |
participants[].approx_left_at | date-time | null | — | When this person was last there. Approximate, same reason. |
protocol | object | null | — | The most recent minutes — null for as long as none exist. |
protocol.id | uuid | yes | Identifies this set of minutes. |
protocol.tldr | string | null | — | The short version. null when the model produced none. |
protocol.content_md | string | yes | The full minutes, in Markdown. |
protocol.generated_at | date-time | yes | When the model wrote these minutes. |
protocol.edited_at | date-time | null | — | Set once a person has edited the minutes. |
protocol.action_items | object[] | yes | The tasks taken from these minutes. |
protocol.action_items[].id | uuid | yes | Identifies the task. |
protocol.action_items[].task | string | yes | What is to be done, in one sentence. |
protocol.action_items[].owner_name | string | null | — | Who is to do it. null when nobody was named in the meeting. |
protocol.action_items[].due | date | null | — | When it is due. null when no date was named. |
protocol.action_items[].verdict | string | yes | Outcome of the second pass over the task. resolved_in_meeting means it was already dealt with while the meeting was still running. Values: open, resolved_in_meeting, discarded, duplicate, unclear_owner. |
protocol.action_items[].status | string | yes | Where the task stands. This one is set by a person in the app, not by the model. Values: open, done, dismissed. |
Other answers
| Code | Meaning |
|---|---|
401 | No key, or a key that is not valid. |
403 | The key is missing the scope this endpoint needs. |
404 | Not found, not in the workspace of the key — or, for a personal key, not visible to that person. 404 rather than 403, deliberately. |
500 | The minutes could not be loaded. |