Back to Guides

Webhooks Guide

Production Ready

Receive 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

1

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'));
2

Verify Webhook Signature

Always verify webhook signatures to ensure requests are from Bear Billing:

Cryptographically verified for security
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.

3

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 TypeDescription
subscription.createdNew subscription was created
subscription.updatedSubscription plan or billing cycle changed
subscription.cancelledSubscription was cancelled
invoice.createdNew invoice generated for billing cycle
invoice.paidInvoice payment succeeded
invoice.payment_failedInvoice payment failed
usage.recordedUsage 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. 1.Visit webhook.site to get a temporary URL
  2. 2.Add that URL as a webhook endpoint in your Bear Billing dashboard
  3. 3.Trigger test events from the dashboard
  4. 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.