Place an outbound call from a number you own, then track it with status webhooks or by polling.
| Method | Path | What it does |
|---|---|---|
POST |
/calls |
Place an outbound call |
GET |
/calls/{callSid} |
Get a call |
DELETE |
/calls/{callSid} |
Hang up |
POST GET DELETE |
/Accounts/{accountSid}/Calls[/{callSid}] |
The same three endpoints, account-scoped |
The /Accounts/{accountSid}/Calls routes behave exactly like /calls and return the same response. accountSid is your account SID (AC_…) or workspace ID; any other value returns 403 FORBIDDEN.
Base URL https://voice-api.edesy.in/v1, Bearer API key. See Authentication.
Place a call#
POST /calls
The from number must be one you own and have registered for outbound.
| Field | Type | Required | Notes |
|---|---|---|---|
from |
string | Yes | Your number, E.164 |
to |
string or object | Yes | E.164, or { "type": "phone", "number": "+91…" } |
stream_url |
string | One of | Stream call audio to your WebSocket agent |
application_id |
string | One of | A saved application; application_sid is accepted as an alias |
url |
string | One of | A URL that returns call instructions (method: GET or POST) |
text |
string | One of | Text to speak (max 2000 characters), with optional voice and language |
stream_sample_rate |
integer | No | 8000 or 16000, for stream_url |
status_callback |
string | No | URL for status webhooks |
status_method |
string | No | POST (default) or GET |
timeout |
integer | No | Seconds to ring, 5 to 600 |
caller_name |
string | No | Max 50 characters |
machine_detection |
string | No | Enable or DetectMessageEnd |
custom_parameters |
object | No | Your own key-values, returned with the call; tag is an alias |
Send exactly one of stream_url, application_id, url or text. Unknown fields are ignored and listed in meta.ignored_fields, so check that list if a setting seems to have no effect.
curl -X POST https://voice-api.edesy.in/v1/calls \
-H "Authorization: Bearer vp_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "+917969002802",
"to": "+919812345678",
"stream_url": "wss://agent.example.com/ws",
"status_callback": "https://example.com/hooks/call-status",
"timeout": 60,
"custom_parameters": { "lead_id": "L-5521" }
}'
Response 201:
{
"data": {
"call_sid": "f4590c42-1a14-4a5f-b526-32f2a4c09018",
"sid": "f4590c42-1a14-4a5f-b526-32f2a4c09018",
"account_sid": "AC_1a2b3c4d",
"from": "+917969002802",
"to": "+919812345678",
"direction": "outbound",
"status": "queued",
"created_at": "2026-10-08T09:31:02Z",
"custom_parameters": { "lead_id": "L-5521" }
},
"meta": { "request_id": "req_8c1d", "timestamp": "2026-10-08T09:31:02Z" }
}
sid is the same value as call_sid. Once known, the call also carries answered_at, ended_at, duration, price (amount, currency), hangup_cause and answered_by.
Get a call#
GET /calls/{callSid} returns the same data object with the latest status.
Hang up#
DELETE /calls/{callSid} ends an active call and returns 204 with no body. A call that has already ended returns 409 CALL_ENDED.
Status webhooks#
Set status_callback on the call, or save one on the application, and the platform reports each status change:
CallStatus |
Meaning |
|---|---|
initiated |
The call is being set up |
ringing |
The callee's phone is ringing |
in-progress |
Answered |
completed |
Ended normally |
busy |
The line was busy |
no-answer |
Not answered before timeout |
failed |
The call couldn't be connected |
stream-failed |
The audio stream to your stream_url failed; ErrorMessage says why |
POST sends JSON and GET sends query parameters:
{
"CallSid": "f4590c42-1a14-4a5f-b526-32f2a4c09018",
"From": "+917969002802",
"To": "+919812345678",
"CallStatus": "in-progress",
"Direction": "outbound",
"Timestamp": "2026-10-08T09:31:09Z",
"Custom": { "lead_id": "L-5521" }
}
Duration is added when the call ends. Match events to calls by CallSid, or by your custom_parameters in Custom.
- Delivery times out after 30 seconds and is retried up to 5 times, so make your handler idempotent.
- Requests carry
User-Agent: VoicePlatform-Webhook/1.0. - If a signing secret is set on your account, each request also carries
X-Webhook-TimestampandX-Webhook-Signature: v1=<hex>, an HMAC-SHA256 of"<timestamp>.<body>". Recompute it and reject mismatches.
Errors#
| HTTP | code |
When |
|---|---|---|
| 400 | VALIDATION_ERROR |
Invalid body or no call instructions; details.errors lists each field |
| 402 | INSUFFICIENT_BALANCE |
Wallet balance is too low |
| 403 | NUMBER_NOT_OWNED |
from isn't a number on your account |
| 403 | FORBIDDEN |
accountSid in the path isn't yours |
| 404 | NOT_FOUND |
No call with that SID |
| 409 | CALL_ENDED |
The call has already ended |
| 503 | SERVICE_UNAVAILABLE |
No carrier capacity right now; retry with backoff |
See Error Codes for the error format.