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

# Sincronização

> Como manter uma cópia local da agenda em dia usando updated_since e webhooks.

Se você mantém uma cópia local dos agendamentos da clínica (para um BI, um CRM ou qualquer sistema próprio), a forma correta de mantê-la em dia combina **webhooks para latência baixa** com **polling como rede de segurança**.

## A receita de polling

<Steps>
  <Step title="Guarde o instante da última sincronização bem-sucedida">
    Persista um timestamp (`updated_since`) toda vez que uma sincronização terminar com sucesso — não a hora de início, a hora em que você confirmou ter processado tudo.
  </Step>

  <Step title="Consulte com updated_since">
    ```bash theme={null}
    curl -H "Authorization: Bearer bd_live_xxxxxxxx.yyyy" \
      "https://api.bydoctor.com.br/api/public/v1/appointments?updated_since=2026-08-04T08:00:00-03:00"
    ```
  </Step>

  <Step title="Siga next até esgotar">
    Continue seguindo o cursor `next` da resposta até que ele venha `null`. Só então a sincronização está completa — parar no meio de uma página deixa agendamentos para trás.
  </Step>

  <Step title="Avance o timestamp salvo">
    Somente depois de esgotar todas as páginas, atualize o `updated_since` salvo para o instante em que esta sincronização começou (não o de agora — chamadas concorrentes na clínica podem ter criado agendamentos entre o início e o fim da sua sincronização).
  </Step>
</Steps>

A mesma receita vale para [pacientes](/pacientes): `GET /patients?updated_since=...` segue a mesma ordem e a mesma paginação. Pacientes não têm webhooks, então ali o polling é o único caminho.

## Cancelamentos não desaparecem

Um agendamento cancelado **continua aparecendo** nos resultados, com `status: "cancelled"` — ele não é removido da resposta. Uma sincronização que trata "ausência na lista" como "foi excluído" vai ficar errada: agendamentos fora da janela de datas ou de status filtrados simplesmente não aparecem por não corresponderem ao filtro, o que é diferente de terem sido cancelados.

Para refletir cancelamentos na sua cópia local, atualize o registro para `status: "cancelled"` quando ele vier assim — não o exclua.

## Webhooks como complemento, não substituto

Use [webhooks](/webhooks) para reagir a mudanças quase em tempo real: eles chegam em segundos, não minutos. Mas a entrega é **pelo menos uma vez** e depende do seu endpoint estar no ar — se ele cair por um tempo, alguns eventos podem se esgotar antes de você voltar a responder `2xx` (veja a política de reentrega em [Webhooks](/webhooks)).

Por isso, trate o polling com `updated_since` como a rede de segurança: mesmo que um webhook se perca, a próxima sincronização periódica fecha a lacuna. Uma sincronização a cada poucos minutos, combinada com webhooks para a experiência em tempo real, cobre os dois casos.
