Pular para o conteúdo principal

Booking Webhooks

Os booking webhooks entregam um POST assinado a um endpoint HTTPS sob seu controle toda vez que um booking muda de estado no seu workspace — criado, confirmado, cancelado, reagendado, recusado, reatribuído ou marcado como no-show. Esta página cobre a lista de eventos, o payload, os headers, a verificação de assinatura e o contrato de entrega/retry. Para a Bookings API somente leitura e uma orientação rápida, comece pela introdução de Bookings.

observação

As inscrições de webhook são configuradas nas configurações de Bookings do app Copera por um administrador do workspace — elas não são criadas nem gerenciadas pela Public API. Cada inscrição tem uma URL de recebimento, um conjunto de eventos e um signing secret.

Eventos

EventoDispara quando
booking.createdUm booking é criado (pending ou confirmed).
booking.confirmedUm booking é confirmado.
booking.cancelledUm booking é cancelado.
booking.rescheduledUm booking é reagendado para um novo horário.
booking.declinedUm booking pendente é recusado pelo host.
booking.reassignedO host de um booking é reatribuído (round-robin).
booking.no_showUm no-show é registrado para o host ou para o booker.

Uma inscrição recebe apenas os eventos que ela inclui, e somente enquanto estiver ativa.

Payload

Cada entrega é um POST com um corpo JSON:

{
"event": "booking.confirmed",
"createdAt": "2026-07-06T09:00:00.000Z",
"data": {
"id": "665f…",
"status": "CONFIRMED",
"bookingTypeId": "665f…",
"bookingTypeTitle": "Intro Call",
"start": "2026-07-08T15:00:00.000Z",
"end": "2026-07-08T15:30:00.000Z",
"durationMinutes": 30,
"timezoneAtBooking": "America/Sao_Paulo",
"hosts": [{ "userId": "665f…", "role": "ORGANIZER" }],
"booker": {
"name": "Alice Booker",
"email": "[email protected]",
"phone": "+15551234567",
"timezone": "America/Sao_Paulo",
"locale": "en"
},
"guests": [],
"answers": [{ "questionId": "q1", "label": "Topic", "value": "Pricing" }],
"location": { "type": "MEETING_CHANNEL" }
}
}

O bloco data contém os dados de booking do seu próprio workspace, então os dados de contato do booker estão incluídos. Campos internos sensíveis nunca são enviados.

Correlacionando um evento de webhook com a API pública

O payload do webhook inclui data.id. Passe esse valor diretamente para GET /public/v1/bookings/{id} para buscar os detalhes completos do booking:

curl -H "Authorization: Bearer $TOKEN" \
"https://api.copera.ai/public/v1/bookings/${data.id}"

Use o mesmo valor data.id com uma requisição autenticada da API de Bookings quando precisar correlacionar eventos de webhook com os detalhes completos do booking.

Headers

HeaderValor
X-Copera-EventA string do evento (ex.: booking.confirmed).
X-Copera-Signaturesha256=<hex> — HMAC-SHA256 do corpo bruto da requisição usando o secret da sua inscrição.
X-Copera-Webhook-VersionA versão do contrato de payload (atualmente 1).

Verificando a assinatura

Calcule o HMAC-SHA256 do corpo bruto da requisição (antes do parse do JSON) com o secret da sua inscrição e compare-o em tempo constante com o hex em X-Copera-Signature:

import { createHmac, timingSafeEqual } from "node:crypto";

function isValidSignature(rawBody, header, secret) {
const expected =
"sha256=" + createHmac("sha256", secret).update(rawBody, "utf8").digest("hex");
const a = Buffer.from(header);
const b = Buffer.from(expected);
return a.length === b.length && timingSafeEqual(a, b);
}

Entrega e retries

  • Responda com um 2xx para confirmar o recebimento.
  • Um 4xx é tratado como uma rejeição permanente — o Copera não faz retry.
  • Um 5xx, erro de rede ou timeout sofre retry com backoff exponencial (3 tentativas no total). Faça seu receiver ser idempotente — o mesmo evento pode ser entregue mais de uma vez.
  • As URLs de recebimento precisam ser endpoints HTTPS públicos; endereços privados ou internos são rejeitados.

Referência