Zencia API
Welcome to the Zencia API — a programmatic interface to the same voice agent platform you use from your dashboard.
With it you can create and configure voice agents, place outbound phone calls, retrieve transcripts and recordings, and embed conversational widgets on your own websites. Everything in the dashboard is built on this API; nothing is hidden behind a separate admin surface.
The Zencia public API is currently in beta. Endpoints and field names may evolve before the 1.0 release.
Quickstart — make your first call in 3 steps
- Get an API key. Head to Settings → Developer, give your key
a memorable name, and click Create key. Copy the raw
zsk_…value immediately — Zencia never stores it in plain text, so you cannot retrieve it later. - Confirm the key works.
You should receive:curl https://app.zencia.ai/api/dev/usage \ -H "Authorization: Bearer YOUR_API_KEY"{ "plan": "free", "extra_minutes": 30, "minutes_used": 0, "minutes_remaining": 30 } - Create an agent.
Or skip this step entirely and create agents through the dashboard — the API mirrors the dashboard 1:1.curl https://app.zencia.ai/api/agents \ -X POST \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Support Bot", "voice_id": "Sia", "voice_engine_id": "Kore", "system_prompt": "You are a friendly customer support agent." }'
Bearer token authentication
All API requests are authenticated using a bearer token in the
Authorization header:
Authorization: Bearer zsk_abc123…
Zencia API keys are prefixed with zsk_ followed by 32 URL-safe
random characters. They have no expiration until you revoke them.
Where to get a key
Open your dashboard, navigate to Settings → Developer, and click Create key. You can create as many keys as you need (one per server, environment, integration, etc.) and revoke any of them at any time.
Security
- Treat your API key like a password. Never commit it to a public Git repository.
- Use environment variables (
process.env.ZENCIA_API_KEY) on your server. - If a key is exposed, revoke it immediately — revoked keys stop working within seconds.
- Keys are stored only as SHA-256 hashes — even Zencia staff cannot retrieve a leaked key for you.
API keys grant full access to your agents, calls, and recordings. They must only be used from server-side code or trusted environments. For browser-embedded voice widgets, use the public widget token instead — it's designed to be safely embedded on customer sites.
Error responses
Zencia uses conventional HTTP status codes. Errors always return a JSON body
with a detail field describing what went wrong.
{ "detail": "Invalid or revoked API key" }
| Code | Meaning | What to do |
|---|---|---|
| 200 | OK | Request succeeded. |
| 201 | Created | Resource created. Response body has the new record. |
| 204 | No Content | Operation succeeded; nothing to return (e.g. delete). |
| 400 | Bad Request | Your request body is malformed. Check the field listed in detail. |
| 401 | Unauthorized | Missing or invalid Authorization header. Check the API key. |
| 402 | Payment Required | Out of plan minutes. Top up or upgrade your plan. |
| 403 | Forbidden | Authenticated, but this resource belongs to another account. |
| 404 | Not Found | Resource doesn't exist or was deleted. |
| 422 | Unprocessable Entity | Validation failed on a specific field. detail lists which. |
| 429 | Too Many Requests | You're hitting rate limits. Back off and retry. |
| 500 | Server Error | Retry with backoff; if persistent, contact support. |
Rate limits & quotas
Zencia enforces two kinds of limits:
- Request rate limit — REST API requests are limited to
60 requests per minute per API key. Burst capacity is 100
requests in any 10-second window. Excess requests receive
429 Too Many Requests. - Voice-minute quota — Live voice calls (dashboard, widget,
Twilio, or API) consume minutes from your plan's monthly allowance. When you
reach zero, new calls are refused with
402 Payment Required; in-progress calls finish normally.
Check your current quota at any time via GET /api/dev/usage.
An API key is a credential, not a separate billing line. All calls made under your account share the same minute pool.
Agents
Voice agents are the central resource in Zencia. Each agent has a personality (system prompt), a voice (one of 30+ premium voices), an optional knowledge base, an optional first message, and a public widget token for embedding.
Endpoints
| Method | Path | Description |
|---|---|---|
| GET | /api/agents | List every agent you own. |
| GET | /api/agents/{agent_id} | Get a single agent. |
| POST | /api/agents | Create a new agent (widget_token auto-generated). |
| PATCH | /api/agents/{agent_id} | Partially update an agent — send only changed fields. |
| DELETE | /api/agents/{agent_id} | Permanently delete an agent (204). |
| POST | /api/agents/generate-prompt | Generate a voice-ready system prompt + greeting from a structured description. |
Create agent — required fields
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | yes | Display name, 1–80 chars. |
| voice_id | string | yes | Display voice name, e.g. "Sia". |
| voice_engine_id | string | yes | Underlying voice engine ID, e.g. "Kore". |
| system_prompt | string | yes | The agent's instructions, ≥1 char. |
| description | string | no | Short one-line summary (≤200 chars). |
| knowledge_base | string | no | Reference material injected on every call. |
| first_message | string | no | Greeting spoken when a call connects. |
| languages | array | no | e.g. ["English","Hindi"]. |
curl https://app.zencia.ai/api/agents \
-X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Support Bot",
"voice_id": "Sia",
"voice_engine_id": "Kore",
"system_prompt": "You are a friendly customer support agent."
}'
Tools (webhook actions)
Tools let an agent take real actions mid-conversation — book a slot, create a lead, look up an order — by calling an HTTP endpoint you control. When the model decides a tool is needed, it fills the parameters from the conversation, Zencia calls your webhook, and the response is fed back into the conversation.
There is no separate "tools" resource. Tools are an array on the agent —
you create, update, and remove them through PATCH /api/agents/{agent_id}
by sending the full tools array. To disable one without deleting
it, set enabled: false.
The description tells the model when to use the tool.
Do not write the call format into your system prompt — the model will recite it
as text instead of invoking the tool. Let the function declaration do its job.
The Tool object
{
"id": "tl_8x2k",
"enabled": true,
"name": "book_site_visit",
"description": "Use when the customer agrees to a date and time.",
"parameters": [
{ "name": "visitor_name", "type": "string", "description": "Full name", "required": true }
],
"method": "POST",
"url": "https://your-server.com/api/book-visit",
"headers": [{ "key": "X-Source", "value": "zencia" }],
"body_template": "{\"name\":\"{{visitor_name}}\"}",
"auth": { "type": "none" },
"timeout_ms": 10000
}
{{param_name}} placeholders in url, headers, and
body_template are substituted with the model's arguments. The
webhook response (status + body, truncated to 100 KB) is returned to the model.
The webhook is called from Zencia's servers, not the browser. URLs that
resolve to localhost or private/loopback IP ranges are rejected.
For local development, expose your machine with ngrok or a similar tunnel.
Built-in tools (toggled by an agent flag, not defined as webhooks)
| Tool | Agent flag | What it does |
|---|---|---|
| end_call | auto_end_call | Hangs up gracefully after the user says goodbye. |
| memory | memory_enabled | Per-customer memory across calls. |
| send_sms | sms_enabled | Texts the person on the call (needs Twilio connected). Hard cap 3 SMS/call. |
| send_whatsapp | whatsapp_enabled | Sends an approved WhatsApp template to the caller. |
| transfer_to_human | transfer_enabled | Hands the call to a real person. Per-call cap: 1. |
Test a tool without going through the model:
POST /api/agents/{agent_id}/tools/test with a tool
object and sample args — returns the full request/response trace.
Telephony — Bonvoice
Bonvoice is an India-focused PBX supporting both inbound and outbound calling, wired up per operator account (one DID per operator).
- Inbound — dialing your Bonvoice DID opens a WebSocket to
our backend; we resolve the operator by DID and pick the agent whose
channels.bonvoicematches. - Outbound —
POST /api/calls/bonvoice/outboundwith anagent_idand destination number.
Key endpoints
| Method | Path | Description |
|---|---|---|
| POST | /api/integrations/bonvoice/connect | Store credentials + auto-register the inbound route. |
| GET | /api/integrations/bonvoice/status | Current connection state + manual_endpoint URL. |
| DELETE | /api/integrations/bonvoice/disconnect | Remove stored credentials (route on Bonvoice's side must be removed separately). |
| POST | /api/calls/bonvoice/outbound | Place an outbound call from your DID. |
| GET | /api/calls/bonvoice/{event_id}/status | Poll live call status. |
Assign a DID to an agent: PATCH /api/agents/{id} with
{ "channels": { "bonvoice": "8037281844" } } — use the canonical
format (no + prefix, no leading zeros).
Telephony — VoiceLink
VoiceLink is similar to Bonvoice but supports multiple DIDs per account, each routed independently to a specific agent.
- Connect —
POST /api/integrations/voicelink/connectonce with your PBX credentials. - Register a DID —
POST /api/integrations/voicelink/didscreates a WebSocket bot + routing rule for that DID. - Inbound — VoiceLink opens a WebSocket to our backend; we resolve the agent from the DID's route doc.
- Outbound —
POST /api/calls/voicelink/outbound, optionally choosing which of your DIDs to dial from.
| Method | Path | Description |
|---|---|---|
| GET | /api/integrations/voicelink/dids | List your registered DIDs + your agents. |
| GET | /api/integrations/voicelink/dids/available | List DIDs you own but haven't registered yet. |
| PATCH | /api/integrations/voicelink/dids/{did} | Reassign a DID to a different agent. |
| DELETE | /api/integrations/voicelink/dids/{did} | Remove the local route (DID stays in your VoiceLink account). |
DIDs are normalized by stripping leading + and zeros, e.g.
919559050094, not +919559050094.
WhatsApp (Meta Cloud API)
WhatsApp is integrated via Meta's WhatsApp Cloud API. Current scope is
outbound only — agents send pre-approved template messages to
the person on a voice call via the built-in send_whatsapp tool.
Meta lets businesses reply freely only within 24 hours of the customer
messaging first. A voice-call-triggered send is by definition first contact,
so send_whatsapp only sends approved templates.
| Method | Path | Description |
|---|---|---|
| POST | /api/integrations/whatsapp/connect | Validate + store phone_number_id, access_token, waba_id. |
| GET | /api/integrations/whatsapp/status | Connection state. |
| GET | /api/integrations/whatsapp/templates | Live refetch of approved/pending/rejected templates. |
| PATCH | /api/integrations/whatsapp/templates | Replace the allow-list of templates the agent may use. |
Recipient safety mirrors send_sms: the agent can only message the
person currently on the call. Hard cap of 3 messages per call.
Calls & recordings
A call is one conversation between a person and one of your agents. Calls can be initiated from the dashboard, an embedded widget/share link, Twilio outbound, or Bonvoice/VoiceLink. Every call produces a transcript and, optionally, an audio recording.
| Method | Path | Description |
|---|---|---|
| GET | /api/calls | List recent calls, newest first (transcript omitted). |
| GET | /api/calls/{call_id} | Get one call including its full transcript. |
| GET | /api/calls/{call_id}/recording | Signed download URL, expires in 1 hour. |
| DELETE | /api/calls/{call_id}/recording | Permanently delete the audio (metadata + transcript kept). |
| POST | /api/calls/outbound | Place an outbound call via your connected Twilio number. |
Recordings are stereo — left channel is the caller, right channel is the agent.
Usage & quota
GET /api/dev/usage returns your current plan, total monthly
minutes, used minutes, and remaining minutes. Call this before initiating long
calls to back off gracefully when you're near zero.
{
"plan": "free",
"extra_minutes": 30,
"minutes_used": 12,
"minutes_remaining": 18
}
API keys
You can manage API keys programmatically — useful if you're onboarding a customer account from your own admin tools.
| Method | Path | Description |
|---|---|---|
| GET | /api/dev/api-keys | List every key (incl. revoked). Only last 4 chars ever returned. |
| POST | /api/dev/api-keys | Create a key — the raw value is shown exactly once. |
| DELETE | /api/dev/api-keys/{key_id} | Soft-revoke a key (kept in the audit trail). |
Webhooks
Subscribe URLs to receive HTTP POST notifications when calls start, end, or finish processing, with HMAC signatures for verification:
call.started·call.ended·call.failedtranscript.ready·recording.uploaded- Per-event subscriptions, automatic retries with exponential backoff, and a test event sender from the dashboard.
Official SDKs
- Node.js / TypeScript (
@zencia/sdk) - Python (
zencia) - Go (
github.com/zencia/zencia-go)
In the meantime, the REST API is straightforward to call from any HTTP client.
Changelog
Breaking changes, new endpoints, and field additions will be documented here.
Need help? support@zencia.ai