Loading...
Set a webhook URL in your dashboard and we POST to it when something happens, so your own system stays in sync without polling.
Webhooks are configured in the dashboard, not through the API — there is no /v1/webhooks route. Set the URL and its signing secret at /profile/integrations. The secret is stored server-side and never reaches a browser. One endpoint covers every event on the account.
Today there is one: registration.confirmed, fired the moment a booking is confirmed and its ticket issued.
{
"type": "registration.confirmed",
"createdAt": "2027-09-01T10:04:11.760Z",
"data": {
"registrationId": "…", "eventId": "…", "eventTitle": "…",
"name": "…", "email": "…", "phone": "…",
"ticketType": "…", "subEventId": "…", "quantity": 1,
"amountPaid": 0, "currency": "INR", "paymentStatus": "…"
}
}We sign the exact bytes we send. Recompute the HMAC over the raw body and compare in constant time.
// Headers we send:
// X-Vihaya-Signature: sha256=<hex> <-- note the prefix
// X-Vihaya-Timestamp: <unix milliseconds>
const timestamp = req.headers['x-vihaya-timestamp'];
const header = req.headers['x-vihaya-signature'];
// The signature is prefixed. Strip it before comparing, or the two buffers
// are different lengths and timingSafeEqual throws.
const signature = String(header).replace(/^sha256=/, '');
const expected = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(`${timestamp}.${rawBody}`) // raw body, before JSON.parse
.digest('hex');
if (signature.length !== expected.length ||
!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))) {
return res.status(401).end();
}
// Reject an old timestamp too — that is what makes a captured
// delivery non-replayable.
if (Date.now() - Number(timestamp) > 5 * 60 * 1000) return res.status(401).end();createdAt if it matters.Do not treat this as a durable queue. Because there are no retries, reconcile against GET /events/{id}/registrations rather than assuming every booking arrived.
The most common use is issuing your own ticket — data.registrationId is the QR payload, so you can render the code and send the email entirely from your own system. See Tickets & QR codes.