Errors

Every error code the Public API returns, plus how to react.

All error responses share a common shape:

{
  "ok": false,
  "error": "<machine-readable code or human message>",
  "message": "<optional human-readable explanation>",
  "issues": [/* present only on 400 validation_failed */]
}

The error field is intended for switch-statements in your code; message is a longer string for logging or surfacing to internal users.

By status code

400 Bad Request

errorWhenFix
"Request body must be valid JSON."Body is missing or not parseable.Send a Content-Type: application/json header + valid JSON.
"Validation failed."One or more fields failed type/length checks. The issues array names them.Map the issues' path/message back to your form.
"`consent` must be true."consent field was missing or false.GDPR requires explicit consent. Your form should have a required checkbox.

401 Unauthorized

See Authentication errors.

404 Not Found

errorWhen
"Lead not found."Lead ID doesn't exist OR belongs to a different workspace.
"Workspace not found."The workspace owning your API key has been deleted. (Extremely unlikely — revoke and recreate.)

409 Conflict

errorWhenFix
"duplicate_phone"Same phone already a lead in this workspace.Treat as a non-error if your form is idempotent — the previous lead is still in flight. To re-engage, delete the old lead from the dashboard or use GET /api/public/leads/:id to check its state first.

429 Too Many Requests

Per-key rate limits. The Retry-After header tells you when you can try again.

502 Bad Gateway

errorWhen
"voice_dispatch_failed"Voice workspace, Vapi rejected the /call request. The message field is the verbatim Vapi error. Common: invalid Vapi key, deleted assistant, bad phone number ID, insufficient Vapi balance. The just-inserted lead is rolled back so you can retry with the same phone.

500 Internal Server Error

Anything Coachbot didn't anticipate. Indicates a bug — report it and we'll fix.

Idempotent client design

The Public API doesn't (yet) support Idempotency-Key headers, so design your client around the existing semantics:

  1. Treat 409 as success on retry. If your form submit retries due to a network hiccup and you get 409, the first attempt actually succeeded — the lead is in Coachbot. Don't show an error to the user.
  2. Don't retry on 400. Validation errors aren't going to fix themselves. Show the user the issue.
  3. Retry on 429 with the Retry-After delay. Don't busy-loop.
  4. Retry on 502 once or twice with backoff. Vapi has occasional outages. If it keeps failing, the underlying issue is in your Vapi config (check /admin/<slug>/logs).
  5. Retry on 5xx with exponential backoff. Anything genuinely transient.