API reference
Every VisitorFlow entity is reachable via the REST API at https://api.visitorflow.com/v1. All requests are authenticated, JSON in, JSON out, and rate-limited per tenant. The full machine-readable spec lives at /docs/api/openapi.
Authentication
Generate an API key from Settings → API & webhooks → New key. Keys are scoped: vfp_live_* for production, vfp_test_* for the sandbox. Pass the key as a Bearer token on every request.
curl https://api.visitorflow.com/v1/visits \
-H "Authorization: Bearer vfp_live_..."Kiosk endpoints under /v1/kiosk/* use a separate device token issued by the pairing flow — those tokens carry the tenant + location implicitly so the body cannot inject a different tenant.
Rate limits
Default budgets per tenant: 600 read req/min, 120 write req/min. Burst is allowed up to 2× for 10 seconds. Hitting the limit returns 429 Too Many Requests with retry-after in seconds. Enterprise plans get custom budgets.
Versioning
The URL prefix carries the major version (/v1/). Additive changes (new fields, new optional params) ship without a version bump. Breaking changes get a new prefix and a 12-month overlap.
Create a visitor visit
POST /v1/visits
{
"type": "visitor",
"host_id": "h_98412",
"visitor": {
"name": "Marisol Cruz",
"email": "marisol@acme.com",
"company": "Acme Co"
},
"location_id": "loc_mty_01"
}
201 Created
{
"id": "vis_2YZ4...",
"checked_in_at": "2026-04-30T14:21:09Z",
"host_notified": true
}Create a driver visit
POST /v1/visits
{
"type": "driver",
"driver": { "name": "J. Pérez", "license_number": "LIC-1234" },
"shipment": { "bol_ref": "BOL-88412", "type": "delivery", "hazmat": false },
"vehicle": { "tractor_plate": "ABC-1234", "trailer_plate": "TR-998" },
"location_id": "loc_mty_01"
}Pre-register a visitor
POST /v1/pre-registrations
{
"host_id": "h_98412",
"visitor": { "name": "Andrés López", "email": "andres@acme.com" },
"scheduled_at": "2026-05-02T15:00:00Z",
"window_minutes": 60
}VisitorFlow emails the visitor a signed QR; the kiosk decodes it and skips straight to photo + NDA. The QR PNG is also reachable at GET /v1/prereg/qr/{id}.png if you want to embed it in your own emails.
List visits
GET /v1/visits?location_id=loc_mty_01&status=onsite
200 OK
{
"data": [{ "id": "vis_2YZ4...", ... }],
"next_cursor": "eyJsYXN0SUQiOi..."
}Check out a visit
PATCH /v1/visits/vis_2YZ4
{ "status": "checked_out" }List incidents
GET /v1/incidents?status=open
200 OK
[
{
"id": "inc_xy12",
"severity": "low",
"type": "tailgating",
"summary": "Visitor entered without badge scan",
"status": "open"
}
]Errors
Errors follow the JSON:API problem shape. 4xx means you sent something invalid; 5xx means we did. Every response includes an x-request-id header — quote it when contacting support.
401 Unauthorized
{ "error": "Bearer token missing or expired" }
400 Bad Request
{
"error": "Invalid payload",
"issues": {
"fieldErrors": { "visitor.email": ["Invalid email"] }
}
}Webhooks
Subscribe to events instead of polling. Every delivery is signed with x-vf-signature: sha256=... and replays with exponential backoff up to a 24h cap. See the webhooks guide.
Looking for SDKs? TypeScript and Python SDKs ship the same week as the public beta. For the canonical schema, fetch the OpenAPI 3.1 document.