Webhook events
Vauchflow delivers events to your endpoint via HTTP POST using the transactional outbox pattern — events are guaranteed to be delivered at least once, even across API restarts.
Register an endpoint
Section titled “Register an endpoint”curl -X POST https://api.vauchflow.com/v1/webhooks \ -H "Authorization: Bearer vf_sk_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://yourapp.com/webhooks/vauchflow", "events": ["voucher.redeemed", "campaign.budget_reached"] }'
# Response includes your signing secret — save it now, it won't be shown again.Event types
Section titled “Event types”| Event | Trigger |
|---|---|
voucher.redeemed | A redemption completed successfully |
voucher.validated | A validation check was performed |
voucher.expired | A voucher passed its expiry date |
campaign.started | Campaign start time reached |
campaign.ended | Campaign end time reached |
campaign.budget_reached | max_redemptions limit hit |
redemption.rolled_back | A redemption was reversed |
fraud.alert | Velocity anomaly detected |
agent.action.pending_approval | High-risk agent action queued for operator review |
agent.action.approved | Operator approved a queued agent action |
agent.action.rejected | Operator rejected a queued agent action |
agent.action.executed | Approved agent action successfully executed |
agent.action.expired | Pending approval expired without operator decision (default 15 min TTL) |
Payload format
Section titled “Payload format”{ "id": "evt_01HX...", "type": "voucher.redeemed", "timestamp": "2026-04-17T14:30:00Z", "data": { "voucher_code": "SAVE20", "customer_id": "cust_xyz", "discount_applied": 18.00, "remaining_redemptions": 498 }}Verifying signatures
Section titled “Verifying signatures”Every payload is signed with HMAC-SHA256. Verify to prevent replay attacks:
const crypto = require('crypto');
function verifyWebhook(rawBody, signatureHeader, secret) { const [timestamp, signature] = signatureHeader.split(','); const ts = timestamp.replace('t=', ''); const sig = signature.replace('v1=', '');
const expected = crypto .createHmac('sha256', secret) .update(`${ts}.${rawBody}`) .digest('hex');
const diff = Math.abs(Date.now() / 1000 - Number(ts)); if (diff > 300) { throw new Error('Timestamp too old — possible replay attack'); }
return crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));}Retry schedule
Section titled “Retry schedule”immediate → 5 min → 30 min → 2h → 5h → 10h → every 12h → 72h max
After 72 hours without successful delivery, the event moves to the dead-letter queue, visible in your dashboard for manual replay.
Security
Section titled “Security”- Encrypted at rest: signing secrets are encrypted with AES-256-GCM (VF-062) before storage. Plaintext is never persisted.
- SSRF protection: webhook delivery blocks internal and private network addresses (link-local, loopback, RFC1918) to prevent server-side request forgery (VF-059).
- Zero-downtime rotation (Starter plans and above): rotate the signing secret without dropping in-flight events. The previous secret remains valid for a configurable overlap window after rotation, giving you time to redeploy receivers (VF-066).