> ## 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.

# Webhooks

> O envelope de evento, os três tipos de evento, entrega pelo menos uma vez e a política de reentrega.

Webhooks notificam seu sistema em tempo real quando um agendamento muda, sem que você precise fazer polling constante. Registre um endpoint HTTPS público em **Minha Clínica → API e Webhooks** e escolha os eventos de interesse.

<Note>
  A URL do endpoint precisa ser HTTPS pública. `http://`, `localhost` e endereços de rede privada são rejeitados no momento em que você salva o endpoint (e checados de novo a cada entrega) — não é possível registrar um endpoint apontando para a sua máquina local ou para uma rede interna.
</Note>

## O envelope

Todo evento chega no corpo da requisição `POST` nesse formato:

```json theme={null}
{
  "id": "evt_<uuid>",
  "type": "appointment.created",
  "created_at": "2026-08-02T10:31:00-03:00",
  "api_version": "v1",
  "company_id": 42,
  "data": { "...": "mesmo formato do GET /appointments/{id}" }
}
```

| Campo         | Descrição                                                                                                                                   |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`          | Identificador do evento, no formato `evt_<uuid>`. **Estável entre reentregas** — a mesma tentativa de evento sempre chega com o mesmo `id`. |
| `type`        | Um dos três tipos de evento abaixo.                                                                                                         |
| `created_at`  | Instante em que o evento foi gerado (ISO 8601, `America/Sao_Paulo`).                                                                        |
| `api_version` | Versão do contrato público — hoje sempre `"v1"`.                                                                                            |
| `company_id`  | Identificador da clínica dona do agendamento.                                                                                               |
| `data`        | O agendamento completo, no mesmo formato do `GET /appointments/{id}` — veja [Agendamentos](/agendamentos).                                  |

## Tipos de evento

| Evento                  | Disparado quando                                                                                                      |
| ----------------------- | --------------------------------------------------------------------------------------------------------------------- |
| `appointment.created`   | Um novo agendamento é criado — pela equipe, via agendamento online do paciente ou pela própria API (`origin: "api"`). |
| `appointment.updated`   | Um agendamento existente muda — horário, status, profissional, sala, modalidade etc.                                  |
| `appointment.cancelled` | Um agendamento é cancelado.                                                                                           |

Um endpoint só recebe os eventos aos quais está inscrito.

Os eventos não distinguem a origem da mudança: uma escrita feita pela API com o escopo `appointments:write` gera o mesmo evento que uma edição no aplicativo — inclusive para o endpoint do sistema que fez a escrita. Se o seu sistema escreve e também recebe webhooks, espere o eco das próprias escritas e trate-o de forma idempotente pelo `id` do agendamento em `data`.

## Entrega pelo menos uma vez (at-least-once)

A entrega é **pelo menos uma vez**: o mesmo evento pode chegar mais de uma vez ao seu endpoint — por exemplo, se sua resposta demorar demais e a tentativa for considerada falha antes de você terminar de processá-la. O `id` do envelope é estável entre essas reentregas.

<Warning>
  **Faça a deduplicação pelo `id` do envelope** e garanta que processar o mesmo evento duas vezes seja seguro (idempotente). Nunca assuma que cada `id` chega exatamente uma vez.
</Warning>

## Responda rápido, processe depois

Responda `2xx` em até **10 segundos**. Se o processamento do evento (gravar no seu banco, disparar outras integrações) demorar mais que isso, enfileire o trabalho e responda `2xx` imediatamente após validar a assinatura — processe de forma assíncrona depois.

## Política de reentrega

Se seu endpoint não responder `2xx`, o ByDoctor tenta novamente seguindo esta escala:

`1 min → 5 min → 30 min → 2 h → 6 h`

Cada "falha" nessa contagem é uma entrega que já esgotou as 6 tentativas da escala acima (cerca de 8h36 de tentativas) — não uma única resposta ruim. Após **20 falhas consecutivas** (ou seja, \~20 entregas seguidas totalmente esgotadas — uma indisponibilidade sustentada do seu receptor, não um erro pontual), o endpoint é **desativado automaticamente** e os administradores da clínica são notificados por e-mail. Um endpoint desativado não recebe novos eventos até ser reativado manualmente em **Minha Clínica → API e Webhooks**.

## Evento de teste (ping)

Ao cadastrar ou editar um endpoint, use o botão de teste na interface do ByDoctor para disparar um evento `ping` — ele segue o mesmo envelope e a mesma assinatura de um evento real, mas com `type: "ping"` e um `data` fixo, não o formato de um agendamento:

```json theme={null}
{ "message": "Evento de teste do ByDoctor." }
```

Não trate `data` vazio como sinal de que é um ping — não é assim que ele se distingue; verifique o campo `type` do envelope. O `ping` é útil para validar que seu endpoint está no ar e verificando assinaturas corretamente antes de assinar eventos de produção.

## Próximo passo

<Card title="Verificação de assinatura" icon="shield-check" href="/verificacao-de-assinatura">
  Valide que cada evento realmente veio do ByDoctor antes de confiar nele.
</Card>
