Errors
Standard HTTP codes, a consistent JSON error body, and typed exceptions in every SDK.
Wordcab uses standard HTTP status codes and a consistent JSON error body. Client libraries translate non-2xx responses into typed exceptions; curl users get the raw payload.
Status codes
| Code | Meaning | Typical cause |
|---|---|---|
200 / 201 / 204 | Success | Request completed. Streaming responses return 200 with a text/event-stream body. |
400 | Bad request | Invalid JSON, missing required fields, or conflicting parameters. |
401 | Unauthorized | Missing, expired, or malformed Bearer token. |
403 | Forbidden | Token is valid but lacks the scope for this operation. |
404 | Not found | The object does not exist, or the key cannot see it. |
409 | Conflict | Resource is in a state that blocks the request (e.g. ending an already-completed call). |
422 | Unprocessable | Schema-valid request that fails semantic validation (e.g. unsupported model for the requested task). |
429 | Rate limited | See rate limits. Response includes Retry-After. |
500 | Server error | Unexpected internal error. Safe to retry with backoff. |
503 | Temporarily unavailable | A backend model or deployment is warming up, draining, or unreachable. |
Error body
{
"error": {
"type": "invalid_request_error",
"code": "missing_required_field",
"message": "Missing required parameter: name",
"param": "name",
"request_id": "req_01HZABCDEF..."
}
}request_id is the single most useful field when you open a support ticket. Every response includes it in the X-Request-ID header as well.
Error types
| Type | When it happens |
|---|---|
invalid_request_error | Malformed or missing parameters. |
authentication_error | Bad or missing API key. |
permission_error | Key scope insufficient for this operation. |
not_found_error | Object does not exist or is not visible to this key. |
conflict_error | State conflict; the object is not in a state that accepts this call. |
rate_limit_error | Key or org exceeded its request or token budget. |
model_error | The backing model returned an error or timed out. Retry with backoff. |
api_error | Unclassified internal error. Include the request_id in any report. |
Handling errors
from wordcab import Wordcab
from wordcab.errors import (
NotFoundError, RateLimitError, PermissionError, APIError,
)
client = Wordcab()
try:
agent = client.agents.get("agent_missing")
except NotFoundError as e:
print(f"No such agent: {e.message} (request {e.request_id})")
except RateLimitError as e:
# retry_after is populated from the Retry-After header
time.sleep(e.retry_after or 1)
except PermissionError:
print("Token is missing the agents:read scope")
except APIError as e:
print(f"Unhandled: {e.type} {e.message}")import {
Wordcab,
NotFoundError,
RateLimitError,
PermissionError,
APIError,
} from "@wordcab/sdk";
const client = new Wordcab();
try {
await client.agents.get("agent_missing");
} catch (e) {
if (e instanceof NotFoundError) console.log(`No such agent: ${e.message}`);
else if (e instanceof RateLimitError) await sleep(e.retryAfter ?? 1000);
else if (e instanceof PermissionError) console.log("Missing scope");
else if (e instanceof APIError) console.log(e.type, e.message);
else throw e;
}Retries
The SDKs retry idempotent requests on 408, 429, 500, and 503 with jittered exponential backoff. Non-idempotent writes (POST to create calls, deployments, etc.) are retried only when you pass an Idempotency-Key header.
client.calls.create(
agent_id="agent_abc",
phone_number="+14155551234",
idempotency_key="campaign-2026-04-15-user-55123",
)Use a stable key per logical action, not per retry. A good key is tied to the business intent (the campaign + user + day), not to the HTTP attempt number.