<!-- Generated by scripts/gen-developer-docs.ts from src/developers/content/recruit/errors.md — do not edit. -->

# Errors

> Every error code the Recruit100x API answers, what it means and what to do about it.

Every error answers the same envelope:

```json
{ "error": { "code": "VALIDATION_FAILED", "message": "…", "details": { "field": "jd.text" } } }
```

`code` is stable — branch on it, not on `message` (plain language, safe to show) or the HTTP status alone. A 429 carries
`Retry-After` (seconds). Routes added in 2026 answer the new codes below; routes that existed before keep their original
codes and messages (they only gain new optional fields).

| Status | Code | What it means | What to do |
|---|---|---|---|
| 400 | `IDEMPOTENCY_KEY_REQUIRED` | This write route needs an `Idempotency-Key` header and none was sent. | Send a unique `Idempotency-Key` (1–255 characters) per operation you mean, and reuse it only to retry that operation. |
| 401 | `API_KEY_INVALID` | The Authorization header is missing, or the key is unknown, revoked or expired. | Send `Authorization: Bearer <key>` with an active key; create a new one in Settings › Integrations if it was revoked or expired. |
| 402 | `INSUFFICIENT_CREDITS` | The workspace has no credits left, so no new invite was sent. | Buy credits on recruit100x.com, then send the invites again. |
| 403 | `AGENCY_SUSPENDED` | The workspace is suspended: reads keep working, actions are refused. | Contact Recruit100x support. |
| 403 | `API_SCOPE_MISSING` | The key is valid but lacks the scope this call needs. | Create a key with the scope named in the message (the old key keeps its scopes). |
| 403 | `FORBIDDEN` | This key may not act on that object. | Use a key of the workspace that owns the object. |
| 403 | `TEST_MODE_ONLY` | A test key touched a live object, a live key touched a test object, or test mode is turned off. | Use the key of the same mode as the object (test ids start with `role_test_`, `inv_test_`, `rep_test_`, `pi_test_`); for a test key, ask for test mode to be turned on. |
| 404 | `NOT_FOUND` | No object with that id exists for your workspace or partnership. | Check the id; objects of another workspace, partnership or mode are never visible. |
| 409 | `CONFLICT` | The object is not in a state that allows this change (the message says which). | Read the object, then retry when its state allows the change; a `retry_after_seconds` detail says when. |
| 409 | `GUIDE_NOT_APPROVED` | The role's interview guide isn't approved yet, so candidates can't be invited. | Wait for the `role.ready` event, or send `"hold_until_ready": true` with `"delivery": "recruit100x"`. |
| 409 | `IDEMPOTENCY_CONFLICT` | The Idempotency-Key was already used with a different body or on another object. | Use a new key for a new request; reuse a key only to retry exactly the same request. |
| 409 | `IN_PROGRESS` | The first request with this Idempotency-Key is still running. | Wait for `Retry-After` and retry with the same key; you will get the first request's answer. |
| 409 | `INVITE_NOT_LINKABLE` | A new link can be issued only for a live invite created with `"delivery": "return_link"`. | Check `details.reason`; for an expired, cancelled or finished invite, invite the candidate again. |
| 409 | `INVITE_STATE` | The invite's status doesn't allow this action (for example, cancelling a started interview). | Read the invite's status first; only unstarted invites can be cancelled. |
| 409 | `ROLE_GUIDE_APPROVED` | The role's interview guide is approved, so its job description and title can no longer change. | Create a new role for a changed job. |
| 409 | `WEBHOOK_LIMIT` | You already have the maximum number of webhook endpoints. | Delete an endpoint you no longer use, then subscribe again. |
| 410 | `WEBHOOK_ENDPOINT_GONE` | The webhook endpoint was deleted. | Subscribe a new endpoint. |
| 422 | `HOLD_NOT_SUPPORTED_FOR_RETURN_LINK` | `hold_until_ready` can't be combined with `"delivery": "return_link"`. | Wait for `role.ready` and invite then, or use `"delivery": "recruit100x"`. |
| 422 | `JD_FETCH_FAILED` | We couldn't read a job description at the link you sent. | Send the description as text: `"jd": {"mode": "paste", "text": …}`. |
| 422 | `ROLE_COUNTRY_NOT_SUPPORTED` | The role's location is in the EU/EEA or outside the countries Recruit100x screens for. | Recruit100x can't screen for this role; don't retry with the same location. |
| 422 | `VALIDATION_FAILED` | The request is not valid; `details.field` names the first field that failed. | Correct the named field and send the request again. |
| 422 | `WEBHOOK_URL_INVALID` | The webhook address is not a public https:// URL. | Use an https:// address on the public internet, without credentials in it. |
| 429 | `INTEGRATION_RATE_LIMITED` | This key sent more requests in the last minute than its limit allows. | Wait for the number of seconds in the `Retry-After` header, then retry; spread bursts out. |
| 429 | `RATE_LIMITED` | Too many requests of this kind in a short time. | Wait for `Retry-After` (when present) and retry with backoff. |
| 500 | `INTERNAL` | Something failed on our side. | Retry with the same Idempotency-Key (where the route takes one); contact support with the time of the call if it keeps failing. |
| 503 | `API_DISABLED` | The API is switched off for maintenance or by support. | Retry later; check the status page or contact support if it lasts. |
| 503 | `VENDOR_UNAVAILABLE` | A service we depend on did not answer in time. | Retry with backoff; nothing was changed when this is returned. |
