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
error | When | Fix |
|---|---|---|
| "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
404 Not Found
error | When |
|---|---|
| "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
error | When | Fix |
|---|---|---|
| "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
error | When |
|---|---|
| "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:
- 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.
- Don't retry on 400. Validation errors aren't going to fix themselves. Show the user the issue.
- Retry on 429 with the
Retry-Afterdelay. Don't busy-loop. - 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). - Retry on 5xx with exponential backoff. Anything genuinely transient.