Appearance
Processing of a meeting failed
POST to your own endpoint meeting.failed
Protoki calls this address when processing a meeting breaks off — there are no minutes in that case.
This event is NOT on by default. A newly registered endpoint gets meeting.ready only; you add meeting.failed in the admin area under "Webhooks". That way an automation that already runs does not suddenly receive calls without minutes.
Signature check, retries and deduplication are identical to meeting.ready.
⚠️ retryable is always true: a meeting can be processed again from the app. Treat the event as a hint, not as a final verdict — a later meeting.ready for the same meeting is possible and normal.
Headers
| Name | Type | Required | Description |
|---|---|---|---|
Protoki-Signature | string | yes | Timestamp and signature: t=1770000000,v1=<hex>. |
Protoki-Event | string | yes | Values: meeting.failed. |
Protoki-Delivery | uuid | yes | Delivery id, for deduplication. |
Body
Example
json
{
"event": "meeting.failed",
"delivery_id": "e07b6d13-84af-4c92-b5d7-0a9e1f83c246",
"occurred_at": "2026-08-04T09:04:15Z",
"workspace_id": "3b1f7c02-5d64-4c1a-9f88-2ac0e6b41d77",
"data": {
"meeting": {
"id": "e07b6d13-84af-4c92-b5d7-0a9e1f83c246",
"title": "Quarterly review",
"platform": "string",
"source": "string",
"status": "string",
"starts_at": "2026-08-04T08:00:00Z",
"ends_at": "2026-08-04T09:00:00Z",
"organizer_email": "anna@company.example",
"join_url": "https://teams.microsoft.com/l/meetup-join/…"
},
"failure": {
"stage": "transcribe",
"retryable": true
}
},
"links": {
"meeting": "https://protoki.com/api/v1/meetings/e07b6d13-84af-4c92-b5d7-0a9e1f83c246",
"app": "https://protoki.com/api/v1/meetings/e07b6d13-84af-4c92-b5d7-0a9e1f83c246"
}
}| Field | Type | Required | Description |
|---|---|---|---|
event | meeting.failed | yes | Which event this is. Branch on it, not on the shape of data. |
delivery_id | uuid | yes | Stays the same across every retry — this is what you deduplicate double deliveries on. |
occurred_at | date-time | yes | When the event happened on our side, not when this attempt was sent. |
workspace_id | uuid | yes | The workspace the meeting belongs to. |
data | object | yes | The payload of the event. |
data.meeting | object | yes | The meeting this event is about. |
data.meeting.id | uuid | — | Identifies the meeting everywhere in this API. |
data.meeting.title | string | — | Subject, as the calendar or the upload spelled it. |
data.meeting.platform | string | — | Where the meeting took place. |
data.meeting.source | string | — | How the meeting reached Protoki. |
data.meeting.status | string | — | Where the meeting stood when this call went out. |
data.meeting.starts_at | date-time | null | — | Start of the appointment. null for an upload, which has none. |
data.meeting.ends_at | date-time | null | — | End of the appointment. null for an upload. |
data.meeting.organizer_email | string | null | — | Who invited. null when the calendar gave nothing. |
data.meeting.join_url | string | null | — | The link the recorder used to join. null for an upload. |
data.failure | object | yes | What went wrong, as far as it is safe to say. |
data.failure.stage | string | yes | The processing stage it broke off at (for example transcribe, protocol). Deliberately coarse — an internal error text is not handed out. |
data.failure.retryable | boolean | yes | Always true: a meeting can be processed again from the app, and the reconciler picks up anything left hanging anyway. |
links | object | yes | Ready-made addresses, so nothing has to be assembled by hand. |
links.meeting | uri | yes | The meeting in this API. |
links.app | uri | yes | The meeting in the Protoki app, for a person to open. |
Response 200
Accepted.
Other answers
| Code | Meaning |
|---|---|
410 | This receiver is gone — Protoki stops sending. |