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

> ## Agent Instructions
> Esta documentação cobre exclusivamente a API pública v1 do ByDoctor.
> Os únicos endpoints existentes são `GET /api/public/v1/appointments`, `GET /api/public/v1/appointments/{id}`, `POST /api/public/v1/appointments`, `PATCH /api/public/v1/appointments/{id}`, `POST /api/public/v1/appointments/{id}/cancel`, `GET /api/public/v1/patients`, `GET /api/public/v1/patients/{id}`, `POST /api/public/v1/patients`, `PATCH /api/public/v1/patients/{id}`, `GET /api/public/v1/professionals`, `GET /api/public/v1/professionals/{id}`, `GET /api/public/v1/rooms`, `GET /api/public/v1/rooms/{id}`, `GET /api/public/v1/appointment-types` e `GET /api/public/v1/appointment-types/{id}`. Não existem `PUT` nem `DELETE`, e não existe escrita em nenhum outro recurso.
> Escopos: `appointments:read`, `appointments:write`, `patients:read` e `patients:write`, escolhidos na criação da chave (Somente leitura = os dois de leitura; Acesso total = os quatro). Chaves antigas não têm os escopos de pacientes. `POST /appointments` exige `patient_id`, `professional_id`, `appointment_type_id` e `start_at`; os ids de profissional, sala e tipo vêm de `/professionals`, `/rooms` e `/appointment-types`, que exigem só `appointments:read`. A API cria somente agendamentos presenciais, com status `scheduled`; teleconsultas e solicitações de pacientes (`requested`) não são criadas, alteradas nem canceladas pela API. `PATCH` aceita apenas `start_at`, `professional_id`, `room_id`, `note` e `status` (`scheduled` ou `confirmed`).
> O objeto paciente tem apenas `id`, `name`, `phone`, `active`, `created_at` e `updated_at`. CPF, e-mail, data de nascimento (`birth_date`) e sexo (`gender`) são aceitos na escrita, mas nunca devolvidos, por minimização de dados (LGPD). Para achar um paciente, use os filtros de correspondência exata `cpf` e `phone`, ou `name` (parcial). Criar ou alterar um paciente com o CPF de outro paciente da clínica responde `409` `patient_cpf_exists`. Não existem eventos de webhook de pacientes.
> Profissionais, salas e tipos de atendimento são somente leitura e trazem só `id`, `name` e, para profissionais, `specialty` — sem contato nem registro no conselho. Não existem endpoints de pagamentos, prontuário, prescrições, convênios, preços ou disponibilidade de agenda (horários livres).
> Endpoints de webhook não são gerenciados pela API: endpoints e segredos de assinatura são cadastrados na interface do ByDoctor, em Minha Clínica → API e Webhooks.
> Erros: `400` vem como `{"campo": ["mensagem"]}`; `401`/`403`/`404` como `{"detail": ...}`; `409` e `422` como `{"code", "detail"}`. Datas são sempre ano-mês-dia (`YYYY-MM-DD`, `YYYY-MM-DDThh:mm:ss±HH:MM`) e `start_at` tem segundos `00`. As mensagens exatas estão na página Erros.
> Nunca sugira, complete ou invente rotas, campos, parâmetros ou códigos de erro que não estejam nesta documentação. Se algo não está documentado aqui, não existe na v1.
> Autenticação: cabeçalho `Authorization: Bearer bd_live_<id>.<secret>`. Base URL: `https://api.bydoctor.com.br/api/public/v1`. Criação aceita o cabeçalho opcional `Idempotency-Key`.
> Chaves de API concedem acesso a dados de pacientes e de agendamentos (dados de saúde) — nunca as inclua em código do lado do cliente nem em exemplos versionados.

# Erros

> Formato das respostas de erro da API, as regras de formato de datas, ids e escolhas, e as mensagens exatas de cada validação.

Toda resposta de erro diz o que foi recusado **e o que é aceito**. As mensagens vêm em inglês; os campos e os códigos são estáveis. Ramifique pelo status HTTP e, no `409`, pelo `code`, nunca pelo texto.

## Formato por status

| Status                       | Corpo                                                      | Quando                                                                                                                          |
| ---------------------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `400 Bad Request`            | `{"campo": ["mensagem"]}`, uma lista por campo             | Corpo ou filtro inválido. Vários campos podem vir juntos. Um erro que não é de um campo específico vem em `non_field_errors`.   |
| `401 Unauthorized`           | `{"detail": "mensagem"}`                                   | Chave ausente, mal formatada, inválida, revogada ou expirada.                                                                   |
| `403 Forbidden`              | `{"detail": "mensagem"}`                                   | A chave não tem o escopo da rota. A mensagem nomeia o escopo.                                                                   |
| `404 Not Found`              | `{"detail": "mensagem"}`                                   | `id` inexistente, inativo ou de outra clínica. A mensagem nomeia o recurso.                                                     |
| `405 Method Not Allowed`     | `{"detail": "mensagem"}`                                   | Método que a rota não aceita, como `DELETE`.                                                                                    |
| `409 Conflict`               | `{"code": "...", "detail": "mensagem"}`                    | Uma regra de negócio recusou a escrita. Veja os códigos em [Agendamentos](/agendamentos#erros) e [Pacientes](/pacientes#erros). |
| `415 Unsupported Media Type` | `{"detail": "mensagem"}`                                   | Corpo num formato que a API não lê, como `text/plain`. Envie JSON com `Content-Type: application/json`.                         |
| `422 Unprocessable Entity`   | `{"code": "idempotency_key_reused", "detail": "mensagem"}` | `Idempotency-Key` repetida com outro corpo ou em outro endpoint.                                                                |
| `429 Too Many Requests`      | `{"detail": "mensagem"}` + cabeçalho `Retry-After`         | Limite de requisições excedido.                                                                                                 |

Um JSON malformado (por exemplo, uma vírgula depois do último campo) responde `400` com `{"detail": "JSON parse error - ..."}`, apontando a linha e a coluna do problema.

## Formatos aceitos

Estas regras valem para o corpo e para os filtros de todas as rotas.

| Tipo              | Formato                                                                                                         | Exemplo                     | Mensagem quando inválido                                                       |
| ----------------- | --------------------------------------------------------------------------------------------------------------- | --------------------------- | ------------------------------------------------------------------------------ |
| Data e hora       | ISO 8601, **ano-mês-dia**: `YYYY-MM-DDThh:mm[:ss][+HH:MM\|-HH:MM\|Z]`. Sem fuso, é lida em `America/Sao_Paulo`. | `2026-10-03T14:00:00-03:00` | `Invalid date-time. Use ISO 8601 in year-month-day order: ...`                 |
| Data              | `YYYY-MM-DD`, **ano-mês-dia**                                                                                   | `1990-05-10`                | `Invalid date. Use YYYY-MM-DD (year-month-day), e.g. 1990-05-10.`              |
| Id                | Número inteiro                                                                                                  | `123`                       | `Must be an integer id, e.g. 123.`                                             |
| Escolha           | Um dos valores listados na mensagem                                                                             | `"M"`                       | `"X" is not a valid choice. Use one of: M, F, O.`                              |
| Campo obrigatório | —                                                                                                               | —                           | `This field is required.` (em campos de escolha, seguido de `Use one of: ...`) |

<Warning>
  `2026-18-07` não é 18 de julho: a ordem é sempre ano-mês-dia, então o `18` é lido como mês e a data é recusada. Para 18 de julho de 2026, envie `2026-07-18`.
</Warning>

## Mensagens de validação

### Agendamentos

| Campo                 | Mensagem                                                                                                   | Como resolver                                       |
| --------------------- | ---------------------------------------------------------------------------------------------------------- | --------------------------------------------------- |
| `start_at`            | `start_at must be on a whole minute: seconds and fractions must be 00, e.g. 2026-10-03T14:00:00-03:00.`    | Zere os segundos.                                   |
| `start_at`            | `start_at must be between AAAA-MM-DD and AAAA-MM-DD (one year in the past to two years in the future).`    | A mensagem traz as datas-limite do dia.             |
| `patient_id`          | `No active patient with this id in your clinic. Find or create one with GET /patients and POST /patients.` | Veja [Pacientes](/pacientes).                       |
| `professional_id`     | `No active professional with this id in your clinic. List them with GET /professionals.`                   | Veja [Profissionais](/profissionais).               |
| `appointment_type_id` | `No active appointment type with this id in your clinic. List them with GET /appointment-types.`           | Veja [Tipos de atendimento](/tipos-de-atendimento). |
| `room_id`             | `No active room with this id in your clinic. List them with GET /rooms.`                                   | Veja [Salas](/salas).                               |
| `status`              | `"X" is not a valid choice. Use one of: scheduled, confirmed.`                                             | Só esses dois status são escritos pela API.         |
| `non_field_errors`    | `Send at least one field to change.`                                                                       | `PATCH` com corpo vazio.                            |

Um id de outra clínica recebe a mesma mensagem de um id inexistente: a API nunca confirma que um id existe fora da sua clínica.

### Pacientes

| Campo              | Mensagem                                                                                                                                                                             | Como resolver                                               |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------- |
| `gender`           | `This field is required. Use one of: M, F, O.`                                                                                                                                       | `M`, `F` ou `O`.                                            |
| `cpf`              | `Invalid CPF: it must have 11 digits with valid check digits, with or without punctuation (e.g. 529.982.247-25). CPFs with every digit repeated, like 999.999.999-99, are rejected.` | Envie um CPF real; os dígitos verificadores são conferidos. |
| `phone`            | `Invalid phone number: send the area code (DDD) and number, e.g. (11) 98765-4321 or +5511987654321. Without a leading +, 10 or 11 digits are read as a Brazilian number.`            | Inclua o DDD.                                               |
| `birth_date`       | `birth_date cannot be in the future.`                                                                                                                                                | —                                                           |
| `non_field_errors` | `Send at least one field to change.`                                                                                                                                                 | `PATCH` com corpo vazio.                                    |

### Filtros

| Parâmetro      | Mensagem                                                                                                  |
| -------------- | --------------------------------------------------------------------------------------------------------- |
| `status`       | `Unknown status. Use one of: requested, scheduled, confirmed, checked_in, completed, no_show, cancelled.` |
| `start_date`   | `start_date cannot be after end_date.`                                                                    |
| `end_date`     | `end_date must be at most 92 days after start_date.`                                                      |
| `active`       | `Use "true" or "false".`                                                                                  |
| `cpf`, `phone` | As mesmas mensagens da escrita de pacientes.                                                              |

Parâmetros que a rota não conhece são ignorados, não recusados. Confira o nome do filtro se o resultado não mudar.

## 401, 403 e 404

| Status | Mensagem                                                                                                                                |
| ------ | --------------------------------------------------------------------------------------------------------------------------------------- |
| `401`  | `Authentication credentials were not provided. Send your API key as "Authorization: Bearer <key>".`                                     |
| `401`  | `Invalid Authorization header format. Send your API key as "Authorization: Bearer <key>".`                                              |
| `401`  | `Invalid API key. Check it was copied whole, or create a new one in Minha Clínica → API e Webhooks.`                                    |
| `401`  | `API key is revoked or expired. Create a new one in Minha Clínica → API e Webhooks.`                                                    |
| `403`  | `This API key does not have the "patients:write" scope.` (com o escopo que a rota exige)                                                |
| `404`  | `No patient with this id in your clinic.` (com o recurso da rota: `appointment`, `patient`, `professional`, `room`, `appointment type`) |
