Skip to content

Errors

An error answers with a JSON body like this one:

{
"error": {
"code": "TOKEN_DAILY_CAP",
"message": "This token's daily minute cap is reached",
"details": { "capMinutes": 60, "usedMinutes": 55, "requiredMinutes": 12 }
}
}
  • code is the contract. Build your logic on it.

  • message is for people. Log it or show it, but never match on it: it may change. The 500 for an unexpected failure, INTERNAL_ERROR, carries code alone.

  • details comes with a few codes only, and holds numbers you can act on:

    Code details
    402 INSUFFICIENT_MINUTES requiredMinutes, and balanceMinutes for a token holding account:read
    429 TOKEN_DAILY_CAP capMinutes, usedMinutes, requiredMinutes
    409 PRICE_ABOVE_MAX minutes, maxMinutes
    409 NOT_READY (the bundle) status, beside error rather than inside it
  • The HTTP status alone isn’t enough. Several codes share one status: many different refusals are a 409.

  • A path under /api/ that isn’t an API route answers a plain-text 404 Not Found, not this JSON. Check the path against the reference.

GET /recordings/{id}/bundle on a meeting that isn’t READY puts details beside error, not inside it:

{
"error": { "code": "NOT_READY", "message": "The meeting is not ready yet" },
"details": { "status": "TRANSCRIBING" }
}

This answer is older than the rule, and moving details would break the scripts that read it, so it stays: read details.status at the top level here. It says where the meeting is: wait for READY, unless it is FAILED, in which case see FAILED and retry.

details.requiredMinutes is always there. details.balanceMinutes comes only to a token holding account:read: a token without it is never told the balance. What that balance counts is in Minutes, caps and limits.

Both are 403.

  • TOKEN_SCOPE: the token holds none of the scopes this route needs, and never will, since a token’s scopes are fixed when it is made. Don’t retry: the owner makes a token with that scope.
  • SCOPE_DISABLED: the token holds the scope, but Lobbe has switched that kind of access off for now. The token is fine: try again later.

A token without the scope always gets TOKEN_SCOPE, switch or no switch. So SCOPE_DISABLED always means the token has what it needs and only has to wait.

  • TOKEN_INVALID (401): the token itself is no good. It is unknown, revoked or expired, one code for all three, and the answer never says which. Don’t retry: the owner makes a new token in Connections.
  • DEVELOPER_MODE_OFF (403): the token is fine, but its owner has turned Developer mode off, which pauses every token of the account. Nothing is revoked: once it is back on, the same token works again. Don’t treat it as a bad token, and don’t retry it in a loop. Tell the person to turn Developer mode back on: in the app, Account, under Developers.

A revoked or expired token answers TOKEN_INVALID either way: the token is checked before the mode.

The table lists every code, its HTTP status, what it means and what to do next. It starts with the checks every token request goes through, in the order Lobbe makes them.

The last column says what your tool does next:

  • Don’t repeat it: the same request won’t work later on its own. Something has to change first, often on the person’s side.
  • Wait for Retry-After: wait the seconds it gives, then send the same request.
  • Change the request: the request itself is wrong, and message usually says how.
  • Try again later: the request is fine. Something on Lobbe’s side, or a switch, is in the way for now.

When you send a request again, send it with the same Idempotency-Key: see Idempotency and retries.

Code HTTP status What it means Next step
UNAUTHORIZED 401 No token came with the request (a missing Authorization header, or one that isn’t Bearer lobbe_…, reads as a signed-out caller): send Authorization: Bearer lobbe_…. Change the request
TOKEN_NOT_ACCEPTED 401 This route doesn’t take API tokens: call only the routes in the API reference. Change the request
TOKENS_DISABLED 401 Lobbe has switched API tokens off for everyone for now, and your token is kept: try again later. Try again later
TOKEN_INVALID 401 The token is unknown, revoked or expired, and the answer never says which: don’t retry it; the owner makes a new token in Connections. Don’t repeat it
DEVELOPER_MODE_OFF 403 The token is fine, but its owner has turned Developer mode off in the app’s settings (Developers), which pauses every token of the account until they turn it back on: don’t treat it as a bad or revoked token and don’t retry in a loop; tell the person to turn Developer mode on. Don’t repeat it
RATE_LIMITED 429 Too many requests came in a short time, from this token or from your IP address: wait the seconds Retry-After gives, then send again. Wait for Retry-After
TOKEN_SCOPE 403 This token doesn’t hold the scope this route needs: don’t retry it; the owner makes a token that has it. Don’t repeat it
SCOPE_DISABLED 403 The token holds the scope, but Lobbe has switched that kind of access off for now: try again later. Try again later
PENDING_APPROVAL 403 The owner’s account is still waiting for approval, so it can’t be used yet: try again once it is approved. Try again later
SCOPE_UNAVAILABLE 400 The app won’t make a token with a scope that is switched off for now: pick from the scopes the create screen offers, and make another token once the rest are on. Try again later
TOKEN_REQUIRED 400 whoami describes an API token, and this request came from a signed-in browser instead: call it with Authorization: Bearer lobbe_…. Change the request
VALIDATION 400 The request is malformed (a field, parameter or header is missing, unknown or out of range), and message says which: fix it before sending again. Change the request
NOT_FOUND 404 Nothing this token can reach has that id (unknown, deleted, someone else’s or out of the token’s reach all look the same): don’t retry the same id. Don’t repeat it
INTERNAL 500 Lobbe couldn’t finish a step on its side (storing the audio, or saving an answer): try again later, and with the same Idempotency-Key a retry is never charged twice. Try again later
INTERNAL_ERROR 500 Something unexpected failed on Lobbe’s side: try again later, and with the same Idempotency-Key a retry is never charged twice. Try again later
INVALID_AUDIO 400 The file isn’t audio Lobbe can read: send it in another format, or from another export. Change the request
AUDIO_INCOMPLETE 400 The audio file is cut short (an MP4-family file whose end is missing, usually a copy or upload that stopped early): send the complete file. Change the request
UPLOAD_TOO_LARGE 413 The file is larger than the upload limit, which whoami gives as limits.maxUploadMb: send a smaller file. Change the request
RECORDING_TOO_LONG 413 The audio is longer than one meeting may be, which whoami gives as limits.maxRecordingMinutes: split it and send the parts. Change the request
VIDEO_UPLOAD_DISABLED 409 Video upload is switched off: send the meeting’s audio instead. Change the request
VIDEO_UNAVAILABLE 503 Lobbe can’t take the audio out of a video right now: try again later, or send the audio itself. Try again later
VIDEO_NO_AUDIO 400 The video has no audio track, so there is nothing to transcribe: send a file with sound. Change the request
VIDEO_UNREADABLE 400 The video can’t be read: send it in another format, or send its audio. Change the request
ATTACHMENT_TYPE 400 The attachment isn’t a PDF, PPTX or DOCX file: send one of those, or no attachment. Change the request
ATTACHMENT_TOO_LARGE 413 The attachment is larger than 10 MB: send a smaller file. Change the request
DAILY_LIMIT_REACHED 429 The owner has reached Lobbe’s own daily limit (on meetings, or on Asks over the last 24 hours), which no token raises: try again later, after Retry-After when it is sent. Try again later
INSUFFICIENT_MINUTES 402 The owner’s balance is short of what this costs: details.requiredMinutes says how many minutes it needs, plus details.balanceMinutes only for a token holding account:read; don’t retry until the owner buys minutes. Don’t repeat it
TOKEN_DAILY_CAP 429 This would take the token past its daily minute cap (details gives capMinutes, usedMinutes and requiredMinutes): wait for Retry-After; when it is absent, waiting can’t help and the owner raises the cap in Connections. Wait for Retry-After
IDEMPOTENCY_KEY_IN_USE 409 Another token of this account, or the app, already used this Idempotency-Key, and a key is the owner’s for good (across the account for a meeting, on that meeting or series for an Ask): send a new random key, never a hash of the file. Change the request
UPLOAD_IN_PROGRESS 503 An earlier request with this Idempotency-Key is still storing its audio: wait for Retry-After and send the same request again, which then answers with that meeting. Wait for Retry-After
NOT_NAMING 409 The meeting isn’t waiting at the speaker-naming step (it is already past it, or hasn’t reached it): read its status instead of skipping again. Don’t repeat it
NOT_FAILED 409 Only a failed meeting can be retried, and this one hasn’t failed: read its status instead. Don’t repeat it
NOT_READY 409 The meeting isn’t ready yet; on the bundle, details sits beside error, not inside it, and details.status says where the meeting is: poll its status and read the bundle once it is READY. Try again later
ASK_DISABLED 409 Ask is switched off in Lobbe for now: try again later. Try again later
ASK_NOT_READY 409 The meeting has no Lobbe yet, so there is nothing to ask: wait until its status is READY. Try again later
PRICE_ABOVE_MAX 409 The answer would cost more than your maxMinutes (details gives minutes and maxMinutes), and nothing was charged: raise maxMinutes, or don’t ask. Change the request
SERIES_ASK_TOO_FEW 409 A series needs at least 2 finished meetings to ask across: try again once it has them. Try again later
GENERATE_FAILED 502 The model couldn’t answer this time, and nothing was charged: try again later with the same Idempotency-Key. Try again later
SERIES_LIMIT 409 The owner already has 50 series, the most one account may have: don’t retry; the owner deletes one in the app first. Don’t repeat it
SERIES_NAME_TAKEN 409 The owner already has a series with this name (capitals don’t make a name different): choose another name. Change the request
MEMORY_DISABLED 409 Memory is switched off in Lobbe, so a note can’t be edited or deleted (reading answers an empty list): try again later. Try again later
MEMORY_DUPLICATE 409 The owner already has this note in the same category: edit or delete that one instead. Change the request
CURSOR_EXPIRED 410 The cursor is older than the 30 days the feed keeps, or comes from before a restore of Lobbe’s data: take a new cursor with after=latest first, then catch up from listReadyRecordings, then read on from that new cursor. Change the request