Booking Webhooks
I booking webhook consegnano un POST firmato a un endpoint HTTPS che controlli ogni volta che un booking fa una transition nel workspace — created, confirmed, cancelled, rescheduled, declined, reassigned o segnalato come no-show. Questa pagina copre l'elenco eventi, il payload, gli header, la verifica della signature e il contratto di delivery/retry. Per la Bookings API read-only e un orientamento rapido, parti dall'introduzione Bookings.
Le subscription webhook si configurano dalle impostazioni Bookings dell'app Copera da un amministratore del workspace — non vengono create o gestite tramite la Public API. Ogni subscription ha un receiver URL, un set di eventi e un signing secret.
Eventi
| Event | Fires when |
|---|---|
booking.created | A booking is created (pending or confirmed). |
booking.confirmed | A booking is confirmed. |
booking.cancelled | A booking is cancelled. |
booking.rescheduled | A booking is rescheduled to a new time. |
booking.declined | A pending booking is declined by the host. |
booking.reassigned | A booking's host is reassigned (round-robin). |
booking.no_show | A no-show is recorded for the host or booker. |
Una subscription riceve solo gli eventi che include, e solo mentre è attiva.
Payload
Ogni delivery è un POST con un body 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" }
}
}
Il blocco data è il dato di booking del tuo workspace, quindi i dettagli di contatto del booker sono inclusi. I campi interni sensibili non vengono mai inviati.
Correlare un evento webhook con la Public API
Il payload webhook porta data.id. Passalo direttamente a GET /public/v1/bookings/{id} per recuperare il dettaglio completo del booking:
curl -H "Authorization: Bearer $TOKEN" \
"https://api.copera.ai/public/v1/bookings/${data.id}"
Usa lo stesso valore data.id con una richiesta autenticata alla Bookings API ogni volta che devi correlare eventi webhook con il dettaglio completo del booking.
Header
| Header | Value |
|---|---|
X-Copera-Event | The event string (e.g. booking.confirmed). |
X-Copera-Signature | sha256=<hex> — HMAC-SHA256 of the raw request body using your subscription secret. |
X-Copera-Webhook-Version | The payload contract version (currently 1). |
Verificare la signature
Calcola l'HMAC-SHA256 del raw request body (prima del parsing JSON) con il secret della subscription e confrontalo in constant time con l'hex in 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);
}
Delivery e retry
- Rispondi con un
2xxper confermare la ricezione. - Un
4xxè trattato come rejection permanente — Copera non ritenta. - Un
5xx, errore di network o timeout viene ritentato con exponential backoff (3 tentativi totali). Rendi il receiver idempotente — lo stesso evento può essere consegnato più di una volta. - Gli URL receiver devono essere endpoint HTTPS pubblici; indirizzi privati o interni vengono rifiutati.
Riferimento
- Introduzione Bookings — orientamento, Quick Start, parità e la Bookings API read-only.
- Autenticazione — scope dei token per gli endpoint di lettura Bookings.