Errors
Every refusal has the same shape and a stable code. Program against the code, never against the message.
code is machine-readable and will not change within a version. message is for a human and may be reworded at any time. details carries context that differs per code and is useful while debugging, but it is not a contract to branch on. request_id also comes back as the X-Request-Id header; quote it in a support request and we can find the exact call.
{
"error": {
"code": "INVALID_SHARED_WITH",
"message": "shared_with only accepts members who can sign in: emp_4b2a91",
"request_id": "baa58c77-4b95-434d-bdbb-4ac3d04ac03b",
"details": {
"invalid": ["emp_4b2a91"]
}
}
}Two responses do not carry this envelope
A
429 is refused at the edge before it reaches the API. And the PUT that uploads audio goes straight to storage, so a rejected signature comes back as XML. Everything else, without exception, is the shape above.A broken request beats a missing scope
Validation runs before the scope check, so an invalid body plus a missing scope answers
400 INVALID_REQUEST and not 403 INSUFFICIENT_SCOPE. Do not conclude from a 400 that the key is fine.Every code
32 codes, grouped by the status they arrive with.
400Something about the request is wrong
BAD_REQUEST- The request was refused and no more specific code applies.
INVALID_CURSOR- `cursor` was not produced by a previous page of this list.
INVALID_DATE- A date is not a calendar date in YYYY-MM-DD form.
INVALID_DATE_RANGE- `date_from` lies after `date_to`.
INVALID_EMAIL- The email address is not a valid address.
INVALID_EXTERNAL_ID- `external_id` is empty or longer than allowed.
INVALID_LIMIT- `limit` is not a whole number within the allowed range.
INVALID_REQUEST- The request body or the combination of query parameters is not valid. `details.fields` names the offending fields where the body is at fault.
INVALID_SHARED_WITH- `shared_with` names members who cannot be shared with, because they have no account or are an integration. `details.invalid` lists them.
INVALID_TIME- `time` is not a time of day in HH:MM form.
401The key did not authenticate
UNAUTHENTICATED- The Authorization header is missing, malformed, or the key is unknown, expired or revoked.
402Quota is spent
QUOTA_EXHAUSTED- The organisation's quota for this period is spent. `details.next_reset_at` says when it replenishes.
TRANSCRIBE_QUOTA_EXHAUSTED- Not enough transcription credit left for this recording. `details.next_reset_at` says when the quota replenishes.
403Authenticated, but not allowed
API_ACCESS_DISABLED- The organisation does not have API access, or the integration behind this key is no longer active.
FORBIDDEN- The action is not allowed for this caller.
INSUFFICIENT_SCOPE- The key is valid but does not carry the scope this endpoint requires.
IP_NOT_ALLOWED- The key has an IP allowlist and this caller's address is not on it.
ORGANISATION_EXPIRED- The organisation's access has expired.
ORGANISATION_SUSPENDED- The organisation is blocked.
PERSONAL_API_KEYS_DISABLED- The organisation does not have personal API keys enabled, so this personal key cannot be used.
404Absent, or invisible to this integration
NOT_FOUND- No such resource, or it is not visible to this integration. A private meeting of another member is answered as absent rather than as forbidden, so its existence is not revealed.
409The resource is not in a state that allows this
AUDIO_ALREADY_PRESENT- This meeting already has audio. A recording is uploaded once; create a new meeting to start over.
CONFLICT- The resource is not in a state that allows this action.
EMAIL_TAKEN- Another member already uses this address. `details` names the member that holds it.
EXTERNAL_ID_TAKEN- Another meeting in this organisation already carries this `external_id`.
MEMBER_LIMIT_EXCEEDED- The organisation has reached the maximum number of member records.
MINUTES_NOT_READY- The minutes have not been generated yet. Poll the meeting until its status says so.
NOT_READY- The content is not available yet. Try again later.
PARTICIPANTS_LOCKED- Participants steer transcription, so they can only be changed while the meeting has no audio yet.
TRANSCRIPT_NOT_READY- Transcription has not finished. Poll the meeting until its status says so.
VOCABULARY_FULL- The vocabulary already holds the maximum number of terms.
500Ours to fix
INTERNAL_ERROR- Something went wrong on our side. The response carries a `request_id`; quote it in a support ticket.