Overview
SMSTAKE Voice is an HTTPS JSON API at https://api.smstake.com/v1/voice/. Use it for outbound dialer (OBD) broadcasts, text-to-speech calls, voice OTP as a fallback when SMS is not enough, and IVR menus that collect keypad input. Place calls only to numbers that your use case is allowed to reach. Prompts, routes and the languages enabled on an account are confirmed during onboarding.
| API | Method | Endpoint |
|---|---|---|
| Outbound voice call | POST | https://api.smstake.com/v1/voice/call |
| Voice OTP | POST | https://api.smstake.com/v1/voice/otp |
Related guides: Voice (OBD/IVR), SMS API, RCS API, and the SMSTAKE blog.
Authentication
Send one of these headers on every call to https://api.smstake.com/v1/voice/. Do not send both.
| Header | Value |
|---|---|
Authorization | Bearer YOUR_API_TOKEN |
X-API-Key | YOUR_API_KEY |
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
X-API-Key: YOUR_API_KEY
Content-Type: application/json
- Use HTTPS only.
- Store the token or API key in an environment variable. Do not commit it to source control.
- Rotate it from the SMSTAKE account, or contact support if it is exposed.
Outbound voice call
Endpoint: POST https://api.smstake.com/v1/voice/call. This places an automated outbound call. Play a file already stored on the account, or speak a script with text-to-speech. Send audio_file_id or text_to_speech, not both.
| Field | Required | Description |
|---|---|---|
phone | Yes | Recipient number in E.164, for example +919876543210 |
audio_file_id | One of these | ID of a prompt uploaded in the SMSTAKE account. Use this for a recorded OBD or IVR prompt |
text_to_speech | One of these | Script SMSTAKE speaks on the call. Use this when you do not have a recorded file |
language | With text-to-speech | Language code for the spoken script. See the language table |
callback_url | No | HTTPS URL for this call's status and DTMF events. If omitted, SMSTAKE uses the URL on the account |
client_ref | No | Your reference. It is echoed on the response and on webhooks |
Text-to-speech examples
curl -X POST "https://api.smstake.com/v1/voice/call" \
-H "Authorization: Bearer $SMSTAKE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"phone": "+919876543210",
"text_to_speech": "Your order is out for delivery today.",
"language": "en",
"callback_url": "https://yourapp.com/webhooks/smstake/voice",
"client_ref": "tts_order_1001"
}'
import os, requests
resp = requests.post(
"https://api.smstake.com/v1/voice/call",
headers={"Authorization": f"Bearer {os.environ['SMSTAKE_API_TOKEN']}"},
json={
"phone": "+919876543210",
"text_to_speech": "Your order is out for delivery today.",
"language": "en",
"callback_url": "https://yourapp.com/webhooks/smstake/voice",
"client_ref": "tts_order_1001",
},
timeout=30,
)
print(resp.json())
const res = await fetch("https://api.smstake.com/v1/voice/call", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SMSTAKE_API_TOKEN}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
phone: "+919876543210",
text_to_speech: "Your order is out for delivery today.",
language: "en",
callback_url: "https://yourapp.com/webhooks/smstake/voice",
client_ref: "tts_order_1001"
})
});
console.log(await res.json());
Recorded audio
Use audio_file_id when the prompt is already uploaded. The same clients work with an API key header instead of Bearer.
{
"phone": "+919876543210",
"audio_file_id": "audio_festive_01",
"callback_url": "https://yourapp.com/webhooks/smstake/voice",
"client_ref": "obd_festive_01"
}
curl -X POST "https://api.smstake.com/v1/voice/call" \
-H "X-API-Key: $SMSTAKE_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @call.json
Success response
Store call_id so you can match later status and DTMF webhooks.
{
"status": "accepted",
"call_id": "call_8f3k2j9x1m",
"phone": "+919876543210",
"client_ref": "tts_order_1001"
}
Voice OTP
Endpoint: POST https://api.smstake.com/v1/voice/otp. Use this when you need a spoken verification call, for example as a fallback after SMS OTP. Put the code in text_to_speech, with spaces between digits so it is read clearly. The same fields as an outbound call apply.
curl -X POST "https://api.smstake.com/v1/voice/otp" \
-H "Authorization: Bearer $SMSTAKE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"phone": "+919876543210",
"text_to_speech": "Your verification code is 4 8 2 9 1 3.",
"language": "en",
"callback_url": "https://yourapp.com/webhooks/smstake/voice",
"client_ref": "otp_login_1001"
}'
import os, requests
code = " ".join("482913")
resp = requests.post(
"https://api.smstake.com/v1/voice/otp",
headers={"X-API-Key": os.environ["SMSTAKE_API_KEY"]},
json={
"phone": "+919876543210",
"text_to_speech": f"Your verification code is {code}.",
"language": "hi",
"callback_url": "https://yourapp.com/webhooks/smstake/voice",
"client_ref": "otp_login_1001",
},
timeout=30,
)
print(resp.json())
const code = "482913".split("").join(" ");
const res = await fetch("https://api.smstake.com/v1/voice/otp", {
method: "POST",
headers: {
"X-API-Key": process.env.SMSTAKE_API_KEY,
"Content-Type": "application/json"
},
body: JSON.stringify({
phone: "+919876543210",
text_to_speech: `Your verification code is ${code}.`,
language: "hi",
callback_url: "https://yourapp.com/webhooks/smstake/voice",
client_ref: "otp_login_1001"
})
});
console.log(await res.json());
A successful OTP call returns the same shape as an outbound call, with its own call_id.
Languages
Set language when you send text_to_speech. English and Hindi are the usual starting points. Other regional Indian languages use the same field when that language is enabled on your account.
| language | Language |
|---|---|
en | English |
hi | Hindi |
bn | Bengali |
gu | Gujarati |
kn | Kannada |
ml | Malayalam |
mr | Marathi |
pa | Punjabi |
ta | Tamil |
te | Telugu |
Call status and DTMF
Register an HTTPS URL on the SMSTAKE account, or send callback_url on the request. SMSTAKE posts JSON as the call moves. Return 200 OK as soon as the event is stored. When signing is enabled, verify X-SMSTAKE-Signature against the raw body. Deduplicate on call_id plus event. For call.dtmf, also include digits, because one call can send more than one key press.
| Event | When it is sent |
|---|---|
call.initiated | SMSTAKE accepted the call and started dialling |
call.answered | The recipient answered |
call.dtmf | The recipient pressed one or more keys. digits holds those keys |
call.completed | The call has ended |
call.answered
POST https://yourapp.com/webhooks/smstake/voice
Content-Type: application/json
X-SMSTAKE-Signature: sha256=<hex-encoded HMAC-SHA256 of the raw body>
{
"event": "call.answered",
"call_id": "call_8f3k2j9x1m",
"phone": "+919876543210",
"status": "answered",
"client_ref": "tts_order_1001",
"occurred_at": "2026-10-21T14:15:08+05:30"
}
call.dtmf
Use digits to drive an IVR step, such as confirming an appointment when the recipient presses 1.
{
"event": "call.dtmf",
"call_id": "call_8f3k2j9x1m",
"phone": "+919876543210",
"digits": "1",
"client_ref": "tts_order_1001",
"occurred_at": "2026-10-21T14:15:20+05:30"
}
call.initiated and call.completed
{ "event": "call.initiated", "call_id": "call_8f3k2j9x1m", "phone": "+919876543210", "status": "initiated", "client_ref": "tts_order_1001", "occurred_at": "2026-10-21T14:15:02+05:30" }
{ "event": "call.completed", "call_id": "call_8f3k2j9x1m", "phone": "+919876543210", "status": "completed", "client_ref": "tts_order_1001", "occurred_at": "2026-10-21T14:15:41+05:30" }
HTTP status
| HTTP status | Meaning |
|---|---|
| 200 / 202 | Call accepted for dialling |
| 400 | Invalid JSON, or phone and a prompt (audio_file_id or text_to_speech) were not both present |
| 401 | Missing or invalid Bearer token or API key |
| 403 | Credentials are valid but not allowed for this action |
| 429 | Rate limit exceeded. Retry with backoff |
| 5xx | Temporary server or upstream issue. Retry with backoff |