Skip to content

Search and Ask

Two scopes open these routes:

  • recordings:query (Meetings, Search and ask): search your meetings, and ask one meeting a question.
  • series:query (Series, Ask a series): ask a whole series a question.

Searching is free, and so is asking what a question will cost. Each answer spends minutes.

GET /recordings/search finds finished meetings by their words:

Terminal window
curl -G https://app.lobbe.ai/api/v1/recordings/search \
-H "Authorization: Bearer $LOBBE_TOKEN" \
--data-urlencode "q=launch budget" \
--data-urlencode "from=2026-10-01T00:00:00+03:30"

-G with --data-urlencode puts the parameters in the address, encoded, so a Persian q works as it is.

  • Every word of q must appear somewhere in the meeting: its title, its transcript or its Lobbe. A word also matches inside a longer word.
  • Small differences don’t count. Capitals, diacritics and the half-space are ignored, Arabic letter forms (ي, ك) match Persian ones, and Persian digits match Latin ones.
  • q is required, 1 to 200 characters. A q with no word in it, only spaces for example, answers 400 VALIDATION.
  • Without seriesId: your own finished meetings, the ones in READY.
  • With seriesId: the finished meetings of that series, a series you joined included. A series you can’t read answers 404.
Parameter What it does
seriesId Only the meetings of this series
kind Only meetings of this kind: MEETING, LECTURE, INTERVIEW, VOICE_MEMO or CALL
from, to Only meetings that happened in this window (recordedAt, both ends included), ISO 8601 with an offset
limit How many meetings per page, 1–50 (20 by default)
cursor The nextCursor of the previous page, passed back as it is
  • Any other parameter answers 400 VALIDATION, so a typo never turns into a filter that silently does nothing.
  • The newest meeting comes first, by when it happened (recordedAt). This is not the order of GET /recordings/ready, which follows when Lobbe received each meeting. See The meeting time.
  • nextCursor is null on the last page.
{
"schemaVersion": 1,
"items": [
{
"id": "MEETING_ID",
"title": "Weekly product sync",
"kind": "MEETING",
"createdAt": "2026-10-19T08:31:12.000Z",
"recordedAt": "2026-10-19T07:00:00.000Z",
"durationSeconds": 2520,
"url": "https://app.lobbe.ai/m/MEETING_ID",
"bundleUrl": "https://app.lobbe.ai/api/v1/recordings/MEETING_ID/bundle",
"series": { "id": "SERIES_ID", "name": "Product sync" },
"displayTitle": "Weekly product sync",
"snippet": "…so the launch budget stays where it is until the payment fix ships…"
}
],
"nextCursor": null
}

Each item is an item of the list of finished meetings, plus snippet: up to 200 characters around the first match, from the transcript, or from the Lobbe when only the Lobbe matched. It is null when the words were found in the title alone.

  • A token with recordings:query and no recordings:read has no list and no bundles. Each item still carries bundleUrl, but fetching it needs recordings:read.
  • Search is not a way to hide meetings from such a token: a short q matches nearly every meeting, so it can find any of your finished meetings, and then ask it.
  • Search spends the token’s search budget, shared with the Ask quotes: its size is in Rate limits.

Asking is two steps: get the price, then ask with that price as your ceiling.

Terminal window
curl https://app.lobbe.ai/api/v1/recordings/MEETING_ID/ask/quote \
-H "Authorization: Bearer $LOBBE_TOKEN"
{ "schemaVersion": 1, "minutes": 3 }

GET /recordings/{id}/ask/quote is free. The price depends on the meeting, not on the question: it comes from the length of the transcript as Lobbe reads it, the speakers’ names included. So one quote holds for every question to that meeting, until its transcript is edited or a speaker is named or renamed.

Terminal window
key=$(uuidgen) # one key for this question, kept for every retry of it
curl https://app.lobbe.ai/api/v1/recordings/MEETING_ID/ask \
-H "Authorization: Bearer $LOBBE_TOKEN" \
-H "Idempotency-Key: $key" \
-H "Content-Type: application/json" \
-d '{ "question": "What did we decide about the launch date?", "maxMinutes": 3 }'
  • question is 1 to 500 characters, after spaces at either end are trimmed.
  • maxMinutes is optional: the most you agree to pay. Without it, the Ask charges whatever the price is. With it, a higher price answers 409 PRICE_ABOVE_MAX, with details.minutes (the price) and details.maxMinutes, and nothing is charged. Send the quote’s minutes: then a price that changed since the quote can never charge you more than you saw.
  • Idempotency-Key makes a retry safe: the same key gets the first answer back, never a second charge. See Idempotency and retries.

POST /recordings/{id}/ask answers 200:

{
"schemaVersion": 1,
"answer": "The launch moves to 2 November [1], once the payment fix has been tested [2].",
"citations": [
{ "startMs": 754000, "speaker": "speaker_1" },
{ "startMs": 812500, "speaker": "speaker_0" }
],
"minutes": 3,
"refused": false
}

minutes is what this answer charged.

  • [n] in answer marks the claim that citations[n - 1] supports. The markers are numbered 1, 2, 3… in reading order, and citations lists the turns in the order the answer first cites them. A group such as [1][2] cites two turns.
  • A meeting’s answer cites at most 3 turns. An answer can cite none, and then has no markers: a question about how long the meeting was, say, is answered from its measured facts.
  • Each citation is a turn of the transcript. startMs is when the turn starts, in milliseconds from the start of the audio. speaker is the voice’s label as transcribed (speaker_0), never the name someone gave it.
  • To show a cited turn, find the segment in the meeting’s bundle whose startMs is the same. Take who spoke from that segment’s speaker, which the bundle has already matched to a person in transcript.speakers, with their name. This needs recordings:read.
  • Lobbe checks the citations. A citation that points at no real turn is dropped, and an answer whose every citation is invented is not given at all: it answers 502 GENERATE_FAILED, and nothing is charged.

When the meeting doesn’t answer the question, refused is true and answer says why. A refusal is charged, like any answer: Lobbe had to read the whole meeting to know.

  • It is your Ask. It shows in the meeting’s Ask tab in the app. Lobbe also reads the latest questions and answers on the meeting as context for the next one, whether they were asked in the app or through a token.
  • Which meetings: your own, and those of a series you joined. A meeting that isn’t READY answers 409 ASK_NOT_READY, and one you can’t reach answers 404.
  • Spending: the price comes from your balance (402 INSUFFICIENT_MINUTES when it is short) and counts toward the token’s daily cap (429 TOKEN_DAILY_CAP). Lobbe’s own daily limit on Asks, one limit for meeting and series Asks together, answers 429 DAILY_LIMIT_REACHED with Retry-After. See Minutes, caps and limits.
  • Budget: the Asks share the token’s ask budget: its size is in Rate limits.
  • While Ask is switched off in Lobbe, an Ask or a quote answers 409 ASK_DISABLED: try again later.

With series:query, one question reads every finished meeting of a series: one you own, or one you joined.

Terminal window
curl https://app.lobbe.ai/api/v1/series/SERIES_ID/ask/quote \
-H "Authorization: Bearer $LOBBE_TOKEN"
{ "schemaVersion": 1, "minutes": 9, "meetingCount": 6 }

Then ask as you would a meeting, with the same body and an Idempotency-Key:

Terminal window
key=$(uuidgen)
curl https://app.lobbe.ai/api/v1/series/SERIES_ID/ask \
-H "Authorization: Bearer $LOBBE_TOKEN" \
-H "Idempotency-Key: $key" \
-H "Content-Type: application/json" \
-d '{ "question": "Which action items are still open?", "maxMinutes": 9 }'
{
"schemaVersion": 1,
"answer": "Two are still open: the pricing page copy [1] and the Android release notes [2].",
"citations": [
{ "recordingId": "MEETING_ID", "startMs": 1203000, "speaker": "speaker_2" },
{ "recordingId": "MEETING_ID_2", "startMs": 98000, "speaker": "speaker_0" }
],
"minutes": 9,
"refused": false
}
  • What it reads: GET /series/{id}/ask/quote gives the price and meetingCount, how many finished meetings the question reads. It reads every one’s Lobbe, then as many full transcripts as fit, newest first.
  • Too few meetings: a series needs at least 2 finished meetings. With fewer, the quote and the Ask both answer 409 SERIES_ASK_TOO_FEW. With one, ask that meeting instead.
  • Citations name a meeting too: each carries recordingId beside startMs and speaker, and an answer cites at most 5 turns, from any of the series’ meetings. To show one, read that meeting’s bundle.
  • Footnotes, refusals, maxMinutes, the price, the balance, the caps and the key work as for a meeting, through POST /series/{id}/ask. The price comes from the series’ meetings, so it changes as meetings are added or change.
  • It is your Ask, in the series’ Ask in the app. A member who asks pays from their own balance, never the series’ owner.
  • A series you can’t reach answers 404, and so does every series while series are switched off. While Ask is switched off, the Ask answers 409 ASK_DISABLED and the quote answers 404.