Errors
Teler reports errors at three layers. This page documents all three.
| Layer | Where | What you see |
|---|---|---|
| HTTP API | Direct calls and SDK-mediated calls | Status code + JSON body |
| SDK | Inside your code | Typed exception |
| Call lifecycle | call.failed webhook | failure.code and failure.reason |
HTTP responses
Section titled “HTTP responses”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 RequestContent-Type: application/json
{ "success": false, "message": "from_number is required"}| Status | Meaning | Common cause |
|---|---|---|
200 | OK | Request succeeded. |
202 | Accepted | Request accepted for async processing (e.g. call initiated, or a call-control mutation). |
400 | Bad Request | Missing or malformed parameter. |
403 | Forbidden | Invalid or revoked API key. |
404 | Not Found | The requested resource doesn’t exist or isn’t visible to your account. |
409 | Conflict | Resource state conflicts with the request. |
410 | Gone | The target call is no longer owned by this node (call-control only). |
422 | Unprocessable | Validation failed (including a missing X-API-Key header). See below. |
500 | Server Error | Unexpected server-side failure. Retry with backoff. |
502 / 503 / 504 | Upstream failure | Transient; retry with backoff. |
SDK exceptions
Section titled “SDK exceptions”Both SDKs share the same exception hierarchy. TelerException is the base
class (default code 500); the others are:
| Exception | Code | Meaning |
|---|---|---|
TelerException | 500 | Base class; catch-all for server/transport errors. Retry with backoff. |
BadParametersException | 400 | Invalid input (carries .param). Fix the input. |
UnauthorizedException | 401 | Client-side auth error. |
ForbiddenException | 403 | Forbidden — this is what a server-returned 403 (invalid API key) maps to. |
NotImplementedException | 501 | Feature 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.
Call failure codes
Section titled “Call failure codes”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:
| Code | Reason | What happened |
|---|---|---|
404 | not_found | The dialed number doesn’t exist or isn’t routable. |
408 | request_timeout | The far end didn’t respond in time. |
480 | temporarily_unavailable | The callee was unreachable (e.g. phone off). |
486 | busy_here | The callee was on another call. |
487 | request_terminated | The call was cancelled before being answered. |
500 | server_internal_error | Internal Teler error: retry, then escalate. |
503 | service_unavailable | Carrier capacity issue: retry. |
603 | decline | The callee actively rejected the call. |
Validation errors
Section titled “Validation errors”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.
Common pitfalls
Section titled “Common pitfalls”| Symptom | Likely cause |
|---|---|
403 on every request | Wrong or revoked key, or X-API-Key header dropped by a proxy |
422 on every request | The X-API-Key header is missing entirely |
400 on flow_url | URL is missing, not HTTPS, or unreachable |
call.failed code=487 | Caller hung up before the callee answered |
call.failed code=486 | Callee is busy; implement a retry-after-delay |
call.failed with no answered_at | Call never connected; that field is conditional |