Webhooks

Receive real-time notifications when events occur in your WebKasa account.

Overview

Webhooks allow you to receive HTTP POST requests to your server when specific events occur. This is more efficient than polling the API for changes.

Available Events

Webhook Events

ParameterTypeDescription
booking.created
event
A new booking was created
booking.confirmed
event
A booking was confirmed
booking.cancelled
event
A booking was cancelled
booking.completed
event
A booking was marked as completed
event.created
event
A new event was created
event.updated
event
An event was updated
event.cancelled
event
An event was cancelled
registration.created
event
A new event registration
registration.cancelled
event
A registration was cancelled

Payload Format

All webhook payloads follow a consistent structure:

{
  "id": "wh_evt_abc123",
  "type": "booking.created",
  "created_at": "2024-01-15T10:30:00Z",
  "data": {
    "id": "bk_xyz789",
    "schedule_id": "sch_abc123",
    "start_time": "2024-02-15T10:00:00Z",
    "end_time": "2024-02-15T11:00:00Z",
    "status": "PENDING",
    "attendee_name": "John Doe",
    "attendee_email": "john@example.com"
  }
}

Verifying Webhooks

All webhook requests include a signature header for verification. Always verify the signature to ensure the webhook came from WebKasa.

X-WebKasa-Signature: sha256=abc123...
verify-webhook.ts
import crypto from 'crypto';

function verifyWebhookSignature(
  payload: string,
  signature: string,
  secret: string
): boolean {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(`sha256=${expectedSignature}`)
  );
}

// In your webhook handler
export async function POST(request: Request) {
  const payload = await request.text();
  const signature = request.headers.get('X-WebKasa-Signature');

  if (!signature || !verifyWebhookSignature(payload, signature, WEBHOOK_SECRET)) {
    return new Response('Invalid signature', { status: 401 });
  }

  const event = JSON.parse(payload);
  // Process the webhook...

  return new Response('OK', { status: 200 });
}

Handling Webhooks

webhook-handler.ts
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  const payload = await request.text();
  const signature = request.headers.get('X-WebKasa-Signature');

  // Verify signature (see above)
  if (!verifyWebhookSignature(payload, signature!, WEBHOOK_SECRET)) {
    return NextResponse.json({ error: 'Invalid signature' }, { status: 401 });
  }

  const event = JSON.parse(payload);

  switch (event.type) {
    case 'booking.created':
      await handleBookingCreated(event.data);
      break;

    case 'booking.confirmed':
      await handleBookingConfirmed(event.data);
      break;

    case 'booking.cancelled':
      await handleBookingCancelled(event.data);
      break;

    case 'registration.created':
      await handleRegistrationCreated(event.data);
      break;

    default:
      console.log(`Unhandled event type: ${event.type}`);
  }

  // Always return 200 to acknowledge receipt
  return NextResponse.json({ received: true });
}

async function handleBookingCreated(booking: BookingData) {
  // Send confirmation email
  await sendConfirmationEmail(booking.attendee_email, booking);

  // Update your database
  await db.bookings.create({ data: booking });

  // Notify team via Slack
  await notifySlack(`New booking from ${booking.attendee_name}`);
}

Best Practices

Return 200 Quickly

Return a 200 response as soon as you receive the webhook. Process the event asynchronously if it takes more than a few seconds.

Handle Duplicates

Webhooks may be delivered more than once. Use the id field to deduplicate and ensure idempotent processing.

Always Verify Signatures

Never process a webhook without verifying its signature. This prevents attackers from sending fake events to your endpoint.

Use HTTPS

Your webhook endpoint must use HTTPS. We do not send webhooks to HTTP endpoints.

Retry Policy

If your endpoint returns a non-2xx response, we'll retry the webhook:

  • 1st retry: 1 minute after initial attempt
  • 2nd retry: 5 minutes after 1st retry
  • 3rd retry: 30 minutes after 2nd retry
  • 4th retry: 2 hours after 3rd retry
  • 5th retry: 24 hours after 4th retry

After 5 failed attempts, the webhook is marked as failed. You can view and retry failed webhooks in the dashboard.

Configure Webhooks

Set up webhook endpoints in your dashboard to start receiving events.

Configure Webhooks