Skip to Content
Webhooks

Last Updated: 1/27/2026


Webhooks

Receive real-time notifications when events occur.

Overview

Webhooks allow your application to receive HTTP callbacks when events happen in your account.

Your App <──── POST /webhook ──── Example API (event data)

:::info Webhooks are sent as POST requests with a JSON body containing event data. :::

Supported Events

EventDescriptionPayload
user.createdNew user registeredUser object
user.updatedUser profile changedUser object
user.deletedUser account removedUser ID
payment.completedPayment succeededPayment object
payment.failedPayment failedPayment + error

Setting Up Webhooks

1. Create Endpoint

// Express.js example import express from 'express'; import { verifyWebhook, type WebhookEvent } from '@example/sdk'; const app = express(); app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => { const signature = req.headers['x-signature'] as string; const payload = req.body; try { const event = verifyWebhook(payload, signature, process.env.WEBHOOK_SECRET!); handleEvent(event); res.status(200).send('OK'); } catch (error) { console.error('Webhook verification failed:', error); res.status(400).send('Invalid signature'); } });

:::danger Always verify webhook signatures. Without verification, attackers could send fake events. :::

2. Register Webhook URL

const client = createClient({ apiKey: process.env.API_KEY! }); const webhook = await client.webhooks.create({ url: 'https://yourapp.com/webhook', events: ['user.created', 'user.updated', 'payment.completed'], secret: 'whsec_your_secret_here', }); console.log('Webhook ID:', webhook.id);

3. Handle Events

import type { WebhookEvent } from '@example/sdk'; function handleEvent(event: WebhookEvent) { switch (event.type) { case 'user.created': console.log('New user:', event.data.id); sendWelcomeEmail(event.data.email); break; case 'user.updated': console.log('User updated:', event.data.id); syncUserData(event.data); break; case 'payment.completed': console.log('Payment received:', event.data.amount); fulfillOrder(event.data.orderId); break; case 'payment.failed': console.error('Payment failed:', event.data.error); notifyCustomer(event.data.customerId); break; default: console.log('Unhandled event:', event.type); } }

:::tip Use a switch statement or event handler map for clean, maintainable webhook handling. :::

Webhook Payload

{ "id": "evt_abc123", "type": "user.created", "timestamp": "2024-01-15T10:30:00Z", "data": { "id": "user_xyz789", "email": "alice@example.com", "name": "Alice Smith", "createdAt": "2024-01-15T10:30:00Z" } }

Signature Verification

import crypto from 'crypto'; function verifySignature( payload: Buffer, signature: string, secret: string, ): boolean { const expected = crypto .createHmac('sha256', secret) .update(payload) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expected), ); }

:::warning Use crypto.timingSafeEqual to prevent timing attacks when comparing signatures. :::

Retry Policy

Failed webhook deliveries are retried with exponential backoff:

AttemptDelay
1Immediate
21 minute
35 minutes
430 minutes
52 hours

:::note After 5 failed attempts, the webhook is marked as failed. Check the dashboard for failed deliveries. :::

Best Practices

  1. Respond quickly - Return 200 within 5 seconds
  2. Process async - Queue events for background processing
  3. Handle duplicates - Events may be sent more than once
  4. Log everything - Store event IDs for debugging
// Idempotent event handling const processedEvents = new Set<string>(); function handleEvent(event: WebhookEvent) { if (processedEvents.has(event.id)) { console.log('Duplicate event, skipping:', event.id); return; } processedEvents.add(event.id); // Process event... }