Toda a documentação

API de integração

Novo

Ligue o site, o CRM ou o chatbot da clínica à Medora para ler locais, profissionais, serviços e disponibilidades.

URL base
https://api.medora.pt/public/api/v1
Autenticação
Authorization: Bearer mk_live_…
Versão
v1 · só leitura

Visão geral

A API de integração dá aos sistemas da própria clínica acesso de leitura aos dados que a Medora usa para marcar consultas. Responde em JSON, autentica-se com uma chave da organização e expõe quatro recursos.

RecursoDescrição
GET /localsLocais da organização.
GET /professionalsProfissionais com horário configurado, opcionalmente num local.
GET /servicesServiços ativos, com duração e preço.
GET /availabilityHorários marcáveis num intervalo de datas.
AmbienteURL base
Produçãohttps://api.medora.pt/public/api/v1
Staginghttps://api.staging.medora.pt/public/api/v1

Primeiro pedido

Crie uma chave (ver «Chaves de API»), guarde-a numa variável de ambiente e liste os locais da organização.

Pedido
export MEDORA_KEY="mk_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

curl -H "Authorization: Bearer $MEDORA_KEY" \
  https://api.medora.pt/public/api/v1/locals
Resposta 200
{
  "locals": [
    {
      "id": 12,
      "name": "Clínica São João",
      "slug": "clinica-sao-joao",
      "virtual": false,
      "public_booking_enabled": true,
      "public_phone": "+351210000000",
      "public_email": "geral@clinica.pt",
      "public_address": "Rua Central 1, Porto",
      "public_website_url": "https://clinica.pt"
    }
  ]
}

A versão 1 é só de leitura. A marcação de consultas por API chega numa versão futura; até lá, marque na Medora ou através do widget de marcação.

Chaves de API

Cada chave pertence a uma organização e dá acesso de leitura a todos os seus locais. Só administradores da organização podem criar ou revogar chaves.

  1. Abra a organização, escolha «Integrações» no menu lateral e depois o separador «API».
  2. Clique em «Nova chave» e dê-lhe o nome do sistema que a vai usar (por exemplo «Site da clínica» ou «CRM»).
  3. Copie a chave mk_live_… nesse momento: por segurança não voltará a ser mostrada.
  4. Para retirar o acesso a um sistema, revogue a chave. A revogação é imediata.

Guarde a chave em segurança. Trate-a como uma palavra-passe: não a partilhe, não a coloque em repositórios de código nem em ficheiros públicos, e mantenha-a numa variável de ambiente ou num cofre de segredos. Se suspeitar que foi exposta, revogue-a de imediato e crie outra.

  • Use uma chave por sistema. Assim pode revogar uma sem afetar as outras.
  • Uma organização pode ter até 20 chaves ativas em simultâneo.
  • Cada criação e revogação fica no registo de atividade da organização.

Autenticação

Envie a chave em todos os pedidos, no cabeçalho Authorization com o esquema Bearer.

Cabeçalho
Authorization: Bearer mk_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
SituaçãoEstadoCódigo
Sem cabeçalho ou com outro formato401missing_api_key
Chave desconhecida ou revogada401invalid_api_key
Organização sem subscrição ativa403organization_locked

Convenções

TemaRegra
FormatoJSON em UTF-8. Apenas o método GET; outros métodos respondem 405 method_not_allowed.
Datas-horaRFC 3339 com o fuso de Lisboa, por exemplo 2026-09-15T09:30:00+01:00. No horário de inverno o offset é escrito como Z (2026-12-15T09:30:00Z); compare instantes, não a string do offset.
Datas-diaYYYY-MM-DD, interpretadas no fuso de Lisboa.
IdentificadoresOs mesmos que vê na Medora: id do local, do profissional e do serviço. Um identificador de outra organização responde como inexistente (404).
VersãoTodas as respostas trazem o cabeçalho X-Medora-Api-Version com a data do contrato (atualmente 2026-09-14). Só muda com uma alteração incompatível, que trará um novo prefixo /v2.
CacheAs respostas trazem Cache-Control: no-store. Se quiser guardar resultados, faça-o no seu sistema.

Limites de utilização

Cada chave pode fazer 120 pedidos por minuto, contados em conjunto por todos os sistemas que a usem. Acima disso a API responde 429 rate_limited com o cabeçalho Retry-After: 60.

  • Peça intervalos curtos de disponibilidade e guarde o resultado do seu lado durante alguns minutos.
  • Locais, profissionais e serviços mudam raramente; não precisa de os pedir em cada interação.
  • Ao receber 429, espere o tempo indicado em Retry-After antes de tentar de novo.

Locais

GET/localsLocais da organização.

Não tem parâmetros. Devolve todos os locais da organização, incluindo os que não aceitam marcação online.

Campos da resposta

CampoTipoDescrição
idinteiroIdentificador do local, usado em local_id noutros pedidos.
nametextoNome do local.
slugtextoIdentificador legível usado nos URLs públicos.
virtualbooleanoVerdadeiro para locais de teleconsulta, sem morada física.
public_booking_enabledbooleanoSe o local aceita marcações pelo portal e pelo widget.
public_phonetexto ou nullTelefone público.
public_emailtexto ou nullEmail público.
public_addresstexto ou nullMorada pública.
public_website_urltexto ou nullSite do local.
Pedido
curl -H "Authorization: Bearer $MEDORA_KEY" \
  https://api.medora.pt/public/api/v1/locals
Resposta 200
{
  "locals": [
    {
      "id": 12,
      "name": "Clínica São João",
      "slug": "clinica-sao-joao",
      "virtual": false,
      "public_booking_enabled": true,
      "public_phone": "+351210000000",
      "public_email": "geral@clinica.pt",
      "public_address": "Rua Central 1, Porto",
      "public_website_url": "https://clinica.pt"
    }
  ]
}

Profissionais

GET/professionalsProfissionais com horário configurado.

Parâmetros

ParâmetroObrigatórioDescrição
local_idnãoLimita aos profissionais com horário nesse local. Sem este parâmetro, devolve os de todos os locais da organização. Responde 404 se o local não pertencer à organização.

Campos da resposta

CampoTipoDescrição
idinteiroIdentificador do profissional, usado em provider_id nas disponibilidades.
nametextoNome.
titletexto ou nullTítulo (por exemplo «Dra.»).
display_nametextoTítulo e nome, prontos a mostrar.
professional_titletexto ou nullDesignação profissional (por exemplo «Médica Dentista»).
disciplineslista de textoCódigos estáveis das disciplinas que exerce (por exemplo psychology, dentistry).
licenseslistaCédulas profissionais: ordem (código), ordem_label (nome da ordem) e license_number.
local_idslista de inteiroLocais onde tem horário.
Pedido
curl -H "Authorization: Bearer $MEDORA_KEY" \
  "https://api.medora.pt/public/api/v1/professionals?local_id=12"
Resposta 200
{
  "professionals": [
    {
      "id": 7,
      "name": "Ana Silva",
      "title": "Dra.",
      "display_name": "Dra. Ana Silva",
      "professional_title": "Médica Dentista",
      "disciplines": ["dentistry"],
      "licenses": [
        { "ordem": "omd", "ordem_label": "Ordem dos Médicos Dentistas", "license_number": "12345" }
      ],
      "local_ids": [12, 15]
    }
  ]
}

Serviços

GET/servicesServiços ativos, marcáveis online ou não.

Parâmetros

ParâmetroObrigatórioDescrição
local_idnãoLimita aos serviços desse local. Responde 404 se o local não pertencer à organização.

Campos da resposta

CampoTipoDescrição
idinteiroIdentificador do serviço, usado em service_id nas disponibilidades.
local_idinteiroLocal a que o serviço pertence.
nametextoNome do serviço.
descriptiontexto ou nullDescrição.
duration_minutesinteiroDuração de uma consulta deste serviço.
unit_pricenúmeroPreço líquido, sem IVA.
iva_ratetextoTaxa de IVA aplicada (por exemplo IVA6, IVA23, IVA0).
pricenúmeroPreço bruto, o valor que o utente paga.
bookable_onlinebooleanoSe aparece no portal e no widget. Serviços não marcáveis online continuam a poder ser lidos aqui.
Pedido
curl -H "Authorization: Bearer $MEDORA_KEY" \
  "https://api.medora.pt/public/api/v1/services?local_id=12"
Resposta 200
{
  "services": [
    {
      "id": 31,
      "local_id": 12,
      "name": "Consulta de avaliação",
      "description": null,
      "duration_minutes": 30,
      "unit_price": 40,
      "iva_rate": "IVA6",
      "price": 42.4,
      "bookable_online": true
    }
  ]
}

Disponibilidades

GET/availabilityHorários marcáveis num intervalo de datas.

Devolve os horários em que é possível marcar, já com a duração, os horários de trabalho, os bloqueios, as ausências, as consultas existentes e o limite de sobreposição aplicados. Usa o mesmo motor do widget de marcação.

Parâmetros

ParâmetroPredefiniçãoDescrição
fromhojePrimeiro dia, YYYY-MM-DD, inclusive.
tofrom + 7 diasÚltimo dia, inclusive. Tem de ser igual ou posterior a from e no máximo 31 dias depois.
local_idtodosLimita a um local. Responde 404 se não pertencer à organização.
provider_idtodosLimita a um profissional. Repetível (provider_id=7&provider_id=9); identificadores desconhecidos são ignorados.
service_idServiço a marcar. Define a duração e restringe ao local do serviço. Responde 404 se não existir ou estiver inativo.
duration_minutes30Duração em minutos, de 5 a 480. Ignorado quando há service_id.

Campos da resposta

CampoTipoDescrição
from, todataIntervalo efetivamente calculado.
timezonetextoSempre Europe/Lisbon.
duration_minutesinteiroDuração usada para calcular os horários.
service_idinteiro ou nullServiço pedido, se houver.
slotslistaHorários marcáveis, ordenados por início: local_id, provider_id, start e end.
professionalslistaProfissionais considerados: id e display_name.
localslistaLocais considerados: id e name.
Pedido
curl -H "Authorization: Bearer $MEDORA_KEY" \
  "https://api.medora.pt/public/api/v1/availability?service_id=31&from=2026-09-15&to=2026-09-22"
Resposta 200
{
  "from": "2026-09-15",
  "to": "2026-09-22",
  "timezone": "Europe/Lisbon",
  "duration_minutes": 30,
  "service_id": 31,
  "slots": [
    { "local_id": 12, "provider_id": 7, "start": "2026-09-15T09:00:00+01:00", "end": "2026-09-15T09:30:00+01:00" },
    { "local_id": 12, "provider_id": 7, "start": "2026-09-15T09:15:00+01:00", "end": "2026-09-15T09:45:00+01:00" }
  ],
  "professionals": [{ "id": 7, "display_name": "Dra. Ana Silva" }],
  "locals": [{ "id": 12, "name": "Clínica São João" }]
}
  • Os horários começam de 15 em 15 minutos e sobrepõem-se; escolha um.
  • Horários já iniciados nunca são devolvidos e dias anteriores a hoje não são calculados.
  • Não há antecedência mínima: a clínica decide as suas regras.
  • Sem service_id, a duração vem de duration_minutes e não é considerado nenhum serviço.

Erros

Os erros têm sempre a mesma forma. O código é estável e serve para o seu sistema decidir; a mensagem é para pessoas e pode mudar. O campo param só aparece em invalid_parameter e indica o parâmetro inválido.

Resposta 422
{
  "error": {
    "code": "invalid_parameter",
    "message": "O parâmetro from tem de ser uma data YYYY-MM-DD",
    "param": "from"
  }
}
EstadoCódigoQuando acontece
401missing_api_keyFalta o cabeçalho Authorization ou tem outro formato.
401invalid_api_keyChave desconhecida ou revogada.
403organization_lockedA organização não tem subscrição ativa.
404not_foundRota inexistente, ou local, profissional ou serviço que não existe nesta organização.
405method_not_allowedMétodo diferente de GET.
422invalid_parameterParâmetro com formato ou valor inválido; param indica qual.
422invalid_rangeto anterior a from, ou intervalo superior a 31 dias.
429rate_limitedMais de 120 pedidos num minuto; volte a tentar após Retry-After.
500internal_errorErro do lado da Medora. Tente de novo mais tarde; se persistir, contacte o apoio.