Para programadores
API, webhooks e widget, grátis
Consulte horários livres, crie e cancele reservas a partir do seu software, receba um aviso assinado de cada alteração e ponha a sua agenda no seu site. O que outros cobram, aqui é grátis.
Autenticação
Crie uma chave em Definições → API e webhooks. Escolha «Só ler» (tipos de reunião, disponibilidade e reservas) ou «Ler e reservar» (também reservar, alterar, cancelar e criar links de uso único). A chave só é mostrada uma vez.
Envie-a no cabeçalho X-API-Key. Todas as rotas estão em https://calendavibe.com/api/v1. Uma chave só vê e altera os dados da sua própria conta.
Os seus tipos de reunião
curl https://calendavibe.com/api/v1/event-types \
-H "X-API-Key: cvwh_…"Rotas
| Rota | O que faz | Chave |
|---|---|---|
| GET /me | A sua conta e o tipo de chave | Só ler |
| GET /event-types | Os seus tipos de reunião, com o link público | Só ler |
| GET /event-types/{id}/slots?from&to&timezone | Os horários livres, tal como a sua página os oferece | Só ler |
| GET /bookings?status=upcoming|past|cancelled|all | As suas reservas (paginadas com cursor) | Só ler |
| GET /bookings/{id} | Uma reserva | Só ler |
| POST /bookings | Reservar um horário | Ler e reservar |
| POST /bookings/{id}/reschedule | Mudar a hora | Ler e reservar |
| POST /bookings/{id}/cancel | Cancelar | Ler e reservar |
| POST /single-use-links | Um link que aceita uma única reserva | Ler e reservar |
Reservar (com Idempotency-Key, para não duplicar se repetir o pedido)
curl -X POST https://calendavibe.com/api/v1/bookings \
-H "X-API-Key: cvwh_…" -H "Content-Type: application/json" \
-H "Idempotency-Key: pedido-1234" \
-d '{
"eventTypeId": "ckx…",
"startTime": "2026-11-03T09:00:00.000Z",
"guest": { "name": "Ana García", "email": "ana@example.com", "timezone": "Europe/Madrid", "locale": "es" },
"consent": true
}'Regras das reservas
Uma reserva pela API segue as mesmas regras que a sua página: só horários realmente livres (também no seu calendário), e o convidado recebe os seus emails e aparece nos seus contactos.
Envie consent: true quando o convidado tiver aceitado o tratamento dos seus dados no seu formulário.
Se dois sistemas pedirem o mesmo horário ao mesmo tempo, o segundo recebe 409 SLOT_UNAVAILABLE e escolhe outro. Com a mesma Idempotency-Key, um pedido repetido devolve a mesma reserva durante 24 horas.
Uma reunião paga não se reserva pela API: a resposta é 402 PAYMENT_REQUIRED com bookingUrl, o link para o convidado reservar e pagar.
Limites
Plano grátis: 60 chamadas por minuto e 10.000 por dia por conta, e até 10 webhooks. Com o Closevibe, mais.
Acima do limite, a resposta é 429 com o cabeçalho Retry-After.
Os erros têm sempre a forma { "error": { "code", "message" } }.
Webhooks
Em Definições → API e webhooks, adicione um URL de destino (https e público) e escolha os avisos: Nova reserva (meeting.booked), Cancelamento (meeting.cancelled), Mudança de hora (meeting.rescheduled) e Pagamento recebido (meeting.paid).
Cada aviso é um POST com os dados da reserva, nunca o link privado do convidado. Se o seu servidor falhar, tentamos de novo após 1 min, 5 min, 30 min, 2 h, 6 h e 12 h. Após 20 falhas seguidas, o URL é desativado e avisamos por email.
Verifique a assinatura: o cabeçalho X-Webhook-Signature é sha256= seguido do HMAC-SHA256 do corpo tal como chega, com o segredo de assinatura desse URL.
Um aviso
{
"id": "evt_…",
"event": "meeting.booked",
"createdAt": "2026-11-01T10:15:00.000Z",
"data": {
"booking": {
"id": "ckx…", "status": "CONFIRMED",
"eventType": { "id": "ckx…", "slug": "primera-consulta", "name": "Primera consulta", "duration": 30 },
"startTime": "2026-11-03T09:00:00.000Z", "endTime": "2026-11-03T09:30:00.000Z", "timezone": "Europe/Madrid",
"guest": { "name": "Ana García", "email": "ana@example.com", "phone": null, "timezone": "Europe/Madrid", "locale": "es", "notes": null },
"answers": [{ "question": "Motivo", "answer": "Revisión" }],
"meetingUrl": "https://meet.google.com/…", "payment": null
}
}
}Verificar a assinatura (Node.js)
const crypto = require('crypto');
// rawBody: the request body exactly as received (a Buffer or string, before JSON.parse).
function isFromCalendaVibe(rawBody, header, secret) {
const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
return header && expected.length === header.length && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(header));
}Widget para o seu site
Na página ou numa janela pop-up (botão ou bolha), com a sua cor e o seu idioma. Se já conhece o visitante, passe o nome e o email e aparecerão preenchidos. No telemóvel, a janela ocupa o ecrã inteiro e fecha-se com o X ou Esc.
Quando alguém reserva dentro do widget, a sua página recebe o evento calendavibe:booked com a hora e o tipo de reunião.
Na página
<div class="calendavibe-inline" data-url="https://calendavibe.com/ana/primera-consulta"
data-color="#6d28d9" data-lang="es"></div>
<script src="https://calendavibe.com/embed.js" async></script>Janela pop-up a partir de um botão ou de uma bolha
<a href="https://calendavibe.com/ana/primera-consulta" data-calendavibe-popup
data-color="#6d28d9" data-name="Ana García" data-email="ana@example.com">Reservar</a>
<script src="https://calendavibe.com/embed.js" async
data-calendavibe-bubble="https://calendavibe.com/ana" data-text="Reservar" data-color="#6d28d9"></script>Perguntas frequentes
Tem algum custo?
Não. A API, os webhooks e o widget são grátis no plano grátis, com os limites acima.
Funciona com o Zapier ou o Make?
Sim: use o módulo HTTP deles com a sua chave para a API, e um webhook do CalendaVibe como acionador.
Posso cobrar uma reunião pela API?
Não: o convidado paga na sua página. A API devolve-lhe o link para lho enviar.