Developers

Developer API

Build booking into your own website or systems. Most businesses only need the embeddable widget — the REST API is for custom integrations.

Embeddable widget

No API key required — paste it into your site.

Get the exact snippet in your dashboard under API & widget:

<div id="kacti-booking"></div>
<script
  src="https://kacti.ca/embed.js"
  data-business="your-business-slug"
  data-mode="inline"
  data-accent="#2563eb"
  defer></script>
  • data-mode — inline or button (floating pop-up)
  • data-service — optional service id to preselect
  • data-target — optional id of the container element
  • The iframe auto-resizes and fires a kacti:booking-confirmed window event.

Authentication

Bearer tokens scoped to one business.

Create a key in your dashboard and send it as a bearer token. Keys can be locked to specific website domains.

curl https://kacti.ca/api/public/v1/services \
  -H "Authorization: Bearer kacti_live_xxxxxxxx"

Endpoints

Everything under /api/public/v1.

GET/api/public/v1/business

Business profile, address, timezone and policies.

GET/api/public/v1/services

Active services with duration, buffer and price.

GET/api/public/v1/employees

Active staff who can be booked.

GET/api/public/v1/availability

Bookable slots for a service on a date.

Query: service_id (required), date=YYYY-MM-DD (required), employee_id, tz_offset_min

POST/api/public/v1/bookings

Create a guest booking. Price, availability and conflicts are validated server-side.

GET/api/public/v1/bookings/{id}

Status of a booking created with your key.

curl -X POST https://kacti.ca/api/public/v1/bookings \
  -H "Authorization: Bearer kacti_live_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "service_id": "…",
    "employee_id": "…",
    "start_at": "2026-03-04T14:00:00.000Z",
    "guest_name": "Jane Doe",
    "guest_email": "jane@example.com",
    "guest_phone": "+1 555 123 4567"
  }'

Errors & limits

Predictable error shapes and per-key rate limits.

Errors return { error: { code, message } } with codes such as unauthorized, origin_not_allowed, invalid_request, not_found and rate_limited.

Rate limits apply per API key (reads are more generous than booking writes). Handle HTTP 429 by retrying after the Retry-After header.