Voepy Developer Docs
Build voice into your product with one HTTP API. Buy phone numbers, place and receive calls, record audio, stream media in real time, run IVR menus, and get charged per second of actual usage.
This is the customer-facing guide set. Pick a topic and start there; each page is standalone and links to the next logical step.
Start here
| Guide | What you'll learn |
|---|---|
| Getting started | Sign up, grab your API key, place your first outbound call in under five minutes. |
| Phone numbers | Search the inventory, buy a DID, configure it for voice or messaging, release when done. |
| Calls | Place outbound calls, accept inbound, control live audio (transfer, bridge, record, IVR menus, real-time transcription, AMD). |
| Webhooks | Subscribe to call events, verify the signature, handle retries and dedup. |
| Billing | Top up your balance, set up auto-recharge, manage payment methods, download invoices. |
| Error reference | Every error code the API can return and what to do about each one. |
Conventions
- JSON in, JSON out. All request and response bodies are JSON. Field
names are
snake_case. - Phone numbers are always E.164. Format:
+followed by 6–15 digits. Example:+15125550100. No spaces, no dashes. - Money is in cents. A $25.00 top-up is
amount_cents: 2500. Currency is USD only at launch. - IDs are opaque, prefixed strings. A call is
voepy_call_01H…, a leg isvoepy_leg_…, a recording isvoepy_rec_…, a route isvoepy_route_…. Treat them as strings. - Timestamps are ISO-8601 with timezone. Example:
2026-05-12T14:32:18.000Z. - Idempotency: every mutating endpoint accepts an
Idempotency-Keyheader. Retrying with the same key returns the original response instead of executing twice. Use a UUID per logical operation. - Pagination: list endpoints take
cursorandlimitquery parameters. The response includesnext_cursor(null on the last page). Do not parse the cursor — opaque by design.
Authentication
Every request needs your API key in the Authorization header:
Authorization: Bearer voepy_live_<your-key>
You receive the plaintext key exactly once at signup. Lose it and you'll have to rotate. See Getting started.
Two things to know:
- API keys are tenant-scoped. They identify your account and
carry the right scopes (e.g.
calls:write,billing:read). - Never expose your key in browser code. Treat it like a password. Server-side only. If you need a browser to call us, proxy through your own backend.
Errors
Every 4xx and 5xx response has the same shape:
{
"error": {
"code": "balance_insufficient",
"message": "Tenant balance is exhausted; top up to place new calls."
}
}
The HTTP status mirrors the category (400/401/402/403/404/409/422/429/ 5xx). Full table in Error reference.
Where to ask for help
- Bug reports / feature requests: open a ticket in your dashboard.
- Live integration support during onboarding: your account contact.
