Skip to main content
The widget runs on a public web page and books real appointments into a real schedule. These are the guards that make that safe.

The public token

data-token is a public token. It is in the page source and visible to anyone. It is not a secret and it is not an API key: it identifies a practice’s widget configuration and nothing more. What it cannot do:
  • Read patient records
  • List patients, or confirm whether a given person is a patient
  • Reach any VoxHealth surface other than the widget endpoint
Regenerating a token in Settings → Scheduling Widget invalidates the previous one, so the snippet on the site must be updated at the same time.

Domain allow-list

A token answers only on the origins recorded for it. A request from anywhere else is refused. This is what stops a copied snippet working on someone else’s site. Keep the list tight: the practice’s real domains, and a staging host only while you need one. The hosted booking page is served from VoxHealth’s own booking host, which is allowed centrally rather than by each practice adding it.

Rate limits

Per-endpoint limits, keyed by client and, where it matters, by phone number: The per-phone limit on managing appointments is the important one: it is what stops the manage form being used to probe whether a given phone number has appointments at a practice.

Patient enumeration

The widget asks whether someone is a new or returning patient, and that answer stays in the browser. The server never answers it. An endpoint that will tell an anonymous caller “yes, that person is a patient here” is a patient-enumeration oracle, whatever else it is for. The question is asked only because the answer changes what the practice offers, not because the server needs it. Identity is collected after a time is chosen; the chart is matched or created server-side; an unmatched manage request simply finds no appointments, which is indistinguishable from a patient with none.

Booking races

Two visitors can want the same slot at the same moment. A slot is claimed while a booking is in flight and released if the booking does not complete, so the second visitor is offered a different time rather than double-booked on top of the first.

What to check before going live

1

The allow-list holds only real domains

Remove staging hosts when you are done with them.
2

The snippet is not committed to a public repo with a stale token

It will still be a valid token until someone regenerates it.
3

The page is served over HTTPS

The widget refuses to be useful on an insecure origin, and browsers block geolocation there anyway.
4

A test booking lands correctly, then cancel it

Both paths, not just booking.