Slatis Public API v1 is open for beta testers Register on the waitlist →
Slatis

SDK

The official TypeScript SDK for Slatis. Full type safety, React hooks, and an embeddable booking widget.

Installation

npm install @slatis/sdk

Configuration

import { Slatis } from '@slatis/sdk'
 
const slatis = new Slatis({
  apiKey: process.env.SLATIS_SECRET_KEY!, // sk_live_* or pk_live_*
  // baseUrl: 'https://api.slatis.com/v1', // default
  // timeout: 30_000,                      // ms, default 30s
  // debug: true,
})

Use sk_* keys on the server only. For browser contexts, use pk_* public keys — they are scoped to booking creation and availability.


Bookings

// Create
const booking = await slatis.bookings.create({
  event_type_id: 'evt_01abc',
  attendee: {
    name: 'Jane Smith',
    email: 'jane@example.com',
    timezone: 'America/New_York',
  },
  requested_time: '2026-05-01T14:00:00Z',
  idempotency_key: 'order_12345_attempt_1',
})
 
// Poll until routing completes (leaves DRAFT)
const scheduled = await slatis.bookings.pollUntilScheduled(booking.id, {
  interval_ms: 500,   // default
  timeout_ms: 10_000, // default
})
 
// Get by ID
const booking = await slatis.bookings.get('bkg_01xyz')
 
// Get by external ID (useful for CRM lookups)
const booking = await slatis.bookings.getByExternalId('crm_deal_456')
 
// List with filters — returns { bookings, pagination }
const { bookings, pagination } = await slatis.bookings.list({
  status: 'SCHEDULED',
  start_date: '2026-05-01',
  end_date: '2026-05-31',
  limit: 50,
})
 
// Fetch all pages using cursor
let cursor: string | undefined
const allBookings = []
do {
  const result = await slatis.bookings.list({ status: 'SCHEDULED', limit: 100, cursor })
  allBookings.push(...result.bookings)
  cursor = result.pagination.next_cursor ?? undefined
} while (cursor)
 
// Update attendee details
await slatis.bookings.update('bkg_01xyz', {
  attendee: { email: 'new@example.com' },
})

Status transitions

await slatis.bookings.confirm('bkg_01xyz')
await slatis.bookings.complete('bkg_01xyz', { notes: 'Great call' })
await slatis.bookings.markNoShow('bkg_01xyz', { reason: 'No contact' })
await slatis.bookings.cancel('bkg_01xyz', { reason: 'Customer request' })
await slatis.bookings.reschedule('bkg_01xyz', {
  start_time: '2026-05-05T10:00:00Z',
  reason: 'Schedule conflict',
})

Team

// List members (paginated)
const { members, pagination } = await slatis.team.getMembers({
  is_active: true,
  skills: ['javascript', 'react'],
  limit: 20,
  offset: 0,
})
 
// Get a single member
const member = await slatis.team.getMember('mem_01abc')
 
// Find members by skill
const jsDevs = await slatis.team.findBySkills(['javascript'])
 
// Available members on a given day (paginated)
const { members, date, pagination } = await slatis.team.getAvailableMembers({
  date: '2026-05-01',
  duration: 30,
  skills: ['sales'],
})
 
// Get the least-loaded available member for smart assignment
const member = await slatis.team.getLeastBusyMember({
  date: '2026-05-01',
  duration: 30,
})
 
if (member) {
  await slatis.bookings.create({
    event_type_id: 'evt_01abc',
    attendee: { name: 'Jane', email: 'jane@example.com' },
    requested_time: '2026-05-01T14:00:00Z',
    assign_to: member.id,
  })
}

Webhooks

Webhook management requires a secret key with the webhooks:manage scope.

// Create
const webhook = await slatis.webhooks.create({
  url: 'https://your-app.com/webhooks/slatis',
  events: ['BOOKING_CREATED', 'BOOKING_CANCELLED'],
  description: 'CRM integration',
})
// webhook.secret is only returned here — store it immediately
 
// List (with optional active filter)
const webhooks = await slatis.webhooks.list({ is_active: true })
 
// Get a single webhook with delivery stats
const detail = await slatis.webhooks.get('wh_01abc')
 
// Update
await slatis.webhooks.update('wh_01abc', {
  is_active: true,
  events: ['BOOKING_CREATED', 'BOOKING_RESCHEDULED'],
})
 
// Delete
await slatis.webhooks.delete('wh_01abc')
 
// Send a test delivery
const result = await slatis.webhooks.test('wh_01abc')
 
// Rotate signing secret
const { secret } = await slatis.webhooks.rotateSecret('wh_01abc')
// Store the new secret — it's only returned once
 
// Delivery history
const { deliveries, pagination } = await slatis.webhooks.listDeliveries('wh_01abc', {
  success: false,
  limit: 20,
})

React hooks

Wrap your app with SlatisProvider once — all hooks read the key from context:

app/layout.tsx
import { SlatisProvider } from '@slatis/sdk/react'
 
export default function Layout({ children }) {
  return (
    <SlatisProvider apiKey={process.env.NEXT_PUBLIC_SLATIS_KEY!}>
      {children}
    </SlatisProvider>
  )
}

Available hooks

HookDescription
useAvailabilityFetch and manage available time slots
useBookingCreate, cancel, reschedule bookings
useEventTypesList your organization's active event types
useCapacityTeam capacity and utilization
useFormForm state management with validation
useFormSchemaLoad custom field schemas for an event type
useTrackingUTM and session attribution
import { useAvailability, useBooking } from '@slatis/sdk/react'
 
function BookingWidget({ eventTypeId }: { eventTypeId: string }) {
  const { slots, isLoading } = useAvailability({
    event_type_id: eventTypeId,
    start_date: new Date(),
    end_date: addDays(new Date(), 7),
    timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
  })
 
  const { createBooking } = useBooking({
    onSuccess: (b) => router.push(`/confirmation/${b.id}`),
  })
 
  // render slot picker + attendee form...
}

Embeddable widget

Zero-configuration widget for static sites and non-React apps:

<script src="https://cdn.slatis.com/widget.js" defer></script>
<div
  data-slatis-widget
  data-api-key="pk_live_xxxxxxxxxxxxxxxxxxxx"
  data-event-type-id="evt_01abc123"
></div>

Listen for booking events:

<script>
  window.addEventListener('slatis:booking:created', (e) => {
    analytics.track('booking_created', { bookingId: e.detail.id })
  })
</script>

Error handling

The SDK throws typed error classes that map to API error codes:

import {
  ValidationError,
  AuthenticationError,
  NotFoundError,
  RateLimitError,
  ConflictError,
  SlatisError,
} from '@slatis/sdk'
 
try {
  await slatis.bookings.create({ ... })
} catch (error) {
  if (error instanceof ValidationError) {
    // 400 — bad input
    console.error('Invalid input:', error.details)
  } else if (error instanceof AuthenticationError) {
    // 401 — invalid or missing key
    console.error('Check your API key')
  } else if (error instanceof ConflictError) {
    // 409 — slot no longer available
    console.error('Time slot taken — refresh and retry')
  } else if (error instanceof RateLimitError) {
    // 429 — rate limited
    console.error('Retry after:', error.retryAfter, 's')
  } else if (error instanceof NotFoundError) {
    // 404
    console.error('Resource not found')
  } else if (error instanceof SlatisError) {
    console.error(error.code, error.message)
  }
}

On this page