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.
@katlink/sdk
A small, dependency-free TypeScript client. Grab a token, check availability, create a booking.
# 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.
Drop-in booking button
Paste this on your existing site — a branded button appears bottom-right and opens the booking flow in a modal.
<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.
Webhooks
Subscribe from your dashboard → Webhooks. Every delivery is signed so you can prove it came from us.
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();
});