Skip to content

Events

Every path is relative to https://app.lobbe.ai/api/v1, and every request sends Authorization: Bearer $LOBBE_TOKEN. The API reference lists every route and explains the x-lobbe-* fields.

What happened to the owner’s meetings since a cursor: created, waiting for names, ready, failed, updated, deleted.

Property Value
Scopes recordings:read or recordings:write
Spends minutes No
Rate limit read: 600 requests per 10 minutes per token
Success 200
Name In Type Required Description
after query "latest" | string No Where to read from: the nextCursor of the previous page, passed back as is, or latest, which starts from now (no events, and a cursor to poll with). Absent = the oldest event a fresh read serves, about two hours inside the 30-day window events are kept for. A cursor older than that window answers 410 CURSOR_EXPIRED: take a new cursor with after=latest first, then catch up from listReadyRecordings, then read on from that new cursor. A malformed value is a 400
limit query integer No How many events to return, 1–500 (default 100)

What happened to the meetings this token reaches since after, oldest first. With recordings:read, the owner’s own meetings (not those of a series they joined); with only recordings:write, the meetings this token submitted.

Field Type Always present Description
schemaVersion 1 Yes Always 1 within API v1
events[] object[] Yes The events on this page, oldest first; for one meeting, in the order its changes happened. No event carries a meeting’s content: only ids, its status, an error code or the kind of change
events[] (type: "recording.created") object A meeting was received
events[].id string Yes The event’s own id, the same on every read: use it to skip an event you already handled. It is not a cursor (page with nextCursor)
events[].recordingId string Yes The id of the meeting it is about
events[].seriesId string | null Yes The series the meeting was in when the change happened; null when it was in none, or while series are switched off
events[].occurredAt string Yes When the change happened (ISO 8601, UTC); follow the feed’s order rather than sorting by it
events[].type "recording.created" Yes recording.created: the meeting was received in full, whether recorded in the app, uploaded or submitted by a token
events[].data object Yes The meeting’s status as the change left it
events[].data.status "QUEUED" | "TRANSCRIBING" | "NAMING" | "GENERATING" | "READY" | "FAILED" Yes Where the meeting is: QUEUED, TRANSCRIBING, NAMING (waiting for the speakers’ names), GENERATING (the Lobbe is being made), then READY; or FAILED
events[] (type: "recording.naming_required") object A meeting is waiting for names
events[].id string Yes The event’s own id, the same on every read: use it to skip an event you already handled. It is not a cursor (page with nextCursor)
events[].recordingId string Yes The id of the meeting it is about
events[].seriesId string | null Yes The series the meeting was in when the change happened; null when it was in none, or while series are switched off
events[].occurredAt string Yes When the change happened (ISO 8601, UTC); follow the feed’s order rather than sorting by it
events[].type "recording.naming_required" Yes recording.naming_required: the meeting is at NAMING, waiting for its speakers’ names or a skip (skipRecordingNaming); sent again each time naming opens again
events[].data object Yes The meeting’s status as the change left it
events[].data.status "QUEUED" | "TRANSCRIBING" | "NAMING" | "GENERATING" | "READY" | "FAILED" Yes Where the meeting is: QUEUED, TRANSCRIBING, NAMING (waiting for the speakers’ names), GENERATING (the Lobbe is being made), then READY; or FAILED
events[] (type: "recording.ready") object A meeting’s Lobbe is ready
events[].id string Yes The event’s own id, the same on every read: use it to skip an event you already handled. It is not a cursor (page with nextCursor)
events[].recordingId string Yes The id of the meeting it is about
events[].seriesId string | null Yes The series the meeting was in when the change happened; null when it was in none, or while series are switched off
events[].occurredAt string Yes When the change happened (ISO 8601, UTC); follow the feed’s order rather than sorting by it
events[].type "recording.ready" Yes recording.ready: the meeting’s Lobbe was made for the first time and its bundle can be read; a later regeneration is recording.updated with regenerated, never a second recording.ready
events[].data object Yes The meeting’s status as the change left it
events[].data.status "QUEUED" | "TRANSCRIBING" | "NAMING" | "GENERATING" | "READY" | "FAILED" Yes Where the meeting is: QUEUED, TRANSCRIBING, NAMING (waiting for the speakers’ names), GENERATING (the Lobbe is being made), then READY; or FAILED
events[] (type: "recording.failed") object A meeting failed
events[].id string Yes The event’s own id, the same on every read: use it to skip an event you already handled. It is not a cursor (page with nextCursor)
events[].recordingId string Yes The id of the meeting it is about
events[].seriesId string | null Yes The series the meeting was in when the change happened; null when it was in none, or while series are switched off
events[].occurredAt string Yes When the change happened (ISO 8601, UTC); follow the feed’s order rather than sorting by it
events[].type "recording.failed" Yes recording.failed: the meeting failed for good; a failure Lobbe still retries on its own is never sent. After retryRecording the meeting moves on with no event of its own, and its next event follows
events[].data object Yes The meeting’s status and why it failed
events[].data.status "QUEUED" | "TRANSCRIBING" | "NAMING" | "GENERATING" | "READY" | "FAILED" Yes Where the meeting is: QUEUED, TRANSCRIBING, NAMING (waiting for the speakers’ names), GENERATING (the Lobbe is being made), then READY; or FAILED
events[].data.error object Yes Why the meeting failed
events[].data.error.code string Yes The failure’s code, e.g. NO_SPEECH or AUDIO_CORRUPT
events[].data.error.retryable boolean Yes Whether retryRecording can help: false for a meeting with no speech or damaged audio
events[] (type: "recording.updated") object A meeting changed: a finished one, or a deleted one that came back
events[].id string Yes The event’s own id, the same on every read: use it to skip an event you already handled. It is not a cursor (page with nextCursor)
events[].recordingId string Yes The id of the meeting it is about
events[].seriesId string | null Yes The series the meeting was in when the change happened; null when it was in none, or while series are switched off
events[].occurredAt string Yes When the change happened (ISO 8601, UTC); follow the feed’s order rather than sorting by it
events[].type "recording.updated" Yes recording.updated: a READY meeting changed, and data.change says how; an edit to a meeting still in progress is carried by its recording.ready. The exception is restored, which follows a recording.deleted: the meeting came back at the status it had, so its data.status can be any status
events[].data object Yes The meeting’s status and the kind of change
events[].data.status "QUEUED" | "TRANSCRIBING" | "NAMING" | "GENERATING" | "READY" | "FAILED" Yes Where the meeting is: QUEUED, TRANSCRIBING, NAMING (waiting for the speakers’ names), GENERATING (the Lobbe is being made), then READY; or FAILED
events[].data.change "regenerated" | "renamed" | "transcript_edited" | "speakers_renamed" | "series_changed" | "restored" Yes What kind of change, never the change itself: regenerated (the Lobbe was made again), renamed (the title changed), transcript_edited (the owner corrected the transcript), speakers_renamed (a speaker’s name changed), series_changed (the meeting moved into, out of or between series) or restored (a deleted meeting is back)
events[] (type: "recording.deleted") object A meeting was deleted
events[].id string Yes The event’s own id, the same on every read: use it to skip an event you already handled. It is not a cursor (page with nextCursor)
events[].recordingId string Yes The id of the meeting it is about
events[].seriesId string | null Yes The series the meeting was in when the change happened; null when it was in none, or while series are switched off
events[].occurredAt string Yes When the change happened (ISO 8601, UTC); follow the feed’s order rather than sorting by it
events[].type "recording.deleted" Yes recording.deleted: the meeting was deleted, at any status; its bundle answers 404 from then on, unless it is restored
events[].data object Yes The meeting’s status as the change left it
events[].data.status "QUEUED" | "TRANSCRIBING" | "NAMING" | "GENERATING" | "READY" | "FAILED" Yes Where the meeting is: QUEUED, TRANSCRIBING, NAMING (waiting for the speakers’ names), GENERATING (the Lobbe is being made), then READY; or FAILED
nextCursor string Yes Always set: pass it back as after for what happens next. A page that has caught up gets a cursor at now, so polling an account with nothing new never ages into 410

Errors answer { error: { code, message, details? } }, and code is the contract: see Errors.