Skip to content

Quickstart: send a meeting

This page takes one meeting through Lobbe with curl: you make a token, send the audio, follow its status, hand over the speakers’ names and read the Lobbe. It takes a few minutes, most of them waiting.

You make tokens in the Lobbe app, and they work only while developer mode is on.

  1. In the app, open Account. Under Developers, turn on Developer mode. It is off by default; once it is on, Connections appears below it.

  2. Open Connections and tap Create token, or go straight to app.lobbe.ai/connections/tokens/new.

  3. Name the token. Under Meetings, tick Send meetings and keep Read, which is ticked already. Pick when it expires, then tap Create token.

  4. The token is shown once. Copy it and keep it in an environment variable:

    Terminal window
    export LOBBE_TOKEN=lobbe_…

If the form doesn’t offer Send meetings, sending meetings through a token isn’t on for your account yet. The read-only version at the end of this page works with Read alone.

Terminal window
curl https://app.lobbe.ai/api/v1/whoami \
-H "Authorization: Bearer $LOBBE_TOKEN"

The answer says who the token belongs to and what it may do:

{
"schemaVersion": 1,
"owner": { "type": "user", "id": "USER_ID", "displayName": "Sara" },
"token": {
"id": "TOKEN_ID",
"name": "n8n office",
"scopes": ["recordings:read", "recordings:write"],
"dailyMinuteCap": null,
"usedMinutes24h": 0,
"expiresAt": "2027-01-17T09:12:00.000Z"
},
"wallet": null,
"limits": { "maxUploadMb": 300, "maxRecordingMinutes": 240 }
}

wallet is null unless the token holds account:read. limits is the largest file and the longest meeting Lobbe takes right now: see Minutes, caps and limits. Every field is in GET /whoami.

If this answers 401 or 403, error.code names the problem. 403 DEVELOPER_MODE_OFF means developer mode is off. Errors lists every code.

Terminal window
curl https://app.lobbe.ai/api/v1/recordings \
-H "Authorization: Bearer $LOBBE_TOKEN" \
-F "audio=@meeting.m4a;type=audio/mp4"

The body is multipart/form-data, with the file in audio and its type after ;type=. Lobbe answers 202:

{
"schemaVersion": 1,
"recording": {
"id": "MEETING_ID",
"status": "QUEUED",
"minutes": 42,
"recordedAt": "2026-10-19T08:30:00.000Z",
"statusUrl": "https://app.lobbe.ai/api/v1/recordings/MEETING_ID/status",
"bundleUrl": null,
"url": "https://app.lobbe.ai/m/MEETING_ID"
}
}

Keep id. minutes is what the meeting costs, from your balance. The other fields you can send (when the meeting happened, a title, a series, the kind of recording, the Lobbe’s language, naming) are in POST /recordings. To send the request again safely, without making a second meeting, add an Idempotency-Key header: see Idempotency and retries.

Without ;type=, curl labels the file application/octet-stream. Lobbe recognizes most audio files from their first bytes anyway, but not all: 400 VALIDATION with the message Unsupported audio type means Lobbe couldn’t tell what the file is, so name its type. The accepted files and their types are listed in Minutes, caps and limits.

Ask for the status about once a minute:

Terminal window
curl https://app.lobbe.ai/api/v1/recordings/MEETING_ID/status \
-H "Authorization: Bearer $LOBBE_TOKEN"

status moves through these values, in this order:

status What is happening
QUEUED Lobbe has the audio, and the meeting is waiting its turn
TRANSCRIBING The audio is being transcribed
NAMING Waiting for the speakers’ names. Not every meeting stops here
GENERATING The Lobbe is being written
READY Done: read it
FAILED It stopped. error.code says why, and error.retryable says whether POST /recordings/{id}/retry can help

FAILED isn’t always the end: Lobbe retries a failed step by itself after a short wait, so a status read can catch a FAILED that then moves on. The loop below waits until there is something to do. At FAILED with error.retryable set to true, it retries the meeting and keeps waiting, up to three times; at a FAILED that can’t recover, or on an error, it stops and prints the answer (it needs jq, and curl 7.76 or later for --fail-with-body):

Terminal window
retries=0
while true; do
body=$(curl -sS --fail-with-body https://app.lobbe.ai/api/v1/recordings/MEETING_ID/status \
-H "Authorization: Bearer $LOBBE_TOKEN") || { echo "$body"; break; }
status=$(jq -r .status <<<"$body")
echo "$status"
case "$status" in NAMING | READY) break ;; esac
if [ "$status" = FAILED ]; then
if [ "$(jq -r .error.retryable <<<"$body")" != true ] || [ "$retries" -ge 3 ]; then
echo "$body"
break
fi
retries=$((retries + 1))
# 409 NOT_FAILED: it recovered by itself in the meantime. Keep waiting either way.
body=$(curl -sS --fail-with-body -X POST \
https://app.lobbe.ai/api/v1/recordings/MEETING_ID/retry \
-H "Authorization: Bearer $LOBBE_TOKEN") ||
[ "$(jq -r .error.code <<<"$body" 2>/dev/null)" = NOT_FAILED ] || { echo "$body"; break; }
fi
sleep 60
done

The retry is safe while Lobbe is still retrying by itself: it never starts a second run, and it costs nothing more. See FAILED and retry.

Following many meetings? Read the events feed, GET /events, instead of asking for each meeting’s status.

At NAMING, the status carries naming:

{
"schemaVersion": 1,
"id": "MEETING_ID",
"status": "NAMING",
"title": null,
"error": null,
"naming": {
"url": "https://app.lobbe.ai/m/MEETING_ID?name=speakers",
"deadline": "2026-10-20T08:45:00.000Z"
},
"bundleUrl": null,
"url": "https://app.lobbe.ai/m/MEETING_ID"
}

You have two choices:

  • Hand naming.url to the person. It opens the meeting’s speaker naming in the app, for the account’s owner only, signed in. So it is safe to send in a chat or an email.

  • Skip naming:

    Terminal window
    curl https://app.lobbe.ai/api/v1/recordings/MEETING_ID/naming \
    -H "Authorization: Bearer $LOBBE_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{ "action": "skip" }'

    Unnamed voices take Lobbe’s suggestions, and the Lobbe is made. The answer is 200 with the meeting’s status. A meeting that isn’t at NAMING answers 409 NOT_NAMING.

If neither happens, Lobbe goes ahead without names from naming.deadline on. When it is null, Lobbe waits for you. To never stop at naming, send -F naming=skip with the meeting.

At READY:

Terminal window
curl "https://app.lobbe.ai/api/v1/recordings/MEETING_ID/bundle?format=markdown" \
-H "Authorization: Bearer $LOBBE_TOKEN"

The answer is one Markdown document: the title, the meeting’s details, the Lobbe’s sections and the transcript. Without ?format=markdown you get the same bundle as JSON; its fields are in GET /recordings/{id}/bundle. Reading a bundle needs recordings:read.

A token with Read alone can’t send meetings, but it reads your finished meetings:

Terminal window
export LOBBE_TOKEN=lobbe_…
# Check the token
curl https://app.lobbe.ai/api/v1/whoami \
-H "Authorization: Bearer $LOBBE_TOKEN"
# Your finished meetings, newest first
curl https://app.lobbe.ai/api/v1/recordings/ready \
-H "Authorization: Bearer $LOBBE_TOKEN"
# One whole meeting, as Markdown
curl "https://app.lobbe.ai/api/v1/recordings/MEETING_ID/bundle?format=markdown" \
-H "Authorization: Bearer $LOBBE_TOKEN"