A forwarding rule is the forwarding setup for one of your numbers. Create it with POST/v1/forwarding/rules and forwarding switches on within a few seconds; change it with PATCH, turn it off with POST/disable and remove it with DELETE. Each number has one rule, and creating it again for the same number returns the existing rule.
The rule object#
{
"id": "3f2b8c1e-7d4a-4e59-9b21-6a0c5d8e1f47",
"tenant_id": "5e7a2d19-0b4c-4f83-a6e1-8d2c9f3b7a04",
"did_number": "8071387146",
"name": "Main line",
"strategy": "simultaneous",
"ring_timeout_sec": 25,
"confirm_required": true,
"caller_id_mode": "did",
"targets": [
{ "number": "9876543210", "priority": 1, "enabled": true, "label": "Sales" },
{ "number": "9123456789", "priority": 2, "enabled": true, "label": "Support" }
],
"status": "active",
"answer_on_bridge": true,
"hold_audio_enabled": false,
"hold_audio_filename": "",
"sticky_enabled": false,
"sticky_window_hours": 0,
"created_at": "2026-10-16T09:30:00Z",
"updated_at": "2026-10-16T09:30:00Z"
}
Rule settings#
Used by create (all optional except did_number and targets) and update (all optional).
| Field | Type | Description |
|---|---|---|
name |
string | Your label, up to 255 characters |
strategy |
simultaneous or sequential |
Ring all at once (default) or one by one in list order. See Ring Strategies |
ring_timeout_sec |
integer, 5 to 120 | How long to ring, in seconds. Default 25. With sequential, per number unless the target sets its own ring_timeout |
confirm_required |
boolean | Default true. "Press any key to accept" for the person who answers. See Call Screening |
answer_on_bridge |
boolean | Default true. The caller hears real ringing and billing starts only when someone answers. Ignored while hold audio is on |
caller_id_mode |
did or original |
Your virtual number (default) or the real caller's number. See Caller ID Display |
sticky_enabled |
boolean | Default false. Ring the person who answered this caller last time first (ring one by one). See Sticky Agent |
sticky_window_hours |
integer, 1 to 8,760 | How long the caller is remembered. 168 (7 days) when sticky is on and no window is set |
targets |
array, up to 5 | The phones to ring, in ring order (see below) |
Each target:
| Field | Type | Description |
|---|---|---|
number |
string, required | Indian mobile or landline, any format (+91..., 91..., 0... or 10 digits) |
label |
string | Up to 64 characters, e.g. "Sales desk" |
enabled |
boolean | Default true. A disabled target stays on the rule but does not ring |
ring_timeout |
integer, 5 to 120 | Seconds this target rings, sequential only |
priority is set for you from the list order.
Create a rule#
Creates a rule for one of your numbers and switches forwarding on.
| Field | Type | Description |
|---|---|---|
did_number |
string, required | Your number that people call. 8071387146, +918071387146, 918071387146 or 08071387146; stored as 10 digits |
targets |
array, required | At least one number to ring |
| other settings | Any field from Rule settings |
curl -X POST https://voice-api.edesy.in/v1/forwarding/rules \
-H "Authorization: Bearer sk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"did_number": "+918071387146",
"name": "Main line",
"targets": [
{ "number": "9876543210", "label": "Sales" },
{ "number": "9123456789", "label": "Support" }
]
}'
Returns 201 with { "data": <rule>, "meta": {...} }.
- The number must be in the same workspace as your API key. Buy it first if it is not.
- Sending the request again for a number that already has your rule is safe: you get the same rule back and nothing is duplicated.
| Status | Code | When |
|---|---|---|
| 201 | Forwarding is on | |
| 400 | validation_error |
A field is wrong; the message names it |
| 400 | targets_required |
No number to forward to |
| 404 | number_not_found |
The number is not in your workspace |
| 409 | rule_exists |
Another account still holds forwarding on this number |
| 502 | inbound_activation_failed |
Saved but not switched on yet. Send the same request again |
List rules#
Every rule in your workspace, active and paused, in data. Not paginated.
Get a rule#
One rule by its id. 404 not_found if it is not in your workspace.
Update a rule#
Send only the fields you want to change. Accepts every field in Rule settings, plus:
| Field | Type | Description |
|---|---|---|
status |
active or paused |
Switch the rule on, or pause it. A paused number tells callers "This number is not in service"; to hand the number back to its normal routing, use Turn off forwarding instead |
hold_audio_enabled |
boolean | Play audio while the phones ring: your clip, or the built-in "please hold" message |
targets replaces the whole list. To add one person, send the existing targets plus the new one.
curl -X PATCH https://voice-api.edesy.in/v1/forwarding/rules/RULE_ID \
-H "Authorization: Bearer sk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"strategy": "sequential",
"targets": [
{ "number": "9876543210", "label": "Sales" },
{ "number": "9123456789", "label": "Support" },
{ "number": "9000012345", "label": "Manager" }
]
}'
Returns 200 with the updated rule.
Turn off forwarding#
Stops forwarding and hands the number back to whatever it did before (for example your voice agent or app). The rule is kept with status: "paused"; switch it back on with PATCH {"status": "active"}. Safe to repeat. A 502 inbound_repoint_failed means forwarding is already off; send the request again to finish. See Turn Off a Rule.
Delete a rule#
Removes the rule and hands the number back to its normal routing. Call logs are kept. Returns 204 with no body, also when the rule is already gone.
Hold audio#
POST /v1/forwarding/rules/:id/hold-audio
DELETE /v1/forwarding/rules/:id/hold-audio
Upload a message or music the caller hears while your team's phones ring: MP3, WAV, M4A or OGG, up to 8 MB. Short clips loop. Send multipart/form-data with the file in a field named file, not JSON.
curl -X POST https://voice-api.edesy.in/v1/forwarding/rules/RULE_ID/hold-audio \
-H "Authorization: Bearer sk_your_api_key" \
-F "[email protected]"
- Uploading turns hold audio on for the rule. While it is on, the caller is answered straight away to hear the clip, so billing starts then.
- DELETE removes your clip. If hold audio is still on, callers hear the built-in "please hold" message. To stop hold audio, PATCH
{"hold_audio_enabled": false}.
| Status | Code | When |
|---|---|---|
| 200 | Uploaded (or removed); returns the rule | |
| 400 | invalid_request |
No file field, or not readable audio |
| 413 | file_too_large |
Over 8 MB |
| 404 | not_found |
No such rule |
See Hold Music.