Slatis

CRM Integration via Webhooks

Sync Slatis bookings to your CRM automatically using webhooks and signature verification.

Overview

When a booking is created, changed, or cancelled, Slatis sends a signed HTTP POST to your webhook URL. This guide wires those events into a CRM (using HubSpot as an example, but the pattern applies to any system).

1. Create the webhook

curl -X POST https://api.slatis.com/webhooks \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/api/webhooks/slatis",
    "events": ["BOOKING_CREATED", "BOOKING_CANCELLED", "BOOKING_RESCHEDULED"],
    "description": "CRM sync"
  }'

Save the secret from the response.

2. Receive and verify

// app/api/webhooks/slatis/route.ts
import crypto from 'crypto'
import { NextRequest, NextResponse } from 'next/server'
 
const WEBHOOK_SECRET = process.env.SLATIS_WEBHOOK_SECRET!
 
export async function POST(request: NextRequest) {
  const rawBody = await request.text()
  const signature = request.headers.get('x-slatis-signature') ?? ''
 
  const expected = 'sha256=' + crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(rawBody)
    .digest('hex')
 
  if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
    return NextResponse.json({ error: 'Invalid signature' }, { status: 401 })
  }
 
  const event = JSON.parse(rawBody) as {
    event: string
    data: { id: string; attendee: { name: string; email: string } }
  }
 
  switch (event.event) {
    case 'BOOKING_CREATED':
      await createCRMContact(event.data)
      break
    case 'BOOKING_CANCELLED':
      await updateCRMDeal(event.data.id, 'cancelled')
      break
    case 'BOOKING_RESCHEDULED':
      await updateCRMDeal(event.data.id, 'rescheduled')
      break
  }
 
  return NextResponse.json({ received: true })
}

3. Push to CRM

async function createCRMContact(booking: { id: string; attendee: { name: string; email: string } }) {
  // Example: HubSpot Contacts API
  await fetch('https://api.hubapi.com/crm/v3/objects/contacts', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.HUBSPOT_TOKEN}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      properties: {
        email: booking.attendee.email,
        firstname: booking.attendee.name.split(' ')[0],
        lastname: booking.attendee.name.split(' ').slice(1).join(' '),
        slatis_booking_id: booking.id,
      },
    }),
  })
}

4. Return 200 quickly

Slatis retries if your endpoint doesn't respond within 5 seconds. For slow operations, acknowledge immediately and process asynchronously:

export async function POST(request: NextRequest) {
  // ... verify signature ...
 
  // Queue for async processing
  await queue.push({ event: JSON.parse(rawBody) })
 
  // Respond immediately — do not await the CRM call
  return NextResponse.json({ received: true })
}

On this page