Get started

Online booking

Let customers book a service, a specialist and a time from your website or a hosted page. Kweko computes free times on the server, never gives one time to two customers, and puts every booking in the specialist's calendar.

Embed with widget.js

Owners and admins set up booking in Settings → Online booking: services (duration, price, buffers, who does them), working hours (the same hours lead distribution uses, plus days off and other hours on single dates), how far ahead customers can book, and whether bookings need approval. The page has a public id (b…) and shows ready snippets:

Inline
<script src="https://your-workspace.kweko.uz/widget.js" data-kweko-book="bq2pjn…" async></script>
  • data-mode="popup" shows a button (data-button="Book now") and opens booking in a dialog; data-kweko-open="<page id>", links to #kweko-<page id> and Kweko.open("<page id>") open it too.
  • data-lang="uz|ru|en" overrides the visitor's browser language; data-theme="dark|auto" and data-color="#c9420b" change the look.
  • After a booking the page receives the kweko:booked window event (event.detail.page, event.detail.status).

widget.js loads the booking screens (/widget-book.js, about 9 KB gzipped) only on pages that embed booking. Both render in a closed Shadow DOM, use no eval and no HTML strings, and never send cookies. On a site with a Content-Security-Policy, allow your workspace address in script-src and connect-src.

Booking also has a hosted page at https://your-workspace.kweko.uz/b/<page id> once the workspace is verified. The same page opens a booking for its customer with #m=<manage token> (the link in their SMS): the token stays in the URL fragment, so it never reaches a server log or another site.

Book from your own page

The widget calls public endpoints on your workspace address. They take no API key and no cookies; call them from the customer's browser.

Load the page
curl "https://your-workspace.kweko.uz/api/book/bq2pjn…?lang=ru"
Response
{ "id": "bq2pjn…", "lang": "ru", "title": "Запись в салон", "confirmation": "instant", "sms": true,
  "services": [{ "id": "bsvc_01j…", "name": "Стрижка", "duration_min": 60, "price": 15000000, "currency": "UZS", "staff": ["member_01j…"] }],
  "staff": [{ "id": "member_01j…", "name": "Dilnoza" }], "today": "2026-10-05", "last": "2026-11-04",
  "ask_email": false, "ask_note": true, "cutoff_hours": 2, "color": "#c9420b", "token": "lx3k9a.Qm…", "min_ms": 3000 }
Free times
curl https://your-workspace.kweko.uz/api/book/bq2pjn…/slots \
  -H "Content-Type: application/json" \
  -d '{"service": "bsvc_01j…", "staff": "any", "from": "2026-10-05", "days": 7}'
Response
{ "days": [{ "date": "2026-10-05", "slots": [{ "start": "2026-10-05T04:00:00Z", "time": "09:00" }, …] }, …] }
Book
curl https://your-workspace.kweko.uz/api/book/bq2pjn… \
  -H "Content-Type: application/json" -H "X-Kweko-Locale: ru" \
  -d '{"token": "lx3k9a.Qm…", "service": "bsvc_01j…", "staff": "any", "start": "2026-10-05T04:00:00Z",
       "name": "Dilnoza", "phone": "90 123 45 67", "note": "", "lang": "ru"}'
Response (201)
{ "ok": true, "status": "confirmed", "service": "Стрижка", "staff": "Dilnoza", "date": "2026-10-05", "time": "09:00",
  "manage": "AaDlAy…", "manage_url": "https://your-workspace.kweko.uz/b/bq2pjn…#m=AaDlAy…", "sms": true }
  • Times are in the workspace's time zone (time, date) and in UTC (start). staff is any or one of the service's staff.
  • Free times are working hours minus bookings (with each service's buffers), open meetings in the specialists' calendars and busy time from a connected Google Calendar. days is 1 to 14.
  • token works like the forms token: bookings sent less than min_ms after loading, or with the hidden website field filled in, get the same 201 and are dropped. A missing, forged or day-old token returns 409 booking_expired.
  • The booking is checked again under a lock, so of two customers booking the same time one gets 201 and the other 409 slot_taken.
  • status is pending when the workspace approves bookings by hand.

Manage link

manage is the customer's key to their booking (the booking id and a signature, 38 characters). Every call is a POST with {"token": "…"}:

EndpointDoes
/api/book/<page id>/manageShows the booking: status, service, staff, date, time, the masked phone, can_change, change_until, reminders
/api/book/<page id>/manage/rescheduleMoves it: {"token", "start", "staff"} (the same service; /slots with "manage": "<token>" lists times without counting the booking itself)
/api/book/<page id>/manage/cancelCancels it
/api/book/<page id>/manage/reminders{"token", "off": true} stops SMS reminders

Changes close cutoff_hours before the start (409 booking_locked). A changed or foreign token returns 404 booking_link_invalid, and so does any link a week after the visit.

What a booking does

Kweko looks for the customer by phone, then by email, and reuses a known contact. When the service creates leads, it adds the booking to the customer's open lead or opens one (source booking, owner: the specialist). The specialist gets a meeting in their calendar and a notification. With an SMS account connected in Settings → SMS, the customer gets a confirmation with the manage link and reminders (24 and 2 hours before by default), unless they opted out; without one nothing is sent.

Events: booking.created, booking.rescheduled, booking.canceled, booking.status_changed, plus contact.created and lead.created when records are new.

Protection and limits

LimitValue
Bookings per customer IP5 per hour
Bookings per page1,000 per day, at most 30 in a burst
Bookings per phone number3 upcoming, 5 made in 24 hours
Free-time lookups per IP60 per minute
Request body16 KB
Bookings per monthBy plan (see Usage in Settings)

Over a rate limit the endpoints answer 429 rate_limited with Retry-After; over the per-phone limit 429 too_many_bookings; over the plan's monthly bookings 429 booking_quota_reached. Card numbers are refused. A page that is turned off, or an unknown id, returns 404 booking_unavailable.