Webhooks
Subscribe to events (e.g. review.created, booking.completed, invoice.paid) and Vimub POSTs an HMAC-signed JSON payload to your URL. Manage subscriptions and signing secrets in Settings → API keys or via the API.
Delivery headers
X-Vimub-Signature: t=1719500000,v1=9f86d081... # HMAC-SHA256, hex
X-Vimub-Timestamp: 1719500000
X-Vimub-Event-Id: 3b2e... # idempotency key
X-Vimub-Event-Type: review.createdVerify the signature
The signature is HMAC-SHA256 of `${timestamp}.${rawBody}` using your subscription's signing secret. Always compare in constant time and reject stale timestamps.
import { createHmac, timingSafeEqual } from 'node:crypto';
// Verify against the RAW request body (do not re-serialize JSON first).
export function verify(rawBody: string, sigHeader: string, secret: string): boolean {
const parts = Object.fromEntries(sigHeader.split(',').map((p) => p.split('=')));
const ts = parts.t, v1 = parts.v1;
if (!ts || !v1) return false;
// Reject anything older than 5 minutes to stop replay.
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
const expected = createHmac('sha256', secret).update(`${ts}.${rawBody}`).digest('hex');
return v1.length === expected.length &&
timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
}Retries & dead-lettering
- Respond
2xxwithin a few seconds to acknowledge. Any other status (or timeout) is retried. - Backoff is
1m → 5m → 15m → 1h → 6h → 24h(6 attempts over ~24h), then the delivery is dead-lettered. - Deliveries carry a stable
X-Vimub-Event-Id— dedupe on it; the same event may be delivered more than once.