Docs/Errors

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

CodeMeaningTypical cause
200 / 201 / 204SuccessRequest completed. Streaming responses return 200 with a text/event-stream body.
400Bad requestInvalid JSON, missing required fields, or conflicting parameters.
401UnauthorizedMissing, expired, or malformed Bearer token.
403ForbiddenToken is valid but lacks the scope for this operation.
404Not foundThe object does not exist, or the key cannot see it.
409ConflictResource is in a state that blocks the request (e.g. ending an already-completed call).
422UnprocessableSchema-valid request that fails semantic validation (e.g. unsupported model for the requested task).
429Rate limitedSee rate limits. Response includes Retry-After.
500Server errorUnexpected internal error. Safe to retry with backoff.
503Temporarily unavailableA backend model or deployment is warming up, draining, or unreachable.

Error body

json
{
  "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

TypeWhen it happens
invalid_request_errorMalformed or missing parameters.
authentication_errorBad or missing API key.
permission_errorKey scope insufficient for this operation.
not_found_errorObject does not exist or is not visible to this key.
conflict_errorState conflict; the object is not in a state that accepts this call.
rate_limit_errorKey or org exceeded its request or token budget.
model_errorThe backing model returned an error or timed out. Retry with backoff.
api_errorUnclassified 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.

python
client.calls.create(
    agent_id="agent_abc",
    phone_number="+14155551234",
    idempotency_key="campaign-2026-04-15-user-55123",
)
Idempotency keys

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.