Webhooks Guide
Production ReadyReceive real-time notifications about subscription events, usage updates, and payment changes. Set up secure webhook endpoints to keep your application in sync with Bear Billing.
Why Use Webhooks?
Real-Time Updates
Get notified instantly when events happen
Secure & Verified
Cryptographic signatures prevent tampering
Automatic Retries
Failed deliveries are retried up to 3 times
Setup Guide
Create Webhook Endpoint
Create an endpoint in your application to receive webhook events:
import express from 'express';
import crypto from 'crypto';
const app = express();
// IMPORTANT: Use raw body for signature verification
app.post('/webhooks/bearbilling',
express.raw({ type: 'application/json' }),
async (req, res) => {
const signature = req.headers['x-bearbilling-signature'];
const payload = req.body;
// Verify webhook signature (see step 2)
const isValid = verifyWebhookSignature(payload, signature);
if (!isValid) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Parse the event
const event = JSON.parse(payload);
// Handle the event (see step 3)
await handleWebhookEvent(event);
// Acknowledge receipt
res.status(200).json({ received: true });
}
);
app.listen(3000, () => console.log('Webhook server running'));Verify Webhook Signature
Always verify webhook signatures to ensure requests are from Bear Billing:
import crypto from 'crypto';
function verifyWebhookSignature(
payload: Buffer,
signature: string
): boolean {
const webhookSecret = process.env.BEARBILLING_WEBHOOK_SECRET;
// Compute expected signature
const hmac = crypto.createHmac('sha256', webhookSecret);
hmac.update(payload);
const expectedSignature = hmac.digest('hex');
// Compare signatures (timing-safe)
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}Security Note: Never skip signature verification in production. This prevents attackers from sending fake webhook events to your endpoint.
Handle Webhook Events
Process different event types in your application:
async function handleWebhookEvent(event: WebhookEvent) {
switch (event.type) {
case 'subscription.created':
await onSubscriptionCreated(event.data);
break;
case 'subscription.updated':
await onSubscriptionUpdated(event.data);
break;
case 'subscription.cancelled':
await onSubscriptionCancelled(event.data);
break;
case 'invoice.created':
await onInvoiceCreated(event.data);
break;
case 'invoice.paid':
await onInvoicePaid(event.data);
break;
case 'invoice.payment_failed':
await onInvoicePaymentFailed(event.data);
break;
case 'usage.recorded':
await onUsageRecorded(event.data);
break;
default:
console.log(`Unhandled event type: ${event.type}`);
}
}Event Types
| Event Type | Description |
|---|---|
| subscription.created | New subscription was created |
| subscription.updated | Subscription plan or billing cycle changed |
| subscription.cancelled | Subscription was cancelled |
| invoice.created | New invoice generated for billing cycle |
| invoice.paid | Invoice payment succeeded |
| invoice.payment_failed | Invoice payment failed |
| usage.recorded | Usage event was recorded for a subscription |
Example Payloads
subscription.created
{
"id": "evt_1NZxY7KZ2qYgJ8vP",
"type": "subscription.created",
"created_at": "2025-01-13T10:30:00Z",
"data": {
"id": "sub_1NZxY7KZ2qYgJ8vP",
"organization_id": "org_1NZxY7KZ2qYgJ8vP",
"plan_id": "plan_pro_monthly",
"status": "active",
"billing_cycle": "monthly",
"current_period_start": "2025-01-13T10:30:00Z",
"current_period_end": "2025-02-13T10:30:00Z"
}
}invoice.paid
{
"id": "evt_1NZxY8KZ2qYgJ8vP",
"type": "invoice.paid",
"created_at": "2025-01-13T10:35:00Z",
"data": {
"id": "inv_1NZxY8KZ2qYgJ8vP",
"subscription_id": "sub_1NZxY7KZ2qYgJ8vP",
"amount": 9900,
"currency": "usd",
"status": "paid",
"paid_at": "2025-01-13T10:35:00Z"
}
}Testing Webhooks
Use webhook.site for Local Testing
- 1.Visit webhook.site to get a temporary URL
- 2.Add that URL as a webhook endpoint in your Bear Billing dashboard
- 3.Trigger test events from the dashboard
- 4.View the webhook payloads in real-time on webhook.site
Best Practices
Return 200 Quickly
Acknowledge receipt with a 200 status immediately. Process the event asynchronously to avoid timeouts.
Handle Idempotency
Webhooks may be delivered multiple times. Use the event ID to prevent duplicate processing.
Log All Events
Store webhook events for debugging. This helps troubleshoot integration issues.
Monitor Failures
Set up alerts for webhook failures. Bear Billing retries 3 times before marking as failed.