Skip to content

Errors

Teler reports errors at three layers. This page documents all three.

LayerWhereWhat you see
HTTP APIDirect calls and SDK-mediated callsStatus code + JSON body
SDKInside your codeTyped exception
Call lifecyclecall.failed webhookfailure.code and failure.reason

Every response carries a standard HTTP status code and a JSON error body. The error body always has the same shape: a success flag and a message.

HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"success": false,
"message": "from_number is required"
}
StatusMeaningCommon cause
200OKRequest succeeded.
202AcceptedRequest accepted for async processing (e.g. call initiated, or a call-control mutation).
400Bad RequestMissing or malformed parameter.
403ForbiddenInvalid or revoked API key.
404Not FoundThe requested resource doesn’t exist or isn’t visible to your account.
409ConflictResource state conflicts with the request.
410GoneThe target call is no longer owned by this node (call-control only).
422UnprocessableValidation failed (including a missing X-API-Key header). See below.
500Server ErrorUnexpected server-side failure. Retry with backoff.
502 / 503 / 504Upstream failureTransient; retry with backoff.

Both SDKs share the same exception hierarchy. TelerException is the base class (default code 500); the others are:

ExceptionCodeMeaning
TelerException500Base class; catch-all for server/transport errors. Retry with backoff.
BadParametersException400Invalid input (carries .param). Fix the input.
UnauthorizedException401Client-side auth error.
ForbiddenException403Forbidden — this is what a server-returned 403 (invalid API key) maps to.
NotImplementedException501Feature unsupported (raised client-side, e.g. unidirectional streams).

A server-returned 403 maps to ForbiddenException. Note that NotImplementedException is raised by the SDK itself — the API never returns a 501.

See SDK errors for try/catch patterns in both languages.

When a call cannot be completed, Teler delivers a call.failed webhook with a failure object:

{
"failure": {
"code": 487,
"reason": "request_terminated"
}
}

failure.code and failure.reason are SIP response codes surfaced on the webhook — they are not HTTP status codes and are unrelated to the API response table above. The most common codes you’ll encounter:

CodeReasonWhat happened
404not_foundThe dialed number doesn’t exist or isn’t routable.
408request_timeoutThe far end didn’t respond in time.
480temporarily_unavailableThe callee was unreachable (e.g. phone off).
486busy_hereThe callee was on another call.
487request_terminatedThe call was cancelled before being answered.
500server_internal_errorInternal Teler error: retry, then escalate.
503service_unavailableCarrier capacity issue: retry.
603declineThe callee actively rejected the call.

422 Unprocessable Entity responses carry an errors array (the FastAPI validation format), naming each offending input:

{
"success": false,
"message": "Validation Error",
"errors": [
{
"loc": ["body", "from_number"],
"msg": "field required",
"type": "value_error.missing"
}
]
}

A simpler 400 Bad Request (with just success and message) is returned for input that fails a semantic check rather than schema validation. In the Python SDK a 400 surfaces as BadParametersException (exposing .param); in Node, err.param exposes the same value.

SymptomLikely cause
403 on every requestWrong or revoked key, or X-API-Key header dropped by a proxy
422 on every requestThe X-API-Key header is missing entirely
400 on flow_urlURL is missing, not HTTPS, or unreachable
call.failed code=487Caller hung up before the callee answered
call.failed code=486Callee is busy; implement a retry-after-delay
call.failed with no answered_atCall never connected; that field is conditional