API Reference
The VoiceZero REST API gives you programmatic access to every voice message, AI insight, and inbox in your account. Base URL: https://api.voicezero.ai/v1
Authentication
All API requests require a secret API key passed as a Bearer token in the Authorization header. Keys are scoped to specific permissions and can be rotated independently.
API Key Format
VoiceZero issues two types of keys:
- Secret keys (
vzsk_prefix) — full read/write access. Never expose in client-side code or public repositories. - Restricted keys (
vzrk_prefix) — scoped to specific inboxes or read-only operations. Safe for server-side webhook consumers.
Example request
curl https://api.voicezero.ai/v1/messages \
-H "Authorization: Bearer vzsk_live_a4c8e2f91b3d7065ae1482fc309b5d74" \
-H "Content-Type: application/json"
const res = await fetch('https://api.voicezero.ai/v1/messages', {
headers: {
'Authorization': `Bearer ${process.env.VZ_SECRET_KEY}`,
'Content-Type': 'application/json'
}
});
const data = await res.json();
Base URL
All responses are JSON. Timestamps are ISO 8601 in UTC. Paginated endpoints use cursor-based pagination via ?cursor= and ?limit= (max 100).
Errors
VoiceZero uses standard HTTP status codes. Error bodies follow a consistent JSON shape:
{
"error": {
"code": "auth/invalid_key",
"message": "API key is expired or revoked. Rotate keys in Dashboard → Settings → API Keys.",
"status": 401
}
}
| Status | Code | Meaning |
|---|---|---|
| 200 | — | Success |
| 400 | invalid_params | Missing or invalid request parameters |
| 401 | auth/invalid_key | API key missing, expired, or revoked |
| 403 | auth/insufficient_scope | Key doesn't have permission for this operation |
| 404 | not_found | Resource does not exist or is not accessible with this key |
| 429 | rate_limited | Too many requests — see rate limits |
| 500 | internal_error | Server error — retry with exponential backoff |
Rate Limits
| Plan | Requests / min | Requests / day |
|---|---|---|
| Signal (free) | 20 | 500 |
| Listen | 60 | 5,000 |
| Understand | 200 | 30,000 |
| Enterprise | Custom | Custom |
Rate limit headers are returned on every response: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset (Unix timestamp).
Messages
List messages
messages:read
Returns a paginated list of voice messages. By default returns the 20 most recent. Filter by inbox, date range, urgency, or sentiment score.
Query parameters
| Parameter | Type | Description |
|---|---|---|
| inbox_id | string | Filter to a specific inbox (e.g. inbox_Bx7k3N) |
| urgency | P1 | P2 | P3 | Filter by urgency level |
| sentiment_min | float (−1 to 1) | Minimum overall sentiment score |
| since | ISO 8601 | Return messages after this timestamp |
| until | ISO 8601 | Return messages before this timestamp |
| limit | integer (1–100) | Number of results per page (default: 20) |
| cursor | string | Pagination cursor from previous response |
Example request
curl "https://api.voicezero.ai/v1/messages?inbox_id=inbox_Bx7k3N&urgency=P1&limit=5" \
-H "Authorization: Bearer vzsk_live_a4c8e2f91b3d7065ae1482fc309b5d74"
Response
{
"object": "list",
"data": [
{
"id": "msg_4Xn9aQkL7vZp",
"object": "message",
"inbox_id": "inbox_Bx7k3N",
"received_at": "2026-03-01T14:22:08Z",
"duration_s": 23,
"language": "en",
"transcript": "The food was cold when it arrived and the waiter didn't come back to check. Very disappointed.",
"ai": {
"sentiment": -0.74,
"urgency": "P1",
"tone": "frustrated",
"themes": ["food_temperature", "service_quality"],
"summary": "Guest frustrated by cold food and lack of server follow-up."
},
"source": "qr",
"metadata": {
"table": "14",
"location_id": "loc_downtown"
}
}
],
"has_more": true,
"next_cursor": "cur_eyJpZCI6Im1zZ18xMjM0NTYifQ"
}
Get a message
curl https://api.voicezero.ai/v1/messages/msg_4Xn9aQkL7vZp \
-H "Authorization: Bearer vzsk_live_a4c8e2f91b3d7065ae1482fc309b5d74"
Delete a message
messages:write
Permanently deletes a message and its audio. This cannot be undone. Use for GDPR right-to-erasure requests.
curl -X DELETE https://api.voicezero.ai/v1/messages/msg_4Xn9aQkL7vZp \
-H "Authorization: Bearer vzsk_live_a4c8e2f91b3d7065ae1482fc309b5d74"
{ "deleted": true, "id": "msg_4Xn9aQkL7vZp" }
Inboxes
{
"data": [
{
"id": "inbox_Bx7k3N",
"name": "Downtown — Table Feedback",
"qr_url": "https://v0.voicezero.ai/Bx7k3N",
"whatsapp_link": "https://wa.me/15559670000?text=feedback-Bx7k3N",
"message_count": 412,
"created_at": "2025-11-03T09:14:00Z"
}
]
}
Create inbox
curl -X POST https://api.voicezero.ai/v1/inboxes \
-H "Authorization: Bearer vzsk_live_a4c8e2f91b3d7065ae1482fc309b5d74" \
-H "Content-Type: application/json" \
-d '{
"name": "Uptown — Table Feedback",
"location_id": "loc_uptown",
"escalation": {
"urgency": ["P1"],
"notify": ["[email protected]"]
}
}'
Get inbox
Analytics
Summary
{
"period": "2026-02-01/2026-02-28",
"total_messages": 1847,
"avg_sentiment": 0.31,
"urgency_breakdown": { "P1": 43, "P2": 218, "P3": 1586 },
"top_themes": [
{ "theme": "wait_time", "count": 312 },
{ "theme": "food_quality", "count": 289 },
{ "theme": "staff_friendliness", "count": 204 }
],
"languages": { "en": 1102, "es": 387, "fr": 201, "other": 157 }
}
Sentiment timeseries
Returns daily/weekly average sentiment per inbox for charting. Query params: inbox_id, since, until, granularity (day | week).
Webhooks
Webhooks push events to your endpoint in real time. Configure via Dashboard → Settings → Webhooks or via API.
curl -X POST https://api.voicezero.ai/v1/webhooks \
-H "Authorization: Bearer vzsk_live_a4c8e2f91b3d7065ae1482fc309b5d74" \
-H "Content-Type: application/json" \
-d '{
"url": "https://yourapp.com/webhooks/voicezero",
"events": ["message.received", "message.escalated"],
"secret": "your-signing-secret"
}'
Event types
| Event | Description |
|---|---|
| message.received | New voice message arrived in any subscribed inbox |
| message.escalated | Message triggered escalation rule (P1 urgency, sentiment threshold) |
| sentiment.threshold | Inbox's rolling sentiment drops below configured level |
| digest.weekly | Weekly AI digest generated — structured JSON for BI pipelines |
| inbox.created | New inbox provisioned (useful for multi-tenant deployments) |
Payload format
{
"id": "evt_9Rz2mKwY3pQx",
"event": "message.escalated",
"created_at": "2026-03-01T14:22:09Z",
"data": {
"message_id": "msg_4Xn9aQkL7vZp",
"inbox_id": "inbox_Bx7k3N",
"urgency": "P1",
"sentiment": -0.74,
"summary": "Guest frustrated by cold food and lack of server follow-up.",
"themes": ["food_temperature", "service_quality"]
}
}
Verifying signatures
Every webhook request includes a X-VZ-Signature header: HMAC-SHA256 of the raw request body signed with your webhook secret.
import crypto from 'node:crypto';
function verifyVoiceZeroWebhook(rawBody, secret, signature) {
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature.replace('sha256=', ''))
);
}
Native Integrations
Slack
Connect from Dashboard → Integrations → Slack. Once authorized, choose which inboxes and event types post to which Slack channel. No code required.
Each Slack notification includes: urgency badge, AI summary, sentiment score, and a direct link to the message in your dashboard.
Zapier
Search for VoiceZero in Zapier. Available triggers: New message, New escalation, Sentiment threshold. Available actions: Send digest to Google Sheets, create Notion page from feedback, log to Airtable.
CRM & HRIS
Feed voice feedback into customer or employee records via webhook + native integrations:
- Salesforce / HubSpot: Enrich contact records with sentiment history and feedback themes
- Workday / BambooHR: Log exit interview voice feedback to employee records
- Intercom: Create conversations from escalated voice messages for follow-up
- Zendesk / Freshdesk: Auto-create tickets from P1 urgency messages
Get your API keys
API access on the Understand plan and above. Webhook events on all plans including Signal (free).
View Pricing & Get Started