Errors
This page documents the error responses from POST /public/v1/calls and what to do about each one.
Base URL
https://api.yourcalls.ai
Error response shape
Errors return the standard envelope with success: false and a populated error object:
{
"success": false,
"data": null,
"error": {
"code": "NOT_FOUND",
"message": "Assistant not found"
},
"requestId": "req-abc123",
"apiVersion": 1
}
Every response uses this envelope, including authentication failures.
Match on error.code, which is stable. Treat error.message as text for humans; it can be reworded.
Validation failures add a details array naming the fields that failed:
{
"success": false,
"data": null,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request payload: metadata may not contain the reserved key \"company_id\"",
"details": [
{
"code": "custom",
"path": ["metadata", "company_id"],
"message": "metadata may not contain the reserved key \"company_id\""
}
]
},
"requestId": "req-abc123",
"apiVersion": 1
}
path locates the problem inside your request body, so you can report it against the right field rather than rejecting the whole payload.
Authentication errors
All four refusals share the code UNAUTHORIZED and differ by message, so you can tell which key problem you have:
| Status | Code | Message | Meaning | What to do |
|---|---|---|---|---|
401 | UNAUTHORIZED | Missing API key | No key in the Authorization or x-api-key header. | Send the key in a header. A key in the URL query string is not accepted. |
401 | UNAUTHORIZED | Invalid API key | The key is not recognised. | Check for a copy-and-paste error, then create a new key in the dashboard. |
401 | UNAUTHORIZED | API key revoked | The key has been revoked. | Create a new key and update your integration. |
401 | UNAUTHORIZED | API key expired | The key has passed its expiry date. | Create a new key and update your integration. |
500 | INTERNAL_ERROR | Authentication error | The key could not be checked. | Retry with backoff. Contact support if it persists. |
Branch on the status and code; use the message to tell a person which of the four it was.
Call trigger errors
| Status | Code | Meaning | What to do |
|---|---|---|---|
400 | VALIDATION_ERROR | The body is missing a required field, has a field of the wrong type, contains an unrecognised field, or uses a reserved metadata key. | Read error.details for the offending field. Remember the body is strict, so an unexpected field is an error rather than being ignored. |
402 | INSUFFICIENT_CREDIT | The account has no credit to cover the call. | Top up the credit balance. Do not retry until you have. |
402 | CALL_ALLOWANCE_EXHAUSTED | The plan's included call minutes are used up and credit cannot cover an overage. | Add credit or change plan. Do not retry until you have. |
402 | BILLING_RESTRICTED | Outbound calls are paused: the account's credit balance is below zero, or its payment details were not re-added after the billing move. | Top up the credit balance, or re-add the payment details in the dashboard. Do not retry until you have. |
403 | BILLING_INACTIVE | Calling is unavailable for the account's current billing state. | Check the billing section of the dashboard. |
404 | NOT_FOUND | No assistant with that ID exists in your company. | Check assistant_id. A valid ID belonging to another company also returns this. |
422 | INVALID_CONFIG | The assistant is not ready to place calls: it has not been published, has no outbound phone number linked, or its number setup is incomplete. | The message names which. Fix it against the assistant in the dashboard. |
422 | REGION_NOT_SUPPORTED | The target number's country is not currently enabled for outbound calling (Jersey, Guernsey and the Isle of Man are not), or it is a premium-rate, shared-cost, personal, pager or corporate number. | See Region support on the Calls page. Get in touch if you need a region added. |
422 | INVALID_PHONE_NUMBER | The target number is in E.164 format but is not a real number for its country. The call was not created. | Check the number at its source. Sending the same number again fails the same way. |
422 | BEFORE_CALL_FAILED | A before-call tool on this assistant declined the call. The call was not created. | This is your own tool's decision. Check what it returned. |
429 | CONCURRENCY_FULL | The account is already running as many simultaneous calls as its plan allows. | Retry with backoff. |
502 | BEFORE_CALL_DISPATCH_FAILED | A before-call tool could not be reached. The call was not created. | Check that your tool endpoint is reachable and responding within its timeout, then retry. |
502 | PROVIDER_ERROR | The call could not be placed because of a temporary problem with the calling service. | Retry with backoff. |
500 | INTERNAL_ERROR | The call failed for an unexpected reason. | Retry with backoff. Quote the requestId from the response if you contact support. |
Which errors are worth retrying
Retry with backoff:
429 CONCURRENCY_FULL502 PROVIDER_ERROR502 BEFORE_CALL_DISPATCH_FAILED500 INTERNAL_ERROR
Do not retry. These will keep failing until something changes at your end:
- every
400 VALIDATION_ERROR - every
402code, until the credit balance, the plan or the payment details change 403 BILLING_INACTIVE404 NOT_FOUND- the
422configuration, region and number codes (INVALID_CONFIG,REGION_NOT_SUPPORTED,INVALID_PHONE_NUMBER)
Troubleshooting tips
- Check auth first. Most integration failures are key related.
- Read
error.detailson a 400. It names the field that failed, which is faster than guessing. - Do not retry a 402 or 403. These mean the account must be changed before any call can succeed. Retrying wastes attempts and delays the real fix.
- Keep both request IDs. Store
data.request_idfrom a successful trigger, which identifies the call, and the top-levelrequestIdfrom a failure, which identifies the HTTP request. They are different values, and between them support can trace what happened.