The public appointment self-booking model
The public appointment pair answers one question — “can an end customer pick a callback slot on a contact-center queue without an account?” — with yes, when the tenant turns it on. Two unauthenticated endpoints expose a queue’s published bookable slots (read) and accept a booking (write), identified by the tenant’s public key in the URL. A successful booking lands as a scheduled callback: the same dispatcher that drives operator-side appointments calls the customer at the chosen slot. This page is the concept map for that public surface: what the two endpoints do, the opt-in gate that keeps them off by default, the payload contract a hosted booking page codes against, and the abuse posture for unauthenticated intake. Operator-side scheduling — the signed-in dashboard that defines a queue’s bookable hours and books appointments for customers — stays authoritative on the queue callback model; the public pair only re-exposes the slots the operator published. Every control named here is tenant-owned: your opt-in flag, your branding and copy, your queue’s bookable hours. Callback dispatches ride the Devotel softswitch exactly as operator-side callbacks do — enabling public booking never configures an outbound route.1. What the public pair does
Two endpoints, both under/api/v1/public/queues/:tenantId/:queueId, both reachable with no session and no API key:
The availability read shapes its window with optional query parameters:
from / to (ISO-8601, defaulting to the next 14 days), slot_minutes (5–240, default 30 — the slot granularity), and lead_minutes (0–20160, default 60 — the minimum notice a customer must give). The booking write re-checks the same schedule, lead-time, and capacity validation the operator path applies, so a public booker can’t land a slot the dashboard would refuse.
The :tenantId segment is the tenant’s public key — the same identifier the hosted booking page embeds in the URL. Treat it as publishable: it authorizes nothing by itself, and the abuse defence below never depends on its secrecy.
2. The opt-in gate — off until the tenant turns it on
Public booking is gated by a tenancy-level flag,public_appointment_booking.enabled, stored in the organization’s settings. The default is off: a tenant that has never opted in has no public surface at all.
The gate fails closed and indistinguishably. A tenant that is disabled, unknown, or pointing at an unknown queue gets the same answer to an anonymous probe:
- The availability GET returns
enabled: falsein the standard{ data, meta }envelope — the hosted page renders a friendly not-found, and the probe can’t tell whether the tenant exists. - The booking POST returns
422 INVALID_TENANT— one generic shape for “not accepting bookings,” whether the tenant is missing or merely opted out.
public_appointment_booking key, optionally with branding (logo_url, primary_color, business_name) and copy (headline, body, footer) overrides. Every value the public page serves is sanitised server-side before it reaches a customer: the logo must be an http(s) URL, the color must be a 3- or 6-digit hex value, and free-form copy is truncated at a bound — so a malformed setting can never inject an external script or an off-platform URL into the page.
3. Payload contract
Send the booking POST as JSON:
A successful booking returns
201 with the appointment id, its status, the queue_id, and the slot_start / slot_end window. The failure shapes a hosted page handles:
Per-DID routing needs no configuration on this surface: the booking resolves to the queue’s saved place in line, and dispatch uses the caller-id and routing already configured on that queue — the public payload never picks an outbound route.
4. Abuse posture for unauthenticated intake
An endpoint anyone on the internet can reach needs a defence that doesn’t depend on a secret. The public pair layers three, and the hosted page should survive each failing:- The opt-in gate (off by default) narrows the reachable surface to tenants who chose to publish.
- A per-IP rate limit on the shared public-unauthenticated bucket caps each caller at a small request budget per minute — the first defence against scripted slot-scraping and booking floods. A page that exceeds it receives a 429 and should back off.
- The service validation re-checks schedule hours, lead time, and per-slot capacity on every write, so a scripted POST can’t manufacture a slot the availability read would never have offered.
5. How this interacts with operator-side scheduling
The public pair is a read and write window into data the operator already owns:- The queue’s bookable hours are defined by operator-side scheduling (the signed-in dashboard surface that publishes slots); the public availability read only re-exposes them, and a queue with no published hours returns
NO_BOOKABLE_SCHEDULEto public bookers. - A public booking persists as a scheduled callback request — the same row type an agent’s wrap-up appointment or an operator-booked slot produces — and moves through the same dispatcher and outcome statuses (
pending→dialing→connected/failed/abandoned/canceled). - Operators watch and control it from the same Voice → Callbacks list the queue callback model describes, with the same cancel / retry / re-prioritize controls.
6. Worked example
Read the slots (tenantacme, queue q_support, granular 15-minute slots):
7. Compliance posture
Enabling public booking is a tenant-owned control: the opt-in flag lives in the tenant’s own organization settings, and the platform neither mandates nor defaults it on. The tenant decides which queues to publish, what their bookable hours are, and whether the public surface exists at all; disabling the flag returns the surface to its probe-proof disabled shape with no residue. A customer’s booking is recorded as their consent to be called at the chosen slot, in parity with the consent the IVR callback offer records; the platform’s audit trail keeps the caller’s number masked. Calling windows and emergency-number guards that apply to any outbound callback apply here unchanged — a booked slot never dispatches outside the recipient’s permitted window. Consult your own counsel on the calling-consent rules that apply in your jurisdiction; the platform provides the recording mechanism, not the legal determination.Related
- The queue callback model — the operator-side lifecycle and outcome statuses a public booking joins.
- Set up and run voice queues — define the queue whose hours the public page publishes.
- Voice queue callbacks with SLA policies and scheduling — the API field inventory for scheduled callbacks, including the
scheduled_forwindow the public pair writes.