API v2 errors

Every endpoint under https://api.emaktalk.com/api/v2 (Call History, Me) answers errors as described here.

Every error answers one shape:

{
  "error": {
    "type": "invalid_request",
    "code": "parameter_invalid",
    "message": "from must be a date or an instant with a zone.",
    "param": "from"
  },
  "request_id": "a4a2b7164eebaace"
}
  • code is the precise case: branch on it. New codes may be added; an existing code never changes meaning.
  • type groups the codes for generic handling. Each code has one HTTP status, usually its type's default.
  • param names the parameter at fault, when there is one.
  • retry_after_sec is on rate_limited and unavailable errors: wait that many seconds (also the Retry-After header), then retry.
  • details carries a code's own facts, when it has some.
  • message is for people. Don't parse it.
  • request_id identifies the request. Quote it when you report a problem.
  • A 401 carries WWW-Authenticate: Bearer, with error="invalid_token" when the credentials sent were refused. A 405 carries Allow.

An unknown id, an id in another account and an id you may not see all answer the same not-found code.

Types

typeDefault HTTPMeaning
invalid_request400The request is malformed or can't be answered as sent. Fix it before retrying.
authentication401No valid credentials. Authenticate again; retrying as is won't help.
permission403The caller is authenticated but may not do this.
not_found404Nothing the caller may see answers to this id or path.
conflict409The request conflicts with the resource's current state.
rate_limited429Too many requests. Wait retry_after_sec seconds (also the Retry-After header), then retry.
unavailable503A temporary condition. Wait retry_after_sec seconds (also the Retry-After header), then retry.
internal500An unexpected failure on our side. Report it with the request_id.

Codes

Branch on code. The codes are grouped by type; each takes its type's HTTP status unless its row says otherwise. Each endpoint's reference lists the codes it answers, by response.

invalid_request (400)

codetypeHTTPMeaningdetails
parameter_invalidinvalid_request400A parameter is malformed, out of range, or given more than once. param names it.allowed: The values the parameter accepts, for a closed vocabulary.
parameter_unknowninvalid_request400A parameter this endpoint doesn't take. param names it.allowed: The parameters the endpoint takes.
parameter_missinginvalid_request400A parameter this request needs is absent. param names it.
parameter_conflictinvalid_request400Two parameters that can't be sent together. param names one of them.
request_invalidinvalid_request400The arguments are well-formed, but the request can't be carried out as sent. message says why and what to send instead; the same request won't succeed on retry.
batch_not_supportedinvalid_request400Several protocol messages in one request (a batch). Send one message per request.
request_too_largeinvalid_request413The request body is too large to accept. Send a smaller request.
cursor_invalidinvalid_request400The cursor is malformed, has expired, or was issued for another caller, account or version of the resource. Start again without it.
query_too_broadinvalid_request400The search ran past its time bound. Narrow the date range or add filters; the same request won't succeed on retry.
ambiguousinvalid_request400A name matches several objects. details.candidates lists them; send one by its number or id.candidates: The objects the name matches: { type, id, name, number } each.
answer_too_largeinvalid_request400The answer is too large to return in one response. Ask for less (fewer parts, a smaller page).
method_not_allowedinvalid_request405This path doesn't answer this HTTP method. The Allow header lists the methods it does.

authentication (401)

codetypeHTTPMeaningdetails
credentials_missingauthentication401The request carries no credentials. Send an API key in Authorization: Bearer.
credentials_invalidauthentication401The credentials can't be used as sent: a bearer token that is neither an API key nor an app token, or more than one kind of credentials at once.
key_invalidauthentication401The API key isn't valid.
session_expiredauthentication401The session or app token is invalid or expired. Sign in again.

permission (403)

codetypeHTTPMeaningdetails
forbiddenpermission403The caller may not do this at all, or may not act on the account it named.
content_forbiddenpermission403The caller may see this call record but not its recording, transcript or analyses.

not_found (404)

codetypeHTTPMeaningdetails
call_record_not_foundnot_found404No call record with this id is visible to the caller in this account.
recording_not_foundnot_found404The call record has no recording of that id to hand over. details.state says why when the recording exists but doesn't play.state: The recording's state: pending or deleted.
analysis_not_foundnot_found404The call record has no analysis of this kind visible to the caller.
reference_not_foundnot_found404A well-formed value names nothing in this account (an extension, an account). param names it.
resource_not_foundnot_found404Nothing the caller may see in this account answers to the id, name or number the request asked for. message says what was looked up.
route_not_foundnot_found404No endpoint answers on this path.

conflict (409)

codetypeHTTPMeaningdetails
recording_already_deletedconflict409The recording is already deleted. Restore it with undelete within 30 days of its deletion (the record's purge_at), or leave it.
recording_not_deletedconflict409The recording is not deleted, so there is nothing to restore.
recording_purgedconflict409The recording was deleted permanently: its 30-day restore window has passed (the record's purge_at), or it was deleted outside this API. It can't be restored.
recording_not_deletableconflict409This recording can't be deleted (or, for shared_storage, restored) through this API. Nothing was changed. details.reason says why.reason: legal_hold: the recording is on legal hold; nobody can delete it until the hold is lifted. unsupported_storage: the recording is kept in older storage that this API doesn't play from or delete from. uploading: the recording is still being stored; retry once it plays. shared_storage: deleting and restoring recordings isn't available on this deployment; retrying won't help.
recording_audio_missingconflict409The recording's audio can't be found in storage, so it can't be restored. Nothing was changed; the recording stays deleted.
resource_conflictconflict409The resource changed since it was read, or its current state doesn't allow this. Read it again and act on what you read.
legacy_routing_retiredconflict409This account routes calls only through call flows, so a number's own routing, ring groups, phone menus, business hours and day/night switches can't be created or changed. Nothing was changed. Attach a call flow to the number, or edit its call flow, instead; the same request won't succeed on retry.
flow_requiredconflict409This account routes calls only through call flows, and the change would leave an enabled phone number without one. Nothing was changed. Attach the number to a call flow (message says how); the same request won't succeed on retry.

rate_limited (429)

codetypeHTTPMeaningdetails
rate_limitedrate_limited429Too many requests. Wait retry_after_sec seconds, then retry.

unavailable (503)

codetypeHTTPMeaningdetails
try_againunavailable503A temporary condition. Wait retry_after_sec seconds, then retry the same request.
routing_mode_unavailableunavailable503How this account routes calls can't be checked right now, so a change that depends on it was not made. Nothing was changed. Wait retry_after_sec seconds, then retry the same request.

internal (500)

codetypeHTTPMeaningdetails
internalinternal500An unexpected failure. Report it with the request_id.