> ## Documentation index
> Fetch the complete documentation index at: https://docs.leadmcp.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors and warnings

Read a failure and a partial answer.

## The error envelope

The error envelope. Every failure carries it, and the shape is frozen. Every failure also carries a `request_id`. Send the request_id to support@leadmcp.ai.

```json
{
  "ok": false,
  "request_id": "req_01JBQ2W8K9V6M3T0X5Y7Z4A1BC",
  "release": "b_2026_09_15",
  "error": {
    "code": "filter.unknown_key",
    "message": "Unknown filter key 'country'.",
    "hint": "Use countries. Call GET /contacts/schema for every key.",
    "field": "filter.country"
  }
}
```

- `ok` | boolean | required. False on every failure response.
- `request_id` | string | required. The id of this request. Send the request_id to support@leadmcp.ai.
- `release` | string | optional. The build id that served this response, when one served it.
- `error` | object | required. The failure itself.
  - `code` | ErrorCode (slug) | required. The closed, published error code list. Codes are dotted `noun.reason`. We add codes and never repurpose one. `account.suspended` (403): an admin suspended the account, or a payment failed. After an admin suspension, contact support@leadmcp.ai. After a failed payment, update the card in Billing; spending calls are refused until a payment succeeds. Values: `request.invalid`, `filter.unknown_key`, `filter.unknown_value`, `filter.rejected`, `cursor.expired`, `enrich.mode_unavailable`, `enrich.too_many_inputs`, `auth.invalid_key`, `account.suspended`, `contact_credits.exhausted`, `premium_credits.exhausted`, `column.not_found`, `export.not_found`, `alert.not_found`, `alert.busy`, `collect.not_found`, `plan.required`, `export.expired`, `export.running`, `export.no_matches`, `rate.limited`, `data.unavailable`, `query.timeout`, `signals.below_minimum`, `alerts.limit_reached`, `auth.oauth_required`, `key.limit_reached`, `key.not_found`.
  - `message` | string | required. One sentence that states what failed.
  - `hint` | string | optional. The fix, named. On a closed list value it prints every allowed slug.
  - `field` | string | optional. The dotted path of the offending field, for example `filter.country`.
  - `details` | ContactCreditsExhaustedDetails or PremiumCreditsExhaustedDetails or SignalsBelowMinimumDetails | optional. Structured error details: contact_credits.exhausted carries ContactCreditsExhaustedDetails, premium_credits.exhausted carries PremiumCreditsExhaustedDetails, and signals.below_minimum carries SignalsBelowMinimumDetails; hint and field stay beside details on error.
    - `ContactCreditsExhaustedDetails` | ContactCreditsExhaustedDetails | optional. Details for contact_credits.exhausted.
      - `binding` | enum | required. The contact credit window whose cap is spent. Values: `day`, `month`.
      - `resets_at` | string | required. The RFC 3339 reset time, or 9999-12-31T23:59:59.000Z for the free plan's lifetime pool.
    - `PremiumCreditsExhaustedDetails` | PremiumCreditsExhaustedDetails | optional. Details for premium_credits.exhausted.
      - `required` | integer | required. The premium credits required for this request.
      - `available` | integer | required. The premium credits still available this month.
      - `allowance` | integer | required. The monthly premium credit allowance on the account.
      - `resets_at` | string | required. The RFC 3339 time when the premium credit allowance resets.
      - `upgrade_url` | string | required. The billing URL where the account owner can raise the premium credit tier.
    - `SignalsBelowMinimumDetails` | SignalsBelowMinimumDetails | optional. Details for signals.below_minimum.
      - `followers` | integer | required. The number of followers on the requested company page.
- `quota` | Quota | optional. present when the account is known; absent for failures before the account is identified (for example a missing or invalid key)
  - `plan` | string | required. The plan slug this account is on. It names the caps; read the numbers themselves from `GET /account`.
  - `contact_credits_used` | integer | required. The contact credits this request spent. A count, a schema read or a miss spends zero.
  - `month_remaining` | integer | required. The contact credits left in the current billing month. A paid plan's month starts on its billing date each month; without a subscription it is the UTC calendar month. On the free plan, the contact credits left in the lifetime pool; the pool has no window.
  - `today_remaining` | integer | required. The contact credits left in the current UTC day. On the free plan, the same number as `month_remaining`.
  - `binding` | enum | required. The window that runs out first at the current pace. On the free plan, always `month`. Values: `month`, `day`.
  - `resets_at` | string | required. The RFC 3339 UTC time at which the binding window resets. On the free plan the pool never resets, and the field is `9999-12-31T23:59:59.000Z`.

## Error codes

| Code | Status | Meaning |
| --- | --- | --- |
| `request.invalid` | 400 | An empty normalized name returns 400 request.invalid. |
| `filter.unknown_key` | 400 | Fields resolve against `GET /contacts/schema`, case-insensitively, and an unknown field returns 400 filter.unknown_key. |
| `filter.unknown_value` | 400 | Unknown values return 400 filter.unknown_value with allowed values and a hint to GET /contacts/schema/country/values. |
| `filter.rejected` | 422 | The filter was rejected before it ran: more than 32 predicates, deeper than 4, more than 25 leaves, more than 1,000 domains or company names, more than 50 values in another list, a leading wildcard in a where leaf, a leading or trailing wildcard in title_query, an operator, value type or shape the column does not take, a leaf other than exists with no value, or an empty `and` or `or` group. |
| `cursor.expired` | 400 | A cursor minted on an earlier build returns 400 cursor.expired, and the caller starts the search again. |
| `enrich.mode_unavailable` | 400 | Sending true returns 400 enrich.mode_unavailable. |
| `enrich.too_many_inputs` | 400 | More than 100 enrichment inputs return 400 enrich.too_many_inputs with the hint: Send at most 100 inputs per call; split larger lists into batches. |
| `auth.invalid_key` | 401 | The credential is missing, unknown or revoked. |
| `account.suspended` | 403 | `account.suspended` (403): an admin suspended the account, or a payment failed. |
| `contact_credits.exhausted` | 402 | The daily or the monthly contact credit cap is spent, or the free plan's lifetime pool is. |
| `premium_credits.exhausted` | 402 | Details for premium_credits.exhausted. |
| `column.not_found` | 404 | The id or the column does not exist, or the row was opted out. |
| `export.not_found` | 404 | The id or the column does not exist, or the row was opted out. |
| `alert.not_found` | 404 | Unknown alert id or an alert belonging to another account. |
| `alert.busy` | 409 | The alert already has a queued or running job. |
| `collect.not_found` | 404 | Unknown collect job id, an alert run, or a job of another account. |
| `plan.required` | 403 | Creating alerts requires a paid plan (plan.required). |
| `export.expired` | 410 | The export file has expired or is no longer available. |
| `export.running` | 409 | One export already runs on this account. |
| `export.no_matches` | 400 | A filter that matches nothing is refused with 400 export.no_matches, free, and no job is created. |
| `rate.limited` | 429 | The key passed 300 requests a minute or 2 concurrent requests. |
| `data.unavailable` | 503 | The data is unavailable for a short time. |
| `query.timeout` | 504 | The query passed its time budget and was stopped. |
| `signals.below_minimum` | 400 | Details for signals.below_minimum. |
| `alerts.limit_reached` | 403 | Accounts may have at most 100 active alerts (alerts.limit_reached). |
| `auth.oauth_required` | 403 | The request is signed with an API key. |
| `key.limit_reached` | 409 | The account already has its one active API key. |
| `key.not_found` | 404 | No active API key with this id on this account. |

## Warning codes

A warning rides on a success. The status stays 200.

| Code | Meaning |
| --- | --- |
| `count_unavailable` | A null count carries a count_unavailable warning. |
| `no_rows` | On zero rows the response carries a `no_rows` warning that names the keys applied. |
| `export_truncated` | The export_truncated warning names the reason and the reset time. |
| `duplicate_work_email` | When two contacts share a work email, the later `last_updated` wins and a `duplicate_work_email` warning says so. |
| `duplicate_linkedin` | When two contacts share a LinkedIn slug, the later `last_updated` wins and a `duplicate_linkedin` warning says so. |
| `off_domain` | A person we hold at another employer, or with no employer domain, answers `matched: false` with `off_domain: true`, costs nothing, and is listed on an `off_domain` warning. |
| `deprecated` | A field, a key or a code is on its way out. It is removed no earlier than six months after this warning first appears. |
| `max_followers_missing` | Without max_followers, a company job asks for at most the premium credits available and adds a max_followers_missing warning. |
