API Reference
Place voice calls, run verification (OTP) calls, trigger saved campaigns, and check call status directly from your own systems over a simple JSON REST API.
The Agentive Voice API gives your application programmatic access to the same calling stack that powers the dashboard. Place a single outbound call, read a verification code out to a customer, run a saved campaign for one number, or poll the result of any call you started.
Every amount is in Indian Rupees (INR). Every timestamp is in Indian Standard Time (IST), in ISO 8601 format. Every request is authenticated with a publishable key and a secret, and every response uses one consistent JSON envelope so your integration code stays simple.
Every endpoint path below is relative to this base URL.
https://voice.agentive.co.in/api/public/v1Every request must be authenticated with two credentials issued to your account.
| Credential | What it is | How to send it |
|---|---|---|
| Publishable key | Your account's public lookup handle. Starts with pk_live_. | x-api-key request header |
| Secret key | Your account's private proof. Starts with sk_live_. Treat it like a password. | x-api-secret request header (preferred), or a secret field in the JSON body |
View and rotate both keys from the API tab in your dashboard. The secret is shown in full only once, when it is first generated or rotated; afterwards it is masked. If you lose it, rotate to generate a new pair, and the old secret stops working immediately.
The header form is recommended because it keeps the secret out of request bodies and most log formats. If you send the secret in both the header and the body, the header value is used. There is a single set of live credentials per account; both keys begin with a _live_ prefix and every call is processed against your live account.
As an alternative to the two headers, you may send the credentials with HTTP Basic auth, using the publishable key as the username and the secret as the password. This is the familiar curl -u form. When an x-api-key header is present it takes precedence; otherwise the Basic credentials are used.
curl https://voice.agentive.co.in/api/public/v1/account \
-u pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcurl https://voice.agentive.co.in/api/public/v1/calls \
-H "x-api-key: pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "x-api-secret: sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{ "type": "audio_blast", "number": "9812345678", "audio_id": 12 }'| Situation | HTTP | details message |
|---|---|---|
| No publishable key sent | 401 | Missing API key. Send your publishable key in the x-api-key header. |
| Unknown publishable key | 401 | Invalid API credentials. |
| Known key, wrong or missing secret | 403 | Invalid API credentials. |
| Account is not active | 403 | This account is not active. Please contact support. |
| API access not enabled for the account | 403 | The API is not enabled for this account. Please contact support. |
The wording is intentionally the same for an unknown key and a wrong secret, so that credentials cannot be probed.
Every response is JSON and uses one consistent envelope.
{
"status": "success",
"code": 200,
"unique_id": "run_4821",
"reference_id": "order-99213",
"details": "Call queued."
}| Field | Type | Description |
|---|---|---|
| status | string | "success" or "error". |
| code | number | A numeric result code. Mirrors the HTTP status (see Error codes). |
| unique_id | string | null | Our identifier for the resource created by this call. Use it with Get call status. For OTP requests this is the verification request id. |
| reference_id | string | null | Echoes the reference_id you sent, so you can correlate the response with your own records. null if you did not send one. |
| details | string | A short human-readable description of the result. |
Successful responses may include extra fields alongside the envelope. These are documented per endpoint (for example request_id and expires_in_sec on OTP send, verified on verify, call_status on status).
status: "success". A failed request returns the matching HTTP error status (400, 401, 403, 404, 429, or 5xx) with status: "error", and the same value in the code field.| HTTP | code | Meaning | When it happens |
|---|---|---|---|
| 200 | 200 | Success | The request was accepted. |
| 400 | 400 | Bad request | A required field is missing or invalid (a malformed number, an unknown type, a missing audio_id, or a missing code on verify). |
| 401 | 401 | Unauthorized | The publishable key is missing or unknown, or (on verify) the submitted code is incorrect. |
| 403 | 403 | Forbidden | The secret is wrong, the account is not active, or API access is not enabled. |
| 404 | 404 | Not found | The campaign id, call id, or verification request could not be found for your account. |
| 429 | 429 | Too many requests | You exceeded the rate limit, or sent too many verification calls to one number in a short window. |
| 5xx | 5xx | Temporary problem | The call could not be placed right now. Safe to retry after a short pause. |
Error responses never include internal infrastructure detail. A failed call placement returns a neutral message such as "Could not place the call right now. Please retry."
{
"status": "error",
"code": 400,
"unique_id": null,
"reference_id": "order-99213",
"details": "A valid Indian mobile number is required."
}Requests are limited per account to 120 requests per minute. The limit is keyed to your account, so traffic from one account never throttles another, and an office behind a single shared IP is not treated as one caller.
When you exceed the limit you receive HTTP 429 with:
{
"status": "error",
"code": 429,
"details": "Too many requests. Please slow down and retry shortly."
}Standard rate-limit headers (RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset) are returned on responses so you can pace your requests.
The write endpoints place a call, trigger a saved campaign, send a voice verification code, and verify a code. The read endpoints fetch a single call's status, list your calls, download a recording, list your campaigns, and report your account balance.
/callsPlace a single outbound call immediately. Three call types are supported.
| type | What it does | Required fields |
|---|---|---|
| audio_blast | Plays a pre-recorded audio clip from your library to the number, then ends. | audio_id |
| press1 | Plays a clip and listens for a keypad press to connect the call onward. | audio_id |
| otp | Places a verification call that reads out a code. | none beyond number |
| Field | Type | Required | Description |
|---|---|---|---|
| type | string | Required | One of audio_blast, press1, otp. |
| number | string | Required | The recipient's Indian mobile number. See Phone number format. |
| audio_id | number | Optional | For audio_blast and press1. The id of a clip in your audio library. Must belong to your account. |
| dtmf_map | object | Optional | press1 only. Maps a pressed digit to an action. Defaults to { "1": "connect_agent" }. |
| caller_id | string | Optional | A verified caller number on your account to display. Defaults to your account default. |
| code | string | Optional | otp only. Supply your own numeric code. If omitted, a code is generated. |
| length | number | Optional | otp only. Length of the generated code, 4 to 8 digits. Default 4. |
| ttl | number | Optional | otp only. Seconds the code stays valid. Default 600 (10 minutes). |
| message | string | Optional | otp only. A custom spoken message. Use {code} where the code should be read out. |
| reference_id | string | Optional | Your own correlation key. Echoed back and in webhooks. |
{
"status": "success",
"code": 200,
"unique_id": "run_4821",
"reference_id": "order-99213",
"details": "Call queued."
}For the otp type the response is the same as Send a verification code.
curl https://voice.agentive.co.in/api/public/v1/calls \
-H "x-api-key: pk_live_..." \
-H "x-api-secret: sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"type": "audio_blast",
"number": "9812345678",
"audio_id": 12,
"reference_id": "order-99213"
}'{
"type": "press1",
"number": "9812345678",
"audio_id": 18,
"dtmf_map": { "1": "connect_agent" },
"reference_id": "promo-march"
}/campaigns/:id/triggerRun an existing API campaign for a single number. The campaign's audio and settings are used as configured in your dashboard. Only Audio Blast and Press-1 campaigns can be triggered this way. Verification-code campaigns use the OTP endpoints instead.
| Parameter | Description |
|---|---|
| id | The numeric id of the campaign to trigger. |
| Field | Type | Required | Description |
|---|---|---|---|
| number | string | Required | The recipient's Indian mobile number. |
| reference_id | string | Optional | Your own correlation key. |
{
"status": "success",
"code": 200,
"unique_id": "run_4822",
"reference_id": "lead-5567",
"details": "Call queued."
}| Situation | HTTP | details |
|---|---|---|
| Campaign not found for your account | 404 | Campaign not found. |
| Campaign is a verification-code campaign | 400 | This is a verification-code campaign. Use the OTP endpoints to send a code. |
| Campaign type cannot be triggered for one number | 400 | This campaign type cannot be triggered for a single number. |
| Campaign has no audio configured | 400 | This campaign has no audio configured. |
curl https://voice.agentive.co.in/api/public/v1/campaigns/57/trigger \
-H "x-api-key: pk_live_..." \
-H "x-api-secret: sk_live_..." \
-H "Content-Type: application/json" \
-d '{ "number": "9812345678", "reference_id": "lead-5567" }'/otp/sendPlace a call that reads a numeric verification code out to the recipient. The code is read digit by digit and spoken twice, then the call ends. There is no agent and no human on the call.
| Field | Type | Required | Description |
|---|---|---|---|
| number | string | Required | The recipient's Indian mobile number. |
| code | string | Optional | Supply your own numeric code (4 to 8 digits). If omitted, one is generated. |
| length | number | Optional | Length of the generated code, 4 to 8. Default 4. |
| ttl | number | Optional | Seconds the code stays valid. Default 600 (10 minutes). |
| max_attempts | number | Optional | How many verify attempts are allowed. Default 3. |
| message | string | Optional | Custom spoken message. Use the token {code} where the digits should be read. If omitted, a default sentence is used. |
| reference_id | string | Optional | Your own correlation key. |
{
"status": "success",
"code": 200,
"unique_id": "5f3c8b2a-1d4e-4a9c-9e7b-2c6f0a1b3d8e",
"reference_id": "signup-7781",
"details": "Verification call queued.",
"request_id": "5f3c8b2a-1d4e-4a9c-9e7b-2c6f0a1b3d8e",
"expires_in_sec": 600
}| Extra field | Description |
|---|---|
| request_id | The verification request id. Use it (or the number) when calling verify. Same value as unique_id. |
| expires_in_sec | Seconds until the code expires. |
Defaults: code length 4, validity 10 minutes, 3 attempts.
Spoken message: by default the call says "Your verification code is 1 2 3 4. Again, 1 2 3 4." If you pass a message with a {code} token, your text is read with the spaced digits substituted in.
curl https://voice.agentive.co.in/api/public/v1/otp/send \
-H "x-api-key: pk_live_..." \
-H "x-api-secret: sk_live_..." \
-H "Content-Type: application/json" \
-d '{ "number": "9812345678", "length": 4, "ttl": 600, "reference_id": "signup-7781" }'/otp/verifyCheck a code the recipient gives you against a verification request. Identify the request by its request_id (returned from send) or by the recipient's number (the most recent pending request for that number is used).
Each verify attempt is counted whether right or wrong. Once the attempt cap is reached the request can no longer be verified, and you must send a fresh code.
| Field | Type | Required | Description |
|---|---|---|---|
| code | string | Required | The code the recipient entered. |
| request_id | string | Optional | One of request_id or number. The id returned by send. |
| number | string | Optional | One of request_id or number. The recipient's number, used to find the most recent pending request. |
| reference_id | string | Optional | Your own correlation key. |
{
"status": "success",
"code": 200,
"unique_id": "5f3c8b2a-1d4e-4a9c-9e7b-2c6f0a1b3d8e",
"reference_id": "signup-7781",
"details": "Code verified.",
"request_id": "5f3c8b2a-1d4e-4a9c-9e7b-2c6f0a1b3d8e",
"verified": true
}{
"status": "error",
"code": 401,
"details": "Incorrect code.",
"verified": false,
"attempts_left": 2
}| Situation | HTTP | details |
|---|---|---|
| Code is correct | 200 | Code verified. |
| Code is incorrect | 401 | Incorrect code. |
| Code has expired | 400 | This code has expired. |
| Too many incorrect attempts | 400 | Too many incorrect attempts. |
| Code already used | 400 | This code has already been used. |
| Request not found | 400 | Verification failed. |
| Missing code or identifier | 400 | A code and either request_id or number are required. |
The verified field is always present (true or false). On a wrong code, attempts_left tells you how many tries remain.
curl https://voice.agentive.co.in/api/public/v1/otp/verify \
-H "x-api-key: pk_live_..." \
-H "x-api-secret: sk_live_..." \
-H "Content-Type: application/json" \
-d '{ "request_id": "5f3c8b2a-1d4e-4a9c-9e7b-2c6f0a1b3d8e", "code": "1234" }'/calls/:unique_idCheck the current status of a call you placed, or a verification request.
| Parameter | Description |
|---|---|
| unique_id | The unique_id returned when you placed the call or sent the code. For calls this looks like run_4821; for verification it is the request id. |
{
"status": "success",
"code": 200,
"unique_id": "run_4821",
"reference_id": null,
"details": "answered",
"call_status": "answered",
"duration_sec": 17
}{
"status": "success",
"code": 200,
"unique_id": "5f3c8b2a-1d4e-4a9c-9e7b-2c6f0a1b3d8e",
"reference_id": "signup-7781",
"details": "verified",
"call_status": "verified",
"verified": true,
"attempts": 1,
"max_attempts": 3
}| Value | Meaning |
|---|---|
| queued | Accepted and waiting to be placed. |
| ringing | The recipient's phone is ringing. |
| answered | The recipient answered and the call is in progress. |
| completed | The call finished after being answered. |
| failed | The call ended without connecting. |
| Value | Meaning |
|---|---|
| pending | Code sent, not yet verified or expired. |
| verified | The correct code was confirmed. |
| expired | The validity window passed. |
| failed | The attempt cap was reached, or the call could not be placed. |
A unique_id that does not belong to your account returns HTTP 404 with "Call not found." or "Not found.".
curl https://voice.agentive.co.in/api/public/v1/calls/run_4821 \
-H "x-api-key: pk_live_..." \
-H "x-api-secret: sk_live_..."/callsPage through the calls on your account, most recent first. This returns the full call object for each call, with the enumerated status and end_reason values, so you can reconcile call results in bulk instead of polling each call by id.
| Parameter | Type | Default | Description |
|---|---|---|---|
| page | number | 1 | The page of results to return. |
| per_page | number | 50 | Results per page. Maximum 100. |
| direction | string | none | Filter by inbound or outbound. |
| status | string | none | Filter by a call status: queued, ringing, in_progress, completed, failed, or missed. |
| from | string | none | Include calls created on or after this ISO 8601 date or timestamp. |
| to | string | none | Include calls created before this ISO 8601 date or timestamp. |
| number | string | none | Match calls where this number appears as either the caller or the recipient. |
{
"status": "success",
"code": 200,
"data": [
{
"unique_id": "run_4821",
"call_id": "a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
"direction": "outbound",
"from_number": "07965318581",
"to_number": "+919812345678",
"status": "completed",
"end_reason": "completed",
"duration_sec": 42,
"campaign_id": 4821,
"reference_id": "order-99213",
"created_at": "2026-06-04T21:42:08+05:30"
}
],
"pagination": {
"page": 1,
"per_page": 50,
"total": 137,
"total_pages": 3
}
}| Field | Type | Description |
|---|---|---|
| data | array | A page of call objects. |
| pagination.page | number | The current page. |
| pagination.per_page | number | Results per page for this response. |
| pagination.total | number | Total calls matching your filters. |
| pagination.total_pages | number | Total number of pages. |
The response carries only the public call object fields. end_reason is always one of the enumerated end reasons.
curl "https://voice.agentive.co.in/api/public/v1/calls?per_page=50&direction=outbound&status=completed" \
-H "x-api-key: pk_live_..." \
-H "x-api-secret: sk_live_..."/calls/:unique_id/recordingDownload the audio recording of a call. The response streams the audio file and supports HTTP Range requests, so you can fetch a portion or resume a download.
| Parameter | Description |
|---|---|
| unique_id | The call's unique_id (for example run_4821) or its call_id. Must belong to your account. |
On success the body is the raw audio. The Content-Type is audio/ogg or audio/wav depending on how the recording was stored. With a Range request the response is HTTP 206 (Partial Content); otherwise it is HTTP 200.
If there is no recording for the call (it never connected, or the audio is not available), the response is HTTP 404 with the standard error envelope:
{
"status": "error",
"code": 404,
"details": "No recording is available for this call."
}curl "https://voice.agentive.co.in/api/public/v1/calls/run_4821/recording" \
-H "x-api-key: pk_live_..." \
-H "x-api-secret: sk_live_..." \
--output call-4821.ogg/campaignsList the campaigns on your account that can be triggered through the API. Use a campaign id from this list with Trigger a saved campaign.
{
"status": "success",
"code": 200,
"data": [
{ "id": 57, "name": "March promo", "type": "audio_blast", "status": "active" },
{ "id": 61, "name": "Renewal press-1", "type": "press1", "status": "active" },
{ "id": 72, "name": "Signup verification", "type": "otp", "status": "active" }
]
}| Field | Type | Description |
|---|---|---|
| id | number | The campaign id. Use it with Trigger a saved campaign. |
| name | string | The name you gave the campaign. |
| type | string | One of audio_blast, press1, or otp. Verification (otp) campaigns are configured here but delivered with the OTP endpoints. |
| status | string | The campaign's current state. |
curl https://voice.agentive.co.in/api/public/v1/campaigns \
-H "x-api-key: pk_live_..." \
-H "x-api-secret: sk_live_..."/accountReturn your account's current wallet balance in INR.
{
"status": "success",
"code": 200,
"data": {
"balance_inr": 1842.5,
"currency": "INR"
}
}| Field | Type | Description |
|---|---|---|
| balance_inr | number | Your current wallet balance, in Indian Rupees. |
| currency | string | Always "INR". |
curl https://voice.agentive.co.in/api/public/v1/account \
-H "x-api-key: pk_live_..." \
-H "x-api-secret: sk_live_..."List calls returns a data array of call objects. The same shape appears in the call.* webhook events.
| Field | Type | Description |
|---|---|---|
| unique_id | string | The call's public id. For calls placed through an API run this looks like run_4821; otherwise it is the call id. |
| call_id | string | null | Our internal identifier for the call. |
| direction | string | outbound or inbound. |
| from_number | string | null | The caller number shown. |
| to_number | string | null | The recipient number. |
| status | string | null | The call state. One of the enumerated status values. |
| end_reason | string | null | Why the call ended. One of the enumerated end reasons, or null while the call is still in progress. |
| duration_sec | number | null | Talk duration in seconds. |
| campaign_id | number | null | The run this call belongs to, matching the digits in unique_id. |
| reference_id | string | null | The reference_id you supplied. |
| created_at | string | null | When the call was created, in IST. |
status and end_reason are closed sets. New values are not added without notice, so you can write exhaustive handling.
| Value | Meaning |
|---|---|
| queued | Accepted and waiting to be placed. |
| ringing | The recipient's phone is ringing. |
| in_progress | The recipient answered and the call is connected. |
| completed | The call finished after being answered. |
| missed | The call rang but was never answered. |
| failed | The call ended without connecting. |
| Value | Meaning |
|---|---|
| completed | The call connected and finished normally. |
| no_answer | The call rang but the recipient never picked up. Safe to retry later. |
| busy | The recipient was on another call. The number is reachable, so a retry can succeed. |
| rejected | The recipient actively declined the call. |
| canceled | The call was cancelled before it connected. |
| failed | The call could not be placed, for example an invalid number or a carrier problem. |
queued, ringing, answered, completed, failed for calls). The enumerated status and end_reason above apply to the call object returned by List calls and sent in webhooks.Send Indian mobile numbers in any of these forms; they are all normalised:
9812345678919812345678+919812345678reference_id is an optional string you attach to any request, such as an order number, ticket id, or signup id. It is:
reference_id field, andUse it to match our events back to your own records without storing our ids. Reference IDs are capped at 120 characters; control characters are stripped.
The call-placing endpoints (POST /calls and POST /otp/send) do not yet accept an idempotency key. If a request times out or the connection drops, the call may already have been placed, so a blind retry can result in a second call to the same number.
To make a retry safe:
reference_id on each request and record it on your side.reference_id to see whether the call was already placed./otp/send issues a fresh code; reuse the existing request_id rather than sending again if a code is already in flight.id (evt_...) you can use to ignore repeats. See Ordering and idempotency in the webhook reference.curl https://voice.agentive.co.in/api/public/v1/calls \
-H "x-api-key: pk_live_..." \
-H "x-api-secret: sk_live_..." \
-H "Content-Type: application/json" \
-d '{ "type": "audio_blast", "number": "98XXXXXXXX", "audio_id": 12, "reference_id": "test-1" }'unique_id and poll status:curl https://voice.agentive.co.in/api/public/v1/calls/run_XXXX \
-H "x-api-key: pk_live_..." \
-H "x-api-secret: sk_live_..."