Inbound Routing

Decide where calls to an Edesy number go - 11 targets including a VoiceML webhook, SIP URI, media stream, Conversation Relay bot, AI voice agent, SIP trunk, IVR flow and missed call. PUT /v1/phone-numbers/{id}/inbound and PATCH routing.

4 min read

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#

PUThttps://voice-api.edesy.in/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}/telephony reports outbound_capable and inbound_bound.
  • Place a test call to the number and read GET/v1/calls?to=+9180XXXXXXXX.
  • See Number Health and Webhook Logs.
Was this page helpful?