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

# Errors

> The two error shapes, and every error code by endpoint

The API uses standard HTTP status codes. Success is `200` (or `201` when something was created).
Anything else comes with a JSON body in one of two shapes.

## Application errors — the `error_code` envelope

Errors raised by an endpoint's own logic — a validation rule, a missing record, a refused
operation — always look like this:

```json theme={null}
{
  "status": "error",
  "error_code": "UNKNOWN_SERVICE",
  "message": "No bookable service named 'Consultation'.",
  "details": { "valid_service_names": ["Consulta Médica", "Control"] }
}
```

<Note>
  **Branch on `error_code`, never on `message`.** Messages are written for humans and may be
  reworded; codes are the contract and do not change.
</Note>

`details` is optional and endpoint-specific: the calendar endpoints use it to list the values
that *would* have been accepted (`valid_service_names`, `valid_professional_names`,
`matching_professional_ids`) or to name the offending `field`.

## Framework errors — the `detail` body

Two failures happen before an endpoint runs, and they use a plainer body:

<AccordionGroup>
  <Accordion title="401 — authentication">
    ```json theme={null}
    { "detail": "Invalid or expired API key. Please check your credentials." }
    ```

    Missing, malformed, unknown or deleted key. See [Authentication](/en/api-reference/authentication).
  </Accordion>

  <Accordion title="422 — request does not match the schema">
    ```json theme={null}
    {
      "detail": [
        { "type": "missing", "loc": ["body", "payload", "phone_number"], "msg": "Field required" },
        { "type": "int_parsing", "loc": ["query", "limit"], "msg": "Input should be a valid integer" }
      ]
    }
    ```

    A required field is absent, a value has the wrong type, or a number is out of its
    documented range (for example `limit` above the maximum). `loc` starts with `body`, `query`
    or `path` and then names the field. Fix the listed fields and retry.
  </Accordion>

  <Accordion title="404 — unknown route or record (some endpoints)">
    ```json theme={null}
    { "detail": "WhatsApp conversation 999999 not found" }
    ```

    Returned for a URL that does not exist, and by *List messages in a WhatsApp conversation*
    for a conversation your key cannot see.
  </Accordion>
</AccordionGroup>

## `500` — `INTERNAL_ERROR`

Something went wrong on our side. The operation was **not** applied (no call queued, no
contact created, no appointment booked), so retrying is safe. If it persists, contact
support with the request you sent.

## Error codes by endpoint

### Calls

| Status | `error_code`           | Meaning                                                               |
| ------ | ---------------------- | --------------------------------------------------------------------- |
| `400`  | `AGENT_NOT_FOUND`      | No voice agent with that `agent_id` in your account.                  |
| `400`  | `INVALID_PHONE_NUMBER` | `phone_number` is not a dialable number. Send E.164 (`+15551234567`). |
| `400`  | `VALIDATION_ERROR`     | Another field was refused; `message` says which.                      |

### Clients

| Status | `error_code`       | Meaning                                                              |
| ------ | ------------------ | -------------------------------------------------------------------- |
| `400`  | `VALIDATION_ERROR` | Neither `phone_number` nor `email` was sent, or a value was refused. |
| `400`  | `DUPLICATE_CLIENT` | A contact with this phone number or email already exists.            |

### Salesflow ingest

| Status | `error_code`           | Meaning                                                                                |
| ------ | ---------------------- | -------------------------------------------------------------------------------------- |
| `404`  | `INPUT_NODE_NOT_FOUND` | No active API input node with that UUID. Check the node is of type **API** and active. |
| `404`  | `CLIENT_NOT_FOUND`     | `client_id` does not exist in your account.                                            |
| `400`  | `VALIDATION_ERROR`     | Neither `client_id` nor `phone_number` was sent, or a value was refused.               |
| `400`  | `UNKNOWN_ERROR`        | The pipeline refused the entry for another reason; read `message`.                     |

### Salesflow batch ingest

The batch endpoint reports most problems **per row** in `results[].errors[].code` (`required`, `invalid_format`, `too_long`, `duplicate_in_batch`, `not_found`, `exists`, `conflict`) with a `200` response; the codes below apply to the request as a whole.

| Status | `error_code`           | Meaning                                                                                                                                                                                           |
| ------ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `404`  | `INPUT_NODE_NOT_FOUND` | No active API input node with that UUID. Check the node is of type **API** and active.                                                                                                            |
| `400`  | `VALIDATION_ERROR`     | The input node has no target stage, or its pipeline is not active.                                                                                                                                |
| `404`  | `STAGE_NOT_FOUND`      | `stage_id` does not belong to the input node's pipeline.                                                                                                                                          |
| `400`  | `INGEST_ROLLED_BACK`   | `all_or_none` was set and at least one row failed; nothing was written. `details.summary` and `details.results` carry the per-row outcome (ids of rows that would have been created are omitted). |

### Salesflow pipelines

| Status | `error_code`         | Meaning                                                                                 |
| ------ | -------------------- | --------------------------------------------------------------------------------------- |
| `404`  | `PIPELINE_NOT_FOUND` | No pipeline with that ID is visible to this key (*List API input nodes of a pipeline*). |
| `400`  | `CLIENTS_NOT_FOUND`  | None of the `client_ids` are active on this pipeline.                                   |
| `404`  | `CLIENT_NOT_FOUND`   | The client to move is not active on this pipeline.                                      |
| `400`  | `MOVE_NOT_ALLOWED`   | The pipeline's stage rules forbid this transition.                                      |
| `404`  | `NOT_FOUND`          | The target stage does not belong to this pipeline.                                      |

### Calendar — availability

| Status | `error_code`    | Meaning                                                                                        |
| ------ | --------------- | ---------------------------------------------------------------------------------------------- |
| `400`  | `INVALID_PARAM` | `start_date` is not `YYYY-MM-DD`, `days` is outside 1–31, or an ID list is malformed or empty. |

### Calendar — booking

| Status | `error_code`               | Meaning                                                                                                              |
| ------ | -------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `400`  | `SERVICE_REQUIRED`         | Neither `service_id` nor `service_name` was sent. `details.valid_service_names` lists your options.                  |
| `400`  | `UNKNOWN_SERVICE`          | No bookable service by that ID or name.                                                                              |
| `400`  | `AMBIGUOUS_SERVICE`        | Several services share that name — send `service_id`.                                                                |
| `400`  | `PROFESSIONAL_REQUIRED`    | Neither `professional_id` nor `professional_name` was sent.                                                          |
| `400`  | `UNKNOWN_PROFESSIONAL`     | Nobody by that name is active on the service.                                                                        |
| `400`  | `AMBIGUOUS_PROFESSIONAL`   | Several active members answer to that name — send `professional_id`; `details.matching_professional_ids` lists them. |
| `400`  | `PROFILE_NOT_IN_SERVICE`   | That `professional_id` is not an active member of the service.                                                       |
| `400`  | `EVENT_TYPE_REQUIRED`      | Neither `event_type_id` nor `event_type_name` was sent.                                                              |
| `400`  | `UNKNOWN_EVENT_TYPE`       | No active appointment type by that ID or name.                                                                       |
| `400`  | `AMBIGUOUS_EVENT_TYPE`     | Several appointment types match that name — send `event_type_id`.                                                    |
| `400`  | `INVALID_EVENT_TYPE`       | The service does not offer that appointment type.                                                                    |
| `400`  | `SERVICE_UNAVAILABLE`      | The service has no active members. Add a professional to it in Dialtu.                                               |
| `400`  | `MISSING_FIELD`            | `start_at`, `end_at` or `timezone` is absent; `details.field` names it.                                              |
| `400`  | `INVALID_TIMEZONE`         | `timezone` is not an IANA zone name.                                                                                 |
| `400`  | `INVALID_PHONE_NUMBER`     | `client.phone` is missing or not a possible international number.                                                    |
| `400`  | `CLIENT_NAME_REQUIRED`     | The phone is new to your account and no name was sent.                                                               |
| `400`  | `CLIENT_IDENTITY_CONFLICT` | That phone or email belongs to a contact this key cannot see. Contact support.                                       |
| `400`  | `DATA_MISSING`             | The matched contact lacks something the appointment needs; `details` names it.                                       |
| `400`  | `VALIDATION_ERROR`         | `end_at` is not after `start_at`, or another rule was refused.                                                       |
| `400`  | `FORBIDDEN_CALENDAR`       | The key may not book on that calendar.                                                                               |
| `409`  | `SLOT_CONFLICT`            | Documented for completeness — bookings through the API are never refused for conflicts.                              |
| `422`  | `OUTSIDE_AVAILABILITY`     | Documented for completeness — bookings through the API are never refused for availability.                           |

### Calendar — waiting lists

| Status | `error_code`                            | Meaning                                                                        |
| ------ | --------------------------------------- | ------------------------------------------------------------------------------ |
| `400`  | `CLIENT_IDENTITY_REQUIRED`              | Neither `client_id` nor `phone` was sent.                                      |
| `400`  | `SERVICES_REQUIRED`                     | Neither `service_ids` nor `service_names` was sent.                            |
| `400`  | `UNKNOWN_SERVICE` / `SERVICE_NOT_FOUND` | A named or numbered service does not exist.                                    |
| `400`  | `SERVICE_NOT_ON_WAITLIST`               | The `waitlist_id` given does not cover that service.                           |
| `400`  | `PROFESSIONAL_NOT_FOUND`                | `preferred_professional_id` does not exist.                                    |
| `400`  | `INVALID_PARAM`                         | A date is not `YYYY-MM-DD`, a filter value is unknown, or a range is inverted. |
| `404`  | `CLIENT_NOT_FOUND`                      | `client_id` does not exist in your account.                                    |
| `404`  | `WAITLIST_NOT_FOUND`                    | `waitlist_id` does not exist.                                                  |
| `404`  | `ENTRY_NOT_FOUND`                       | No waiting-list entry with that ID.                                            |
| `409`  | `ENTRY_NOT_OPEN`                        | The entry is already booked, removed or expired.                               |

### WhatsApp

| Status | `error_code`            | Meaning                                                                             |
| ------ | ----------------------- | ----------------------------------------------------------------------------------- |
| `400`  | `VALIDATION_ERROR`      | Invalid `status`, `direction` or `sort_by` value; `message` lists the allowed ones. |
| `404`  | *(plain `detail` body)* | The conversation does not exist in your sub-account.                                |
