Desenvolvedores

A API da Meevia

Leia a agenda, marque agendamentos e consulte o catálogo e a ficha do paciente a partir do seu próprio sistema. Esta página leva você da primeira chave à primeira resposta com sucesso.

Nesta página

O que é e para quem serve

A API abre, para o seu sistema, as partes da clínica que fazem sentido automatizar: a agenda, o catálogo de profissionais e procedimentos, e a ficha básica do paciente. O que você faz por ela segue as mesmas regras que valem para quem opera a clínica dentro da plataforma.

É HTTP com JSON, sem biblioteca obrigatória e sem SDK para instalar. Se o seu ambiente sabe fazer uma requisição e ler uma resposta, ele já sabe conversar com a Meevia.

Casos comuns

  • Um site ou aplicativo próprio onde o paciente escolhe o horário e marca sozinho.
  • Um sistema que a clínica já usa e que precisa enxergar a agenda do dia sem ninguém digitar duas vezes.
  • Automação interna: um painel próprio, um relatório, uma rotina que confirma presença.

O que a clínica precisa ter

O acesso à API faz parte do plano da clínica. Se o plano atual não tiver esse acesso, a primeira chamada já volta recusada, e isso nenhuma mudança no seu código resolve: é conversa com o time comercial.

O que ainda não está aqui

Esta versão lê e escreve agenda, e lê catálogo e paciente. A Meevia avisar o seu sistema quando algo acontece na clínica, cobrança e pagamento não fazem parte dela.

Como obter uma chave

A chave nasce no painel de desenvolvedor, que fica em developers.meevia.app e tem casca própria, fora do sistema da clínica. É assim porque quem integra muitas vezes não é da clínica. Não existe caminho pela API para criar uma chave.

Abrir o painel de desenvolvedor

  1. 1Abra o painel de desenvolvedorO endereço é developers.meevia.app. Quem já trabalha dentro do sistema da clínica chega pelo mesmo lugar por Integrações, no card de API e Webhooks, que é uma porta para o painel.
  2. 2Entre com a sua conta, ou peça um conviteQuem administra a clínica entra direto. Quem é de fora precisa ser convidado: na aba Acessos, quem administra o painel convida pelo e-mail e escolhe entre Somente ver, que consulta, e Pode administrar, que também emite chave. Pedir o convite é melhor que pedir a chave pronta, porque chave que viaja por mensagem já vazou.
  3. 3Escolha a clínicaO painel atende todas as clínicas em que você tem acesso, e a escolhida no alto é a dona de tudo que as abas mostram. Trabalhando para várias, é aqui que você troca.
  4. 4Na aba Chaves, crie uma chave novaDê um nome que diga onde ela vai ser usada. Seis meses depois, esse nome é a única forma de revogar a chave certa sem derrubar a integração errada.
  5. 5Escolha o modo e os escoposO modo decide se a chave mexe na clínica de verdade ou no ambiente de teste. Os escopos decidem o que ela pode fazer. Marque só o que a integração precisa.
  6. 6Copie a chave antes de fechar a janelaA chave completa aparece uma única vez, na emissão. A Meevia guarda o pedaço que a identifica e nunca a parte secreta, então fechar sem copiar não tem recuperação: revogue a chave e emita outra.

Uma chave, uma clínica

A chave vale para a clínica que a emitiu, e só para ela. Se você atende várias clínicas, são várias chaves, cada uma guardada separada e trocável sem mexer nas outras. Não existe chave que enxergue mais de uma clínica.

Onde guardar

Guarde a chave no servidor, no cofre de variáveis do seu ambiente. Chave dentro do código de um aplicativo ou de uma página é chave publicada, porque qualquer pessoa consegue ler.

Quando revogar

Revogar vale na hora e não tem volta: a chave para de funcionar e as chamadas dela passam a ser recusadas. Faça isso ao trocar de fornecedor, ao desligar uma integração e na menor suspeita de vazamento.

Quem pode o quê

O papel Pode administrar no painel abre as duas coisas que mexem: emitir e revogar chave, e reiniciar o ambiente de teste. Ele se recebe por convite e vale por clínica, então quem vem de fora faz as duas sem depender de ninguém. Reiniciar tem um segundo caminho: quem administra a clínica também reinicia. Quem só tem Somente ver enxerga as chaves e não emite nenhuma; o painel avisa isso na tela, em vez de esconder o botão.

Autenticação

Toda chamada vai autenticada. A chave viaja no cabeçalho de autorização, no esquema que o exemplo mostra, e é só isso: não há login, sessão nem token que vence no meio do caminho.

Requisiçãobash
curl -X GET \
  -H "Authorization: Bearer mv_live_a1b2c3d49f8e7d6c5b4a39281706f5e4d3c2b1a0" \
  "https://wnricobmssysbwfhbmsm.supabase.co/functions/v1/api-v1/v1/practitioners"

A chave é um valor único. É ele inteiro que viaja no cabeçalho. Ela tem três pedaços colados: o prefixo diz em que modo a chave está, o pedaço do meio a identifica e é o que aparece na aba Chaves do painel, e o último é a parte secreta. Essa última a Meevia nunca guarda em claro, então nem o suporte consegue ler a sua. Envie sempre a chave completa: mandar só a parte secreta é o engano que mais rende recusa de autorização.

Chave ausente, escrita errada, revogada ou vencida recebem todas a mesma recusa, sem dizer qual dos quatro casos foi. É de propósito. Dizer qual é dar pista a quem está tentando adivinhar.

Dois modos

Produção

mv_live_

Mexe na clínica de verdade. Um agendamento criado por aqui aparece na agenda da recepção e dispara o que a clínica configurou disparar.

Teste

mv_test_

Mexe num ambiente separado, com dados de mentira, que existe só para você experimentar. Nada do que acontece ali encosta na clínica real.

O modo é decidido na emissão e não muda depois. Na prática você mantém as duas chaves e troca a variável de ambiente para virar de um lado para o outro.

A chave que aparece nos exemplos é inventada e não funciona em lugar nenhum: ela está ali só para você reconhecer o formato da sua. Repare que o prefixo dela é de produção. Fazendo o passo a passo no modo de teste, como esta página recomenda, a sua vai começar diferente.

Escopos

Cada escopo abre uma parte da API, e a chave só faz o que os escopos dela permitem. A falta de um escopo aparece na primeira chamada que precisa dele, não na emissão.

appointments:read

Ler a agenda

Listar os agendamentos de um período e abrir um deles.

appointments:write

Mexer na agenda

Criar agendamento, mudar a situação de um e cancelar.

catalog:read

Ler o catálogo

Profissionais, procedimentos e os horários livres de um dia.

patients:read

Ler paciente

Abrir a ficha básica de um paciente que você já conhece pelo identificador. Não existe busca aberta por nome nesta versão.

Conceda o mínimo. Uma integração que só mostra a agenda num telão não precisa poder marcar agendamento. E uma chave enxuta é um estrago pequeno no dia em que ela vazar.

Escopo não se edita depois da emissão. Ampliar é emitir uma chave nova com o que falta, trocar no seu ambiente e revogar a antiga.

Ambiente de teste

A clínica ganha um ambiente de teste só dela, isolado da clínica real. A primeira chave de teste emitida já cria esse ambiente, então não há nada a provisionar nem a pedir.

O que já vem dentro

Vem um paciente, um procedimento e um profissional de exemplo. Nenhum deles existe na clínica de verdade. As listas de profissionais e de procedimentos devolvem os identificadores desses dois, então consultar catálogo e horário livre funciona na primeira sessão. Cadastro é da clínica: pela API, o que se cria é agendamento.

O que não dá para testar aqui

A API escreve em três lugares: criar agendamento, mudar a situação de um e cancelar. Hoje nenhum dos três dá para exercitar aqui, e o motivo vem em cadeia. Criar precisa do identificador do paciente, que não aparece na tela nem volta de nenhuma consulta, porque não há listagem de pacientes. Mudar a situação e cancelar precisam do identificador de um agendamento, e ele só existiria se criar tivesse funcionado: a lista de agendamentos nasce vazia aqui. Quem precisa testar escrita faz isso na clínica de verdade, com o cuidado que isso pede: marque num horário vazio e cancele assim que confirmar que funcionou.

Como reiniciar

A aba Ambiente de teste, no painel, tem um botão que descarta o ambiente atual e entrega outro, limpo, com os mesmos dados iniciais. As chaves de teste já emitidas continuam valendo: elas estão ligadas à clínica, não ao ambiente que foi descartado.

Reiniciar apaga tudo que você criou ali, e não há desfazer. É o que você quer quando um teste sujou o ambiente, e é o que você não quer no meio de uma bateria de testes.

Reiniciar é de quem tem Pode administrar no painel ou administra a clínica. Quem vem de fora com esse papel reinicia sozinho, sem ter a quem pedir.

O endereço da API

Toda chamada sai para o mesmo endereço, e ele é um só para todo mundo. Não existe um endereço por clínica: quem separa uma clínica da outra é a chave, nunca a URL.

Exemplotext
https://wnricobmssysbwfhbmsm.supabase.co/functions/v1/api-v1

Repare que há um pedaço que parece repetido no meio do caminho. Está certo assim. Um deles é da infraestrutura que hospeda a API e o outro é da versão da nossa. Copie o endereço exatamente como aparece aqui; tirar a parte que parece sobrando devolve uma resposta de endereço inexistente.

Primeira chamada, do zero à primeira resposta

Leva cinco minutos, contando do login. Faça no modo de teste: se algo sair diferente do esperado, quem paga é um paciente de mentira.

  1. 1Emita uma chave de testeSiga o caminho descrito em Como obter uma chave, marcando o modo de teste e o escopo de leitura do catálogo. Copie a chave.
  2. 2Guarde a chave numa variável de ambienteAssim a chave não fica no histórico do terminal nem colada no meio do comando que você vai mandar para um colega.
  3. 3Peça a lista de profissionaisÉ a chamada mais simples daqui: não recebe parâmetro nenhum, e o ambiente de teste já vem com um profissional dentro. Se ela responder, sua chave, seu escopo e seu endereço estão certos de uma vez só.
  4. 4Confira o que voltouUma resposta bem-sucedida traz o profissional de teste. Daí em diante a receita é a mesma para o resto: muda o endereço, o cabeçalho continua igual.

Troque a chave de exemplo pela variável em que você guardou a sua no passo anterior, ou pela chave inteira. A que aparece aqui é inventada, e volta recusada.

Requisiçãobash
curl -X GET \
  -H "Authorization: Bearer mv_live_a1b2c3d49f8e7d6c5b4a39281706f5e4d3c2b1a0" \
  "https://wnricobmssysbwfhbmsm.supabase.co/functions/v1/api-v1/v1/practitioners"
Código de status 200
Respostajson
{
  "data": [
    {
      "id": "1f6d5c84-3b92-4a07-8e15-d6c3f9b204ae",
      "name": "Dra. Helena Costa",
      "specialty": "Dermatologia"
    }
  ]
}

Se não veio o que você esperava

Compare o que voltou com o catálogo de recusas desta página, que diz o que aconteceu e o que fazer em cada caso. Vale olhar também a aba Requisições do painel, que mostra o endereço chamado, a resposta e o horário de cada chamada recebida. Ela guarda só esse resumo, nunca o conteúdo enviado.

O formato das respostas

As respostas vêm embrulhadas sempre do mesmo jeito, e cada chamada mostra o formato do que ela devolve. Programe contra o embrulho e ignore o que não conhece: com o tempo aparecem informações novas, e a integração que ignora o que não espera sobrevive a isso sem precisar de você.

Os embrulhos

  • Um registro só, dentro do embrulho padrão.data
  • Uma lista, dentro do mesmo embrulho.data
  • Uma lista em páginas, acompanhada do marcador que pede a próxima.datanext_cursorPode vir sem valor
  • Esta resposta foge do padrão das outras: ela traz o dia consultado ao lado dos horários.dateslots
  • O formato de toda recusa, em qualquer chamada.error

Listas longas

Listas vêm em páginas. A resposta traz um marcador de continuação: enquanto ele vier preenchido, mande esse mesmo marcador na chamada seguinte para pegar a próxima página. Quando vier sem valor, acabou. Não tente adivinhar o total nem montar a paginação por conta própria.

O que cada resposta carrega

Agendamento

CampoTipo
iduuid
statusstring
starts_atdatetime
ends_at

Pode vir sem valor

datetime
patient_id

Pode vir sem valor

uuid
professional_id

Pode vir sem valor

uuid
procedure_idsarray<uuid>
created_atdatetime

Paciente

CampoTipo
iduuid
namestring
phone

Pode vir sem valor

string
email

Pode vir sem valor

string

Profissional

CampoTipo
iduuid
name

Pode vir sem valor

string
specialty

Pode vir sem valor

string

Procedimento

CampoTipo
iduuid
namestring
pricenumber
duration_minutesinteger

Horário livre

CampoTipo
timestring
professional_iduuid

Recusa

CampoTipo
codestring
messagestring
details

Nem sempre vem

object

As chamadas

Cada uma traz o que recebe, o que devolve e um exemplo pronto para colar no terminal. Troque os identificadores do exemplo pelos seus.

MétodoGETEndereço/v1/appointments

Lista os agendamentos de um período, em páginas.

Escopo exigido
appointments:readLer a agenda
Repetição
Não se aplica
Resposta
Agendamentodatanext_cursorPode vir sem valor
ParâmetroTipoOnde vai
fromOpcional
Formato
YYYY-MM-DD
Se você não enviar
o dia de hoje, no fuso da clínica
datequery
toOpcional
Formato
YYYY-MM-DD
Se você não enviar
trinta dias depois da data inicial
datequery
statusOpcional
Valores aceitos
pre_agendadoagendadoconfirmadoem_esperacanceladorealizadofaltou
stringquery
professional_idOpcionaluuidquery
limitOpcional
Se você não enviar
50
Máximo
200
integerquery
cursorOpcional
Se você não enviar
o marcador de continuação que veio na página anterior
stringquery
Requisição · Deu certobash
curl -X GET \
  -H "Authorization: Bearer mv_live_a1b2c3d49f8e7d6c5b4a39281706f5e4d3c2b1a0" \
  "https://wnricobmssysbwfhbmsm.supabase.co/functions/v1/api-v1/v1/appointments?from=2026-10-01&to=2026-10-31&limit=2"
Código de status 200
Resposta · Deu certojson
{
  "data": [
    {
      "id": "9c1f4b2a-7e83-4d61-b0a5-2f8c6d31e4a7",
      "status": "agendado",
      "starts_at": "2026-10-03T14:30:00",
      "ends_at": "2026-10-03T15:30:00",
      "patient_id": "4d7e2c19-5a6b-4f30-9e81-c2a5b7d04f63",
      "professional_id": "1f6d5c84-3b92-4a07-8e15-d6c3f9b204ae",
      "procedure_ids": [
        "2a9f8b31-6c74-4e05-9d28-a3f1e7b5c06d"
      ],
      "created_at": "2026-09-28T11:04:22.517Z"
    },
    {
      "id": "5e0b7a94-1d62-4c38-97af-8b41d2e6c03f",
      "status": "confirmado",
      "starts_at": "2026-10-03T16:00:00",
      "ends_at": "2026-10-03T16:45:00",
      "patient_id": "4d7e2c19-5a6b-4f30-9e81-c2a5b7d04f63",
      "professional_id": "1f6d5c84-3b92-4a07-8e15-d6c3f9b204ae",
      "procedure_ids": [
        "2a9f8b31-6c74-4e05-9d28-a3f1e7b5c06d"
      ],
      "created_at": "2026-09-28T11:04:22.517Z"
    }
  ],
  "next_cursor": "MjAyNi0xMC0wM3wxNDozMDowMHw5YzFmNGIyYS03ZTgzLTRkNjEtYjBhNS0yZjhjNmQzMWU0YTc="
}
Requisição · Pedindo a próxima páginabash
curl -X GET \
  -H "Authorization: Bearer mv_live_a1b2c3d49f8e7d6c5b4a39281706f5e4d3c2b1a0" \
  "https://wnricobmssysbwfhbmsm.supabase.co/functions/v1/api-v1/v1/appointments?from=2026-10-01&to=2026-10-31&limit=2&cursor=MjAyNi0xMC0wM3wxNDozMDowMHw5YzFmNGIyYS03ZTgzLTRkNjEtYjBhNS0yZjhjNmQzMWU0YTc%3D"
Código de status 200
Resposta · Pedindo a próxima páginajson
{
  "data": [],
  "next_cursor": null
}

MétodoPOSTEndereço/v1/appointments

Marca um agendamento para um paciente, com um profissional, num horário.

Escopo exigido
appointments:writeMexer na agenda
Repetição
Exige valor de repetição
Resposta
Agendamentodata
ParâmetroTipoOnde vai
Idempotency-KeyObrigatóriostringheader
patient_idObrigatóriouuidbody
professional_idObrigatóriouuidbody
procedure_idsObrigatório
Mínimo de itens
1
array<uuid>body
starts_atObrigatório
Formato
YYYY-MM-DDTHH:MM[:SS][Z|±HH:MM]
datetimebody
statusOpcional
Valores aceitos
pre_agendadoagendado
Se você não enviar
pre_agendado
stringbody
Requisição · Deu certobash
curl -X POST \
  -H "Authorization: Bearer mv_live_a1b2c3d49f8e7d6c5b4a39281706f5e4d3c2b1a0" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7f3c05a1-9b24-4e6d-8c17-0a5f3d92b4e8" \
  -d '{
  "patient_id": "4d7e2c19-5a6b-4f30-9e81-c2a5b7d04f63",
  "professional_id": "1f6d5c84-3b92-4a07-8e15-d6c3f9b204ae",
  "procedure_ids": [
    "2a9f8b31-6c74-4e05-9d28-a3f1e7b5c06d"
  ],
  "starts_at": "2026-10-03T14:30:00",
  "status": "agendado"
}' \
  "https://wnricobmssysbwfhbmsm.supabase.co/functions/v1/api-v1/v1/appointments"
Código de status 201
Resposta · Deu certojson
{
  "data": {
    "id": "9c1f4b2a-7e83-4d61-b0a5-2f8c6d31e4a7",
    "status": "agendado",
    "starts_at": "2026-10-03T14:30:00",
    "ends_at": "2026-10-03T15:30:00",
    "patient_id": "4d7e2c19-5a6b-4f30-9e81-c2a5b7d04f63",
    "professional_id": "1f6d5c84-3b92-4a07-8e15-d6c3f9b204ae",
    "procedure_ids": [
      "2a9f8b31-6c74-4e05-9d28-a3f1e7b5c06d"
    ],
    "created_at": "2026-09-28T11:04:22.517Z"
  }
}
Requisição · Sem o valor de repetiçãobash
curl -X POST \
  -H "Authorization: Bearer mv_live_a1b2c3d49f8e7d6c5b4a39281706f5e4d3c2b1a0" \
  -H "Content-Type: application/json" \
  -d '{
  "patient_id": "4d7e2c19-5a6b-4f30-9e81-c2a5b7d04f63",
  "professional_id": "1f6d5c84-3b92-4a07-8e15-d6c3f9b204ae",
  "procedure_ids": [
    "2a9f8b31-6c74-4e05-9d28-a3f1e7b5c06d"
  ],
  "starts_at": "2026-10-03T14:30:00"
}' \
  "https://wnricobmssysbwfhbmsm.supabase.co/functions/v1/api-v1/v1/appointments"
Código de status 422
Resposta · Sem o valor de repetiçãojson
{
  "error": {
    "code": "validation_failed",
    "message": "Cabeçalho Idempotency-Key é obrigatório para criar agendamento."
  }
}

MétodoGETEndereço/v1/appointments/{id}

Abre um agendamento específico.

Escopo exigido
appointments:readLer a agenda
Repetição
Não se aplica
Resposta
Agendamentodata
ParâmetroTipoOnde vai
idObrigatóriouuidpath
Requisição · Deu certobash
curl -X GET \
  -H "Authorization: Bearer mv_live_a1b2c3d49f8e7d6c5b4a39281706f5e4d3c2b1a0" \
  "https://wnricobmssysbwfhbmsm.supabase.co/functions/v1/api-v1/v1/appointments/9c1f4b2a-7e83-4d61-b0a5-2f8c6d31e4a7"
Código de status 200
Resposta · Deu certojson
{
  "data": {
    "id": "9c1f4b2a-7e83-4d61-b0a5-2f8c6d31e4a7",
    "status": "agendado",
    "starts_at": "2026-10-03T14:30:00",
    "ends_at": "2026-10-03T15:30:00",
    "patient_id": "4d7e2c19-5a6b-4f30-9e81-c2a5b7d04f63",
    "professional_id": "1f6d5c84-3b92-4a07-8e15-d6c3f9b204ae",
    "procedure_ids": [
      "2a9f8b31-6c74-4e05-9d28-a3f1e7b5c06d"
    ],
    "created_at": "2026-09-28T11:04:22.517Z"
  }
}

MétodoPATCHEndereço/v1/appointments/{id}/status

Muda a situação de um agendamento, dentro do que é permitido.

Escopo exigido
appointments:writeMexer na agenda
Repetição
Seguro repetir
Resposta
Agendamentodata
ParâmetroTipoOnde vai
idObrigatóriouuidpath
statusObrigatório
Valores aceitos
agendadoconfirmadocancelado
stringbody
Requisição · Deu certobash
curl -X PATCH \
  -H "Authorization: Bearer mv_live_a1b2c3d49f8e7d6c5b4a39281706f5e4d3c2b1a0" \
  -H "Content-Type: application/json" \
  -d '{
  "status": "confirmado"
}' \
  "https://wnricobmssysbwfhbmsm.supabase.co/functions/v1/api-v1/v1/appointments/9c1f4b2a-7e83-4d61-b0a5-2f8c6d31e4a7/status"
Código de status 200
Resposta · Deu certojson
{
  "data": {
    "id": "9c1f4b2a-7e83-4d61-b0a5-2f8c6d31e4a7",
    "status": "confirmado",
    "starts_at": "2026-10-03T14:30:00",
    "ends_at": "2026-10-03T15:30:00",
    "patient_id": "4d7e2c19-5a6b-4f30-9e81-c2a5b7d04f63",
    "professional_id": "1f6d5c84-3b92-4a07-8e15-d6c3f9b204ae",
    "procedure_ids": [
      "2a9f8b31-6c74-4e05-9d28-a3f1e7b5c06d"
    ],
    "created_at": "2026-09-28T11:04:22.517Z"
  }
}
Requisição · Mudança de situação recusadabash
curl -X PATCH \
  -H "Authorization: Bearer mv_live_a1b2c3d49f8e7d6c5b4a39281706f5e4d3c2b1a0" \
  -H "Content-Type: application/json" \
  -d '{
  "status": "realizado"
}' \
  "https://wnricobmssysbwfhbmsm.supabase.co/functions/v1/api-v1/v1/appointments/9c1f4b2a-7e83-4d61-b0a5-2f8c6d31e4a7/status"
Código de status 422
Resposta · Mudança de situação recusadajson
{
  "error": {
    "code": "status_transition_not_allowed",
    "message": "Transição de status não permitida por esta API.",
    "details": {
      "from": "agendado",
      "to": "realizado"
    }
  }
}

MétodoPOSTEndereço/v1/appointments/{id}/cancel

Cancela um agendamento.

Escopo exigido
appointments:writeMexer na agenda
Repetição
Seguro repetir
Resposta
Agendamentodata
ParâmetroTipoOnde vai
idObrigatóriouuidpath
Requisição · Deu certobash
curl -X POST \
  -H "Authorization: Bearer mv_live_a1b2c3d49f8e7d6c5b4a39281706f5e4d3c2b1a0" \
  "https://wnricobmssysbwfhbmsm.supabase.co/functions/v1/api-v1/v1/appointments/9c1f4b2a-7e83-4d61-b0a5-2f8c6d31e4a7/cancel"
Código de status 200
Resposta · Deu certojson
{
  "data": {
    "id": "9c1f4b2a-7e83-4d61-b0a5-2f8c6d31e4a7",
    "status": "cancelado",
    "starts_at": "2026-10-03T14:30:00",
    "ends_at": "2026-10-03T15:30:00",
    "patient_id": "4d7e2c19-5a6b-4f30-9e81-c2a5b7d04f63",
    "professional_id": "1f6d5c84-3b92-4a07-8e15-d6c3f9b204ae",
    "procedure_ids": [
      "2a9f8b31-6c74-4e05-9d28-a3f1e7b5c06d"
    ],
    "created_at": "2026-09-28T11:04:22.517Z"
  }
}

MétodoGETEndereço/v1/patients/{id}

Abre a ficha básica de um paciente.

Escopo exigido
patients:readLer paciente
Repetição
Não se aplica
Resposta
Pacientedata
ParâmetroTipoOnde vai
idObrigatóriouuidpath
Requisição · Deu certobash
curl -X GET \
  -H "Authorization: Bearer mv_live_a1b2c3d49f8e7d6c5b4a39281706f5e4d3c2b1a0" \
  "https://wnricobmssysbwfhbmsm.supabase.co/functions/v1/api-v1/v1/patients/4d7e2c19-5a6b-4f30-9e81-c2a5b7d04f63"
Código de status 200
Resposta · Deu certojson
{
  "data": {
    "id": "4d7e2c19-5a6b-4f30-9e81-c2a5b7d04f63",
    "name": "Ana Ribeiro",
    "phone": "+5511987654321",
    "email": "ana.ribeiro@example.com"
  }
}

MétodoGETEndereço/v1/practitioners

Lista os profissionais da clínica.

Escopo exigido
catalog:readLer o catálogo
Repetição
Não se aplica
Resposta
Profissionaldata

Esta chamada não recebe parâmetros.

Requisição · Deu certobash
curl -X GET \
  -H "Authorization: Bearer mv_live_a1b2c3d49f8e7d6c5b4a39281706f5e4d3c2b1a0" \
  "https://wnricobmssysbwfhbmsm.supabase.co/functions/v1/api-v1/v1/practitioners"
Código de status 200
Resposta · Deu certojson
{
  "data": [
    {
      "id": "1f6d5c84-3b92-4a07-8e15-d6c3f9b204ae",
      "name": "Dra. Helena Costa",
      "specialty": "Dermatologia"
    }
  ]
}

MétodoGETEndereço/v1/procedures

Lista os procedimentos do catálogo.

Escopo exigido
catalog:readLer o catálogo
Repetição
Não se aplica
Resposta
Procedimentodata

Esta chamada não recebe parâmetros.

Requisição · Deu certobash
curl -X GET \
  -H "Authorization: Bearer mv_live_a1b2c3d49f8e7d6c5b4a39281706f5e4d3c2b1a0" \
  "https://wnricobmssysbwfhbmsm.supabase.co/functions/v1/api-v1/v1/procedures"
Código de status 200
Resposta · Deu certojson
{
  "data": [
    {
      "id": "2a9f8b31-6c74-4e05-9d28-a3f1e7b5c06d",
      "name": "Limpeza de pele profunda",
      "price": 280,
      "duration_minutes": 60
    }
  ]
}

MétodoGETEndereço/v1/availability

Mostra os horários livres de um dia, e dá para restringir a um profissional ou a um procedimento.

Escopo exigido
catalog:readLer o catálogo
Repetição
Não se aplica
Resposta
Horário livredateslots
ParâmetroTipoOnde vai
dateObrigatório
Formato
YYYY-MM-DD
datequery
professional_idOpcionaluuidquery
procedure_idOpcionaluuidquery
Requisição · Deu certobash
curl -X GET \
  -H "Authorization: Bearer mv_live_a1b2c3d49f8e7d6c5b4a39281706f5e4d3c2b1a0" \
  "https://wnricobmssysbwfhbmsm.supabase.co/functions/v1/api-v1/v1/availability?date=2026-10-03&procedure_id=2a9f8b31-6c74-4e05-9d28-a3f1e7b5c06d"
Código de status 200
Resposta · Deu certojson
{
  "date": "2026-10-03",
  "slots": [
    {
      "time": "09:00",
      "professional_id": "1f6d5c84-3b92-4a07-8e15-d6c3f9b204ae"
    },
    {
      "time": "10:00",
      "professional_id": "1f6d5c84-3b92-4a07-8e15-d6c3f9b204ae"
    }
  ]
}

Repetir sem duplicar

A rede cai no meio da chamada, o tempo estoura, e você fica sem saber se o agendamento foi criado. Repetir por conta própria pode marcar o mesmo paciente duas vezes.

Por isso toda criação viaja com um valor de repetição inventado por você, um para cada operação. Se ele chegar de novo com o mesmo conteúdo, a Meevia devolve a resposta que já tinha dado, sem processar outra vez.

Idempotency-Key

Como escolher esse valor

Gere um valor único por operação (um identificador aleatório serve) e guarde esse valor junto da sua tentativa, para reusar exatamente o mesmo na hora de repetir. Gerar um novo a cada tentativa é o mesmo que não ter proteção nenhuma.

A resposta guardada volta como veio, inclusive quando ela foi uma recusa. Repetir com o valor de uma tentativa que deu errado devolve o mesmo erro, não uma tentativa nova.

Reusar o mesmo valor com conteúdo diferente é recusado, e essa recusa costuma denunciar duas operações distintas compartilhando o mesmo valor. A mesma resposta aparece quando uma chamada gêmea ainda está em andamento, e aí esperar alguns instantes e repetir resolve.

O valor vale por um dia. Depois disso ele é esquecido, e uma repetição volta a processar de verdade.

Uma tentativa que ficou sem resposta é dada por perdida depois de poucos minutos, e a chamada seguinte com aquele valor assume o lugar. Assim uma requisição que morreu no meio não trava você até o dia seguinte.

Minutos de espera antes de repetir uma tentativa sem resposta
5

O que acontece ao repetir cada chamada

Não se aplica

É leitura, e leitura não muda nada ao ser repetida.

Exige valor de repetição

Sem ele a chamada é recusada. É a proteção contra marcar o mesmo paciente duas vezes quando a rede falha no meio.

Seguro repetir

Repetir leva ao mesmo lugar: pedir a situação em que o agendamento já está devolve o agendamento como ele está. Não é preciso enviar valor de repetição aqui.

Limites de uso

Cada chave tem o próprio teto de chamadas por minuto. É por chave e não por clínica. Duas integrações na mesma clínica não disputam o mesmo limite, e uma que disparou chamadas demais não derruba a outra.

Chamadas por minuto, em cada chave
120

A contagem zera na virada de cada minuto do relógio, e não numa janela que desliza. Na prática, dois blocos disparados na virada caem em minutos diferentes, então um pico curto pode passar mesmo somando acima do teto. Não é folga com que dê para contar: o que sustenta uma integração é o ritmo médio.

Quando estourar, a resposta traz num cabeçalho próprio, e não no corpo, quantos segundos esperar. Respeite esse número em vez de tentar de novo na hora. Se isso virar rotina, o problema não é o teto: espace as chamadas, guarde o que muda pouco (o catálogo muda pouco) e evite ficar perguntando em laço.

Retry-After

Mudanças de situação permitidas

A API aceita um conjunto fechado de mudanças, e a tabela mostra quais: cada situação de origem tem os destinos que ela permite, e o que não está na tabela é recusado. Concluir e registrar falta ficam fora por decisão de produto. As duas geram venda, cobrança e consumo de sessão de pacote. Continuam na mão de quem opera a clínica.

Situação atualPode mudar para
pre_agendadoagendadoconfirmadocancelado
agendadoconfirmadocancelado
confirmadocancelado
em_esperacancelado

As situações

pre_agendado
Marcado, mas ainda sem confirmação de ninguém. É a situação em que um agendamento novo nasce quando você não pede outra.
agendado
Está na agenda e a clínica conta com ele.
confirmado
O paciente confirmou que vem. É o que a recepção olha para saber com o que contar no dia.
em_espera
Está na fila, esperando uma vaga abrir. A API não coloca ninguém aqui, mas lê quem está, e daqui a única mudança possível é cancelar.
cancelado
Cancelado, e é ponto final: daqui a API não muda mais nada.
realizado
O atendimento aconteceu. Quem grava isso é a clínica, porque a mudança gera a venda. A API lê e não escreve.
faltou
O paciente não apareceu. Também é da clínica: entra na cobrança de falta e no consumo de sessão de pacote. A API lê e não escreve.

Quando a chamada não dá certo

Toda recusa volta no mesmo formato, com um código curto que não muda e uma mensagem em português. No seu programa, decida sempre pelo código, nunca pela mensagem: ela existe para o seu log e pode ser reescrita a qualquer momento.

Algumas recusas trazem também o detalhamento do que não passou. Nem toda recusa traz esse detalhamento, então o seu código não pode depender dele.

unauthorizedCódigo de status 401

A chave não foi aceita. Ela pode não ter chegado, ter chegado errada, ter sido revogada ou estar vencida, e a resposta é a mesma nos quatro casos.

Comece por aqui, porque é o que mais confunde: chamada recusada por chave não reconhecida não aparece na aba Requisições, já que sem chave válida não dá para saber de qual clínica ela era. Não achar a chamada lá não quer dizer que ela não chegou. Dito isso, confira se o cabeçalho está mesmo sendo enviado e se o valor é a chave completa, não só a parte secreta, sem espaço sobrando nem quebra de linha no meio (copiar de um editor de texto costuma trazer uma). Confira também se não é a chave de exemplo desta página, que é inventada. Se a chave for antiga, veja na aba Chaves do painel se ela continua ativa. Persistindo, emita outra: é mais rápido que investigar.

plan_requiredCódigo de status 403

A chave é válida, mas o plano da clínica não inclui o acesso à API.

Nenhuma mudança no seu código resolve. Avise a clínica, que fala com o suporte da Meevia: é assunto de plano.

scope_requiredCódigo de status 403

A chave é válida, mas não tem o escopo que esta chamada exige.

Veja, na ficha da chamada, qual escopo ela pede, e compare com os escopos da chave na aba Chaves do painel. Escopo não se edita: emita outra chave com o que falta, troque no seu ambiente e revogue a antiga.

not_foundCódigo de status 404

Duas situações diferentes chegam aqui: ou o endereço não corresponde a nada, ou o que você pediu não existe nesta clínica.

Confira primeiro o endereço, letra por letra, contra o exemplo da chamada; um plural a mais cai neste caso. Se o endereço estiver certo, o que falta é o registro: ele pode ter sido apagado, ou ser de outra clínica. Lembre também que o ambiente de teste tem os dados dele próprio. Identificador copiado da clínica real não existe lá dentro.

method_not_allowedCódigo de status 405

O endereço existe, mas não atende esse tipo de requisição.

Confira, na ficha da chamada, qual método ela espera. Quase sempre é uma leitura tentada como escrita, ou o contrário.

validation_failedCódigo de status 422

Alguma coisa no que você enviou não passou na conferência: falta um dado obrigatório, ou um deles veio num formato que não serve.

A mensagem da recusa diz o que não passou. Compare com a tabela de parâmetros da chamada, com atenção especial ao formato de data e hora, que é onde mais se erra.

rate_limitedCódigo de status 429

Você passou do teto de chamadas por minuto dessa chave.

Espere os segundos que vêm no cabeçalho de espera da resposta. Ele não está no corpo. É por isso que muita gente não acha o número e acaba tentando de novo na hora, o que só afunda mais. Se acontecer com frequência, ajuste o ritmo: espace as chamadas, guarde o que muda pouco e não fique perguntando em laço.

idempotency_conflictCódigo de status 409

O valor de repetição que você enviou já foi usado para outra coisa, ou uma chamada gêmea ainda está em andamento.

Se foi outra coisa, passe a gerar um valor novo para cada operação nova; reaproveitar o mesmo em operações diferentes é o que causa isto. Se for a gêmea, espere alguns instantes e repita com o mesmo valor: assim que a primeira terminar, a resposta guardada é devolvida.

status_transition_not_allowedCódigo de status 422

A mudança que você pediu não é permitida a partir da situação em que o agendamento está.

Leia a tabela de mudanças permitidas, que mostra para onde dá para ir a partir de cada situação. Concluir e registrar falta não estão lá, e continuam sendo da operação da clínica. A recusa vem com a situação atual e a pedida, o que costuma revelar que o agendamento já estava noutro estado.

sandbox_not_readyCódigo de status 409

A chave é de teste e o ambiente de teste da clínica ainda não está de pé.

Repita em alguns instantes. Se insistir, o ambiente precisa ser reiniciado, o que o recria do zero, e isso você mesmo faz se tem Pode administrar no painel. Chave de produção nunca cai neste caso.

internal_errorCódigo de status 500

Alguma coisa quebrou do nosso lado.

Não é o seu código. Tente de novo depois de um intervalo. Se persistir, fale com o suporte da Meevia dizendo o horário e o que você chamou; a aba Requisições do painel ajuda a localizar.

Voltar ao topo

Precisa de ajuda

Conte o que você chamou, o que esperava e o que voltou. A aba Requisições do painel mostra o que chegou até nós, e é por ele que a gente começa a olhar.

Esta página e a API

Se você encontrar diferença entre o que está escrito aqui e o que a API respondeu, a API tem razão, e a gente quer saber. A data abaixo diz quando esta página foi conferida contra ela pela última vez.

Fale no WhatsApp