Introduction
Welcome
The LAM Voice API lets your application place and follow voice calls: deliver a passcode by phone, broadcast a spoken message to a whole contact base, run calling campaigns, and read back your call history for billing or CRM purposes.
Everything is driven from your own system over HTTPS.
| I want to… | Start here |
|---|---|
| Read a one-time passcode out to a customer | POST /api/v1/voice-otp |
| Broadcast a message I typed to thousands of contacts | POST /api/v1/voice-push |
| Run a campaign from an audio file I recorded | POST /api/v1/campaigns |
| Feed my CRM with what happened on my calls | GET /api/v1/calls |
| Check how much credit I have left | GET /api/v1/balance |
Authentication
Base URL: https://voice-gateway.lafricamobile.com
Every request carries your API key in a header:
curl "https://voice-gateway.lafricamobile.com/api/v1/calls" \
-H "x-api-key: YOUR_API_KEY"
Your account is derived from the key, so a key only ever sees and calls your own data — never another customer's.
Generate a key from the dashboard under API Keys (this requires the API access capability on your account).
The key is displayed once and only once. Store it somewhere safe before closing the dialog — if you lose it, you have to create a new one.
Capabilities
Each endpoint sits behind one or more capabilities enabled on your account. Calling an endpoint
whose capability is off returns 403. Every operation in this reference states which capability
it needs; here is the map:
| Capability | Unlocks |
|---|---|
VOICE_OTP | Passcode calls |
TTS | Turning a text into speech, and voice push |
CAMPAIGNS | Campaigns and contact groups |
AUDIO | The audio library |
SIP_CALLS, INBOUND, IVR | Other calling products — any one of them also opens the call log |
GET /api/v1/balance needs no capability: every account has a wallet and is billed, so you can
always read your own credit.
TTS is off by default. Broadcasting free text at scale is a sensitive capability, so it is
granted deliberately rather than enabled for everyone. If you get a 403, ask your account manager
to switch on the capability named in this reference.
Your first voice push
The shortest useful path, end to end:
# 1. Create a contact group and keep its id
curl -X POST "https://voice-gateway.lafricamobile.com/api/v1/contacts/groups" \
-H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"name":"Dakar customers"}'
# → { "id": "3f2a1b4c-...", ... }
# 2. Feed it (1000 contacts max per request, repeat as needed)
curl -X POST "https://voice-gateway.lafricamobile.com/api/v1/contacts/groups/3f2a1b4c-.../contacts" \
-H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"contacts":[{"phone":"221771234567","name":"Awa Diop"},{"phone":"221781814903"}]}'
# → { "added": 2, "failed": 0, "total": 2 }
# 3. Broadcast a spoken message to the group
curl -X POST "https://voice-gateway.lafricamobile.com/api/v1/voice-push" \
-H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"name":"Payment reminder","text":"Hello, your invoice is due on September 15th.","contactGroupId":"3f2a1b4c-..."}'
# → { "campaignId": "c1d2e3f4-...", "status": "running", ... }
# 4. Follow it
curl "https://voice-gateway.lafricamobile.com/api/v1/campaigns/c1d2e3f4-.../stats" \
-H "x-api-key: YOUR_API_KEY"
# → { "total": 1500, "answered": 1120, "no-answer": 310, ... }
Phone numbers are digits only — no +, no spaces, no dashes. Write 221771234567.
Things worth knowing before you build
A voice push carries one message for everyone. The text is synthesised once and the same audio is played to every contact. There is no per-contact personalisation, and the text is frozen once the push starts — so half your base never hears one message while the other half hears another.
201 means "started", not "everyone was called". Credit is checked call by call, not up front.
If your balance runs out mid-campaign, the remaining contacts wait for a top-up rather than failing.
Check GET /api/v1/balance before launching a large campaign, and subscribe to the low_credit
notification to hear about it early.
Read available, not balance. Every call in progress holds an estimate of its cost, so your
wallet total is not what you can commit. With 1000 in the wallet and 300 held by a running campaign,
available is 700 — that is the figure to base a decision on.
Listen before you broadcast. POST /api/v1/audios/tts returns a previewUrl you can open in any
browser. On a synthesis this is the one moment where a mispronunciation can be caught — before
thousands of calls go out.
Get notified instead of polling. Register a URL with PUT /api/v1/tenants/me/webhook and we call
it when a campaign ends.
The notification is sent once, with no retry, and it is not signed. Treat it as an accelerator rather than a delivery guarantee: react to it, but keep a periodic check of your campaigns as a safety net.
Calls are billed per minute, at your account's rates, and an unanswered call is not billed. They
all show up in the call log with the serviceType of the product that placed them — PUSH_VOCAL for
a campaign or a voice push, VOICE_OTP for a passcode call.
Errors
| Code | Meaning |
|---|---|
400 | Invalid payload — the message field spells out what is wrong. |
401 | Missing or invalid API key. |
402 | Insufficient credit. |
403 | A required capability is not enabled on your account. |
404 | Unknown identifier, or not owned by your account. |
409 | Conflicting concurrent request — retry once. |
429 | Too many requests — back off and retry. |
502 | An upstream engine (speech synthesis) is unavailable. Nothing was created, so the request can be replayed as is. |
Dates are ISO 8601 in UTC (2026-09-01T12:39:22Z).
Need a hand? Write to assistance@lafricamobile.com.