English
English
Appearance
English
English
Appearance
Public REST API for the PBX Module (Extensions / CDR / Click-to-Call / Queue / Webhooks). Authentication: Bearer Token (user session). Base URL: provisioned per customer — see the Base URL section.
The PBX API lets a customer CRM:
pbx.call.ringing / answered / hangup / cdr.created).| Term | Description |
|---|---|
| Extension | A SIP extension — registers to Zorio PBX using extension_number + sip_password |
| Account | Each customer has fully isolated data |
| CDR | Call Detail Record — one record per call (in/out/internal/local) |
| Click-to-Call | Originate a two-leg call from the API: A-leg dials the agent extension, B-leg dials the customer number |
| Queue | A queue — agents (Tier) answer based on a strategy (round-robin, longest-idle, ...) |
| Tier | Priority level within a queue (tier_level 1-9); tier_position orders agents within the same level |
| Webhook | An HTTPS URL where Zorio POSTs events to the customer CRM (pbx.call.ringing / pbx.call.answered / pbx.call.hangup / pbx.cdr.created) |
| HMAC | Header X-Zorio-Signature: sha256=hex(hmac_sha256(secret, body)) for verification |
| Idempotency | Header X-Zorio-Delivery: <UUID> — clients use this to dedupe on retry |
1. Login POST /api/auth/login → Bearer token
2. Create extension POST /api/pbx/extensions → returns sip_password once
3. Register webhook Admin Console UI (NOT via API)
4. Click-to-call POST /api/pbx/calls/click-to-call → 202 call_uuid
5. Receive events Zorio POSTs to your URL: pbx.call.ringing → pbx.call.answered → pbx.call.hangup
6. Query CDR GET /api/pbx/cdr?from=&to=&extension=
7. Download recording GET /api/pbx/cdr/{uuid}/recording → 302 signed URL TTL 30 minutesEndpoint: POST /api/auth/login
Request Body (JSON)
{
"username": "admin",
"password": "<password>"
}Response Body (JSON) — 200
{
"data": {
"user": {
"id": 1,
"username": "admin",
"email": "admin@example.com",
"role": "admin",
"tenant_id": 1
}
},
"token": "1|abcdefghijklmnopqrstuvwxyz0123456789"
}Authorization: Bearer <token>
Accept: application/jsonThe user must have the pbx_api_access permission (built into the admin role).
| Group | Documentation | Description |
|---|---|---|
| Extensions | Go to page | CRUD + change SIP password + list available numbers |
| Call history (CDR) | Go to page | Query CDR with filters + signed-URL recording download |
| Click-to-Call | Go to page | Originate a two-leg call from the API |
| Queue | Go to page | CRUD queues + manage agent tiers |
| PBX webhook events | Go to page | Payload schema + HMAC verification + retry policy |
Every list endpoint uses ?page=1&per_page=50 (max 200). Response:
{
"current_page": 1,
"data": [],
"last_page": 5,
"per_page": 50,
"total": 234
}{ "data": {} }{
"message": "Short error description",
"errors": { "field_name": ["Detailed description"] }
}All datetimes are returned as ISO 8601 with offset (+00:00 = UTC).
| Endpoint group | Limit |
|---|---|
/api/pbx/calls/click-to-call | 10 req/min/token |
/api/pbx/* (every other endpoint) | 60 req/min/token |
Exceeding the limit returns HTTP 429 with header Retry-After: <seconds>.
| HTTP | When |
|---|---|
| 200 | OK |
| 201 | Created (new resource) |
| 202 | Accepted (click-to-call enqueued) |
| 401 | Token missing / invalid / expired — re-login |
| 403 | Token is valid but missing permission pbx_api_access |
| 404 | Resource does not exist within the token's account scope |
| 409 | Conflict (e.g. extension already in the queue) |
| 422 | Validation failure (see errors for field details) or business-rule violation |
| 429 | Rate limit hit |
| 500 | Server error (report to the Zorio team) |
| 502 | Click-to-call: Zorio PBX refused to originate |
| URL | |
|---|---|
| Production | https://app.zorio.vn/api/pbx/ (provisioned per customer) |
Q1: My webhook URL is temporarily blocked (e.g. CDN). How long does Zorio retry?
A: 4 attempts, total ~36 minutes. After that the delivery moves to the deadletter queue — you must re-register the webhook after fixing the issue.
Q2: Click-to-call failed — how do I distinguish "agent did not pick up" vs "customer did not answer"?
A: After pbx.call.hangup fires, check hangup_cause:
NORMAL_CLEARING + billsec > 0: both parties picked up; call succeeded.NO_ANSWER: one of the two parties did not pick up.USER_BUSY: the destination number was busy.Q3: I only want events for a specific extension, not the whole account.
A: Webhook subscriptions are currently account-wide. Per-extension filtering is not yet supported.
Q4: I need a test account before integrating with production.
A: Contact Zorio to be provisioned a separate test account.