Agent API.
Read-only REST routes for tenants, bookings, services, and availability.
Agent API
VoxelBooking includes a small read-only REST API for external automation, reporting scripts, and custom integrations.
The API is intentionally narrow in v1. It can read operational booking data. It cannot create tenants, create bookings, change availability, publish content, upload assets, or run prompts.
Base URL
All Agent API routes live under:
/api/agent/v1
Example:
curl https://your-domain.com/api/agent/v1/schema
What exists in v1
| Method | Route | Auth | Scope | Purpose |
|---|---|---|---|---|
GET |
/api/agent/v1/schema |
No | None | Return the OpenAPI 3.0.3 schema |
GET |
/api/agent/v1/tenants |
Yes | tenants:read |
List businesses |
GET |
/api/agent/v1/bookings |
Yes | bookings:read |
List bookings for one business |
GET |
/api/agent/v1/services |
Yes | services:read |
List services for one business |
GET |
/api/agent/v1/availability |
Yes | availability:read |
List available staff schedule rows for one business |
Authentication
Authenticated routes require a Bearer token:
Authorization: Bearer vb_your_api_key
Accept: application/json
API keys are stored in the api_keys table as SHA-256 hashes. The raw key is shown only when created. The stored record includes:
| Field | Purpose |
|---|---|
name |
Human label for the key |
key_hash |
SHA-256 hash of the raw key |
key_prefix |
First 8 characters, used for identification |
scopes |
JSON array of granted scopes |
role |
agent or viewer |
is_active |
Whether the key can be used |
last_used_at |
Updated after successful authentication |
expires_at |
Optional expiry time record |
Roles and scopes
The current authentication engine defines two roles:
| Role | Default behavior |
|---|---|
viewer |
Read-only scopes across tenants, bookings, services, availability, customers, settings, and reports |
agent |
Read and write scopes are defined internally, but v1 routes expose only read routes |
Only the scopes used by the current routes matter for v1:
tenants:readbookings:readservices:readavailability:read
If a key does not include the required scope, the API returns 403.
Rate limit
Authenticated Agent API requests are limited to 60 requests per minute per API key. When the limit is reached, the API returns:
{
"error": "rate_limited",
"message": "Rate limit exceeded. Please wait before making more requests.",
"retry_after": 60
}
Public schema
The schema route is public so tools can discover the contract before authenticating:
curl https://your-domain.com/api/agent/v1/schema
The response is an OpenAPI 3.0.3 document with paths, parameters, response schemas, and required scopes.
List tenants
Returns businesses visible to the installation.
curl https://your-domain.com/api/agent/v1/tenants \
-H "Authorization: Bearer vb_your_api_key" \
-H "Accept: application/json"
Required scope:
tenants:read
Response fields:
| Field | Description |
|---|---|
id |
Tenant ULID |
name |
Business name |
slug |
Public booking page slug |
status |
Tenant status |
timezone |
Tenant timezone |
locale |
Tenant locale |
currency |
Tenant currency |
booking_pattern |
timeslot, resource, capacity, or event |
created_at |
Creation time record |
Example response:
{
"data": [
{
"id": "01HTENANT0000000000000000",
"name": "Salon Bella",
"slug": "salon-bella",
"status": "active",
"timezone": "Europe/Amsterdam",
"locale": "en",
"currency": "EUR",
"booking_pattern": "timeslot",
"created_at": "2026-05-04 09:30:00"
}
]
}
List bookings
Returns bookings for one tenant. The tenant_id query parameter is required.
curl "https://your-domain.com/api/agent/v1/bookings?tenant_id=01HTENANT0000000000000000&limit=25" \
-H "Authorization: Bearer vb_your_api_key" \
-H "Accept: application/json"
Required scope:
bookings:read
Query parameters:
| Parameter | Required | Notes |
|---|---|---|
tenant_id |
Yes | Tenant ULID |
status |
No | Filter by status |
limit |
No | Defaults to 50, maximum 100 |
offset |
No | Defaults to 0 |
Response fields include booking id, tenant id, service id, staff id, customer id, start and end time, status, source, consent flag, and creation time record. Internal notes and sensitive fields are not returned.
List services
Returns services for one tenant. The tenant_id query parameter is required.
curl "https://your-domain.com/api/agent/v1/services?tenant_id=01HTENANT0000000000000000" \
-H "Authorization: Bearer vb_your_api_key" \
-H "Accept: application/json"
Required scope:
services:read
Response fields:
| Field | Description |
|---|---|
id |
Service ULID |
name |
Service name |
description |
Optional service description |
duration_minutes |
Duration in minutes |
price |
Optional price |
color |
Service color |
sort_order |
Display order |
is_active |
Boolean active flag |
List availability
Returns available staff schedule rows for one tenant. The tenant_id query parameter is required.
curl "https://your-domain.com/api/agent/v1/availability?tenant_id=01HTENANT0000000000000000" \
-H "Authorization: Bearer vb_your_api_key" \
-H "Accept: application/json"
Required scope:
availability:read
Response fields:
| Field | Description |
|---|---|
staff_id |
Staff ULID or null |
day_of_week |
Integer weekday |
start_time |
Start time |
end_time |
End time |
is_available |
Returned rows are available |
The current implementation returns schedule rows. It does not calculate free appointment slots for a requested service or date.
Error responses
Missing Bearer token:
{
"error": "unauthorized",
"message": "Missing or invalid Authorization header. Use: Authorization: Bearer <api_key>"
}
Invalid, expired, or inactive key:
{
"error": "unauthorized",
"message": "Invalid or expired API key."
}
Missing scope:
{
"error": "forbidden",
"message": "This route requires the 'bookings:read' scope."
}
Missing tenant_id:
{
"error": "validation",
"message": "tenant_id is required"
}
What the Agent API does not do
The v1 Agent API does not include:
- Creating or updating bookings
- Creating or updating tenants
- Creating or updating services
- Changing availability
- Reading customers directly
- Writing settings
- Uploading files
- Publishing pages
- Triggering background jobs
- Payment processing
- Calendar sync
Use the admin panel for write operations.
Related docs
Ready to build?
One-time purchase. Self-hosted. Own every file forever.