Errors
Errors use standard HTTP status codes and always the same JSON body. Branch on
error.code, which is stable; message is informative and may change.
HTTP/1.1 409 Conflict
Content-Type: application/json
X-Request-Id: req_7f3a9c2e5b1d4f60
{
"error": {
"code": "external_id_already_exists",
"message": "external_id is already assigned to another employee of the company."
}
}
All codes
The reference lists the codes each endpoint can return. New codes may be added in v1 (always with a consistent HTTP status): handle an unknown code by its status.
| HTTP | Code | Meaning and what to do |
|---|---|---|
| 400 | invalid_cursor | The cursor is not valid (tampered with or from another listing). Restart the listing without a cursor. |
| 401 | invalid_api_key | The API key is missing, invalid, revoked or expired. |
| 403 | api_disabled | The product (areas, employees...) is not enabled in the admin panel for the key's environment (live or test). |
| 403 | endpoint_disabled | An administrator disabled this specific endpoint in the panel. |
| 403 | insufficient_scope | The API key lacks the scope the endpoint requires (e.g. employees:write). |
| 403 | ip_not_allowed | The source IP is not in the product's IP allowlist. |
| 403 | new_recipients_paused | xYago paused the sender's sends to new recipients (too many phones without xYago). Recipients that already got messages keep working. Contact xYago. |
| 403 | verify_paused | xYago paused Verify for the sender (too many phones without xYago). Verifications already started can still be checked. Contact xYago. |
| 404 | not_found | The resource does not exist or belongs to another company (never distinguished). |
| 404 | sender_not_found | The sender_id is not a sender of your account. |
| 404 | template_not_found | The sender has no template with that name. |
| 404 | recipient_not_on_xyago | POST /verify/start: the phone does not use xYago. Nothing was sent and nothing will be retried: send the code through your other channel (e.g. SMS). |
| 409 | area_already_exists | An area with that name already exists under the same parent. |
| 409 | external_id_already_exists | The external_id is already assigned to another employee of the company. |
| 409 | external_id_in_progress | Another request is creating an employee with that external_id right now. Retry in a few seconds (look it up by external_id first). |
| 409 | employee_already_exists | An employee with that phone_number already exists in the company. |
| 409 | email_already_registered | The email is already used by another employee. |
| 409 | document_number_already_exists | The document_number is already used by another employee of the company. |
| 409 | vacation_already_decided | The request was already approved or rejected. |
| 409 | vacation_overlap | The employee already has approved vacations in that range. |
| 409 | time_entry_overlap | The entry overlaps another entry of the employee in the company. |
| 409 | sender_not_approved | The sender is not approved by xYago yet (in live only approved senders can send). |
| 409 | sender_suspended | xYago suspended the sender (or the account). Contact xYago. |
| 409 | template_not_approved | The template is not approved (in sandbox a draft one also works). |
| 409 | template_paused | xYago paused the template (e.g. after user complaints). It cannot be used until xYago reactivates it; contact xYago. |
| 409 | idempotency_key_reused | That Idempotency-Key was already used with a different body. Use a new key for each different send. |
| 409 | undeliverable | The message cannot be delivered to this recipient. Do not retry. |
| 409 | verification_expired | The code expired (10 minutes). Start a new verification. |
| 409 | max_attempts_reached | The verification's 5 attempts are used up. Start a new one. |
| 409 | verification_not_pending | The verification no longer accepts codes: it was already verified (single use), superseded by a newer one (canceled) or could not be sent (failed). |
| 409 | sandbox_number_exists | The number is already a confirmed test number. |
| 422 | validation_error | The body or parameters do not match the schema (required field, format, unknown field...). message names the field. |
| 422 | invalid_parent_id | parent_id does not reference an active area of the company. |
| 422 | invalid_employee_data | xYago rejected the employee data. Check the fields. |
| 422 | employee_has_no_job | Tried to change the job of an employee who has no job in the company. |
| 422 | invalid_employee_id | employee_id does not reference an employee of the company. |
| 422 | invalid_vacation | xYago rejected the vacation request. |
| 422 | vacation_type_not_configured | The company has no vacation time-off type configured in xYago. |
| 422 | vacation_requires_document | The company requires a supporting document for vacations; they cannot be requested through the API. |
| 422 | invalid_date_range | Invalid from..to range: from after to or longer than 31 days. |
| 422 | invalid_time_range | The entry ends in the future. |
| 422 | invalid_time_entry | xYago rejected the time entry. |
| 422 | invalid_phone | to is not a valid E.164 phone number (at least 10 digits). |
| 422 | template_variables_mismatch | The number of variables does not match the template's variables_count. |
| 422 | invalid_variables | A variable is longer than 256 characters or contains a link. |
| 422 | invalid_button_variables | A button_variables value for a url button with a variable is missing, one is not expected (the button has no variable) or it is invalid (text, max. 200 characters). |
| 422 | sandbox_recipient_not_allowed | With an xy_test_ key you can only send to the test numbers confirmed in the panel. |
| 422 | invalid_message | xYago rejected the message content. |
| 429 | rate_limited | The API key exceeded its per-minute request limit or, on POST /messages, a sender sending cap (messages per minute, per recipient per day, new recipients per day) or, in Verify, a code cap (wait between codes, per phone, per sender) or the wrong-codes-per-hour cap. Wait the Retry-After seconds. |
| 500 | internal_error | Unexpected xYago error. Retry with backoff; if it persists, contact support with the X-Request-Id. |
| 502 | upstream_error | An internal xYago service failed or timed out. Retry with backoff (for writes, check first whether they were applied). |
| 503 | limits_unavailable | Sending limits cannot be checked right now; for safety nothing is sent. Retry with backoff and the same Idempotency-Key. |
| 503 | messaging_not_configured | Messaging is temporarily unavailable. Contact support. |
| 503 | import_queue_unavailable | The import could not be queued. Try again later. |
What to retry
| Status | Retry? |
|---|---|
400, 401, 403, 404, 409, 422 | No: fix the request or the configuration. Exception: 409 external_id_in_progress (retry in a few seconds). |
429 | Yes, after the Retry-After seconds. |
500, 502, 503, network errors / timeouts | Yes, with exponential backoff (e.g. 1 s, 2 s, 4 s... at most 5 attempts). For writes, first check whether they were applied (see idempotency). |
Validation errors
422 validation_error names the failing field in message as
field: reason (several separated by ; ). Unknown fields are rejected
too: sending company_id when creating an employee returns 422, because
the company comes from the API key.
{
"error": {
"code": "validation_error",
"message": "phone_number: String should match pattern '^\\+[1-9][0-9]{6,14}$'; company_id: Extra inputs are not permitted"
}
}
When contacting support
Include the response's X-Request-Id, method and path, time (UTC) and environment
(live/test). Never send the API key.