> ## Documentation Index
> Fetch the complete documentation index at: https://docs.voxhealth.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Security

> Tokens, the domain allow-list, and rate limits.

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](/developers/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:

| Action                | Limit                                               |
| --------------------- | --------------------------------------------------- |
| Availability          | 60 per hour, per client                             |
| Start booking         | 10 per hour, per client                             |
| Manage an appointment | 10 per hour per client, 5 per hour per phone number |
| ZIP geocoding         | 10 per hour, per client                             |
| Payer search          | 120 per hour, per client                            |

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

<Steps>
  <Step title="The allow-list holds only real domains">
    Remove staging hosts when you are done with them.
  </Step>

  <Step title="The snippet is not committed to a public repo with a stale token">
    It will still be a valid token until someone regenerates it.
  </Step>

  <Step title="The page is served over HTTPS">
    The widget refuses to be useful on an insecure origin, and browsers block geolocation there anyway.
  </Step>

  <Step title="A test booking lands correctly, then cancel it">
    Both paths, not just booking.
  </Step>
</Steps>
