Each number has one inbound target: the place every incoming call goes. There are 11 kinds of target, from a webhook that returns VoiceML to a SIP URI, a raw-audio media stream, a Conversation Relay bot or an IVR Studio flow. Set it once in the portal under When a call comes in, or with the API, and change it whenever you like.
The 11 targets#
| # | Target | What happens | Set with |
|---|---|---|---|
| 1 | Webhook URL | Edesy fetches your URL, which returns VoiceML | PUT.../inbound webhook, or routing webhook |
| 2 | SIP URI or saved SIP destination | The call is sent to your SIP endpoint: LiveKit Cloud, Vapi, Bolna, Retell or any SIP server | routing sip |
| 3 | Media stream | Raw L16 audio to your WebSocket bot. See Media Streams | PUT.../inbound media_stream, or routing stream |
| 4 | Conversation Relay | Text in, text out bot. See Conversation Relay | PUT.../inbound conversation_relay, or routing relay |
| 5 | Edesy AI voice agent | An agent built at voice-agent.edesy.in answers | PUT.../inbound voice_agent, or routing voiceagent |
| 6 | Your SIP trunk | The call goes to one of your Edesy SIP trunks and on to its configured destination | routing trunk |
| 7 | Browser / app softphones | Rings your team's registered browser softphones | Portal |
| 8 | IVR Studio flow | Runs a published flow built at ivr.edesy.in | routing ivr |
| 9 | Application preset | Follows a saved application | routing application |
| 10 | Missed call | The call is rejected before it is answered (the caller pays nothing) and a call.missed webhook is sent |
routing missed_call |
| 11 | Call forwarding rule | Rings your team's phones with a forwarding rule from forwarding.edesy.in | Forwarding portal |
Callers on your blocklist are refused before any target runs.
Quick binding: PUT/v1/phone-numbers/{id}/inbound#
One call that sets up the number for a webhook, media stream, relay bot or AI voice agent, including making it ready for outbound use.
curl -X PUT https://voice-api.edesy.in/v1/phone-numbers/{id}/inbound \
-H "Authorization: Bearer $EDESY_KEY" \
-H "Content-Type: application/json" \
-d '{ "target": "webhook", "webhook_url": "https://example.com/edesy/inbound", "webhook_method": "POST" }'
| Field | Required | Description |
|---|---|---|
target |
yes | webhook, media_stream, conversation_relay or voice_agent |
webhook_url, webhook_method |
for webhook |
URL returning VoiceML; POST (default) or GET |
stream_url, sample_rate |
for media_stream |
ws:// or wss:// URL; 16000 (default) or 8000 |
relay_url, relay_settings |
for conversation_relay |
ws:// or wss:// URL; optional settings object |
agent_id, workspace_id |
for voice_agent |
Identify the agent on the Edesy AI voice agent platform |
force |
no | Take over a number currently bound to something set up outside these APIs |
DELETE/v1/phone-numbers/{id}/inbound detaches the inbound target. Outbound calls from the number keep working.
If the number is already bound to an unrelated setup, PUT returns 409 inbound_conflict unless you pass "force": true.
Full routing: PATCH/v1/phone-numbers/{id}/routing#
Covers every API-settable target. Send inbound_target_type plus the field that target needs.
curl -X PATCH https://voice-api.edesy.in/v1/phone-numbers/{id}/routing \
-H "Authorization: Bearer $EDESY_KEY" \
-H "Content-Type: application/json" \
-d '{
"inbound_target_type": "sip",
"inbound_sip_uri": "sip:[email protected]",
"inbound_sip_username": "edesy",
"inbound_sip_password": "your-password",
"inbound_sip_headers": { "X-Agent": "support" }
}'
inbound_target_type |
Required fields | Optional fields |
|---|---|---|
webhook |
inbound_webhook_url |
inbound_webhook_method |
sip |
inbound_sip_uri |
inbound_sip_username, inbound_sip_password (digest auth), inbound_sip_headers (replaces the whole set; {} clears it) |
stream |
inbound_stream_url |
inbound_stream_sample_rate (8000 or 16000) |
relay |
inbound_relay_url |
inbound_relay_config (replaced as a whole) |
trunk |
inbound_trunk_id |
|
voiceagent |
||
ivr |
ivr_flow_id |
|
application |
application_id |
|
missed_call |
The same request also accepts outbound_caller_id, friendly_name and recording_enabled. A missing required field returns 400 VALIDATION_ERROR.
Saved SIP destinations (an address book of SIP endpoints with a test-call button) live under /v1/sip-destinations. For trunks and agent platforms, see SIP for AI voice agents and SIP trunking.
What your webhook receives#
For the webhook target, Edesy sends a form-encoded request to your URL when a call arrives, with CallSid, AccountSid, From (the caller), To (your number), CallStatus and Direction set to inbound. Reply with VoiceML. To refuse a call without answering, return reject as the first instruction.
{
"instructions": [
{ "verb": "say", "text": "Thanks for calling Acme. Connecting you now." },
{ "verb": "dial", "number": "+9198XXXXXXXX", "timeout": 25 },
{ "verb": "say", "text": "Sorry, nobody is available. Please call again later." }
]
}
Check the result#
- GET
/v1/phone-numbers/{id}/telephonyreportsoutbound_capableandinbound_bound. - Place a test call to the number and read GET
/v1/calls?to=+9180XXXXXXXX. - See Number Health and Webhook Logs.