Skip to content

Errors

Every non-2xx response is an RFC 9457 application/problem+json body:

{
"type": "https://docs.vocapable.com/errors/contact_not_dialable",
"title": "Contact blocked by scrub",
"status": 409,
"detail": "Contact cont_01JA0M… is on the federal DNC list (dataset 2026-07-27).",
"instance": "/v1/campaigns/camp_01JA0V.../launch",
"errors": [{ "field": "contact_id", "reason": "dnc_federal" }]
}
  • type is stable and machine-matchable, and it resolves: every code the API can emit has a page at https://docs.vocapable.com/errors/{code}, indexed in the error registry.
  • errors[] carries field-level detail for validation failures. invalid_request is the only code that routinely carries many entries.
  • detail is human-oriented prose. Log it; never branch on it.

The final path segment of type is the error code (snake_case), and the registry is a promise: a code is never re-pointed at a different meaning A changed meaning is a new code, because the old one is something an integrator wrote an if against. Branch on the code alone and treat the status as redundant confirmation:

const problem = await response.json();
const code = new URL(problem.type).pathname.split("/").pop();
switch (code) {
case "scrub_unacknowledged":
// fresh report exists: acknowledge it, then relaunch
break;
case "rate_limited":
// honor Retry-After
break;
}

Neither is ever the caller’s fault, and neither is fixed by changing the request:

  • 503 means this deployment is missing a dependency it needs (the database, a live telephony provider, the calendar aggregator). The request may succeed later or on another environment. Retry with backoff.
  • 501 means the code path is deliberately unbuilt here, and retrying will never help until it ships (for example knowledge_upload_extractor_unavailable). Surface it; do not retry.

Body or query contract failures return 422 invalid_request, with one errors[] entry per offending field, as in [{"field": "schedule.start_date", "reason": "…"}]. Bad filters and cursors are 400 (invalid_filter, invalid_cursor). Wire your client to render errors[] next to the fields it names; the platform will never return a bare 500 for a validation problem.

The full registry, listing every code, its status, and its meaning, grouped exactly as the API documentation registers them, lives at /errors.