Katlink
REST API · v1 · JWT auth

Build on Katlink

Sync bookings into your CRM, drive your own booking widgets, integrate your PMS — everything the apps do runs through this API.

Typed SDK

Dependency-free TypeScript client for Node 18+, Bun, Deno and browsers.

Drop-in widget

One script tag adds a booking button to any existing website.

Signed webhooks

HMAC-SHA256 signed events for created, completed and cancelled bookings.

Quick start

@katlink/sdk

A small, dependency-free TypeScript client. Grab a token, check availability, create a booking.

book.ts
# Install
pnpm add @katlink/sdk

# Use
import { Katlink } from '@katlink/sdk';

const k = new Katlink({ baseUrl: 'https://katlink.karlink-iq.com' });
const { accessToken } = await k.auth.login('demo@katlink.iq', 'demo1234');
k.setToken(accessToken);

const slots = await k.bookings.availability('SERVICE-ID', '2026-07-01');
const booking = await k.bookings.create({
  businessId: 'BIZ-ID',
  serviceId: 'SERVICE-ID',
  startAt: slots[0].startAt,
  customer: { name: 'Aryan', phone: '07700000000' },
});

Need types for routes not in the SDK? Run openapi-typescript https://katlink.karlink-iq.com/api/openapi.json -o katlink.d.ts and import paths directly.

No code

Drop-in booking button

Paste this on your existing site — a branded button appears bottom-right and opens the booking flow in a modal.

index.html
<script
  src="https://app.katlink.iq/widget.js"
  data-slug="your-business-slug"
  data-label="Book now"
  data-position="bottom-right"
  data-brand-color="#0d9488"
  async></script>

Set data-position="inline" to render inline where the script is placed.

Events

Webhooks

Subscribe from your dashboard → Webhooks. Every delivery is signed so you can prove it came from us.

booking.createdbooking.completedbooking.cancelled
verify.ts
import { createHmac, timingSafeEqual } from 'crypto';

app.post('/hooks/katlink', (req, res) => {
  const sig = req.header('X-Katlink-Signature') ?? '';
  const expected = createHmac('sha256', process.env.KATLINK_WEBHOOK_SECRET)
    .update(req.rawBody)
    .digest('hex');
  if (!timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
    return res.status(401).end();
  }
  const { event, data } = req.body; // booking.created | completed | cancelled
  res.status(200).end();
});