Update phone number
https://app.sulus.ai/api/phone-numbers/{id}
Update a number's configuration (writes to the live voice platform first, then mirrors locally)
Authentication
Send a bearer token created on your dashboard's Developer page:
Authorization: Bearer <YOUR_API_KEY>
Path parameters
id
string
Required
The phone number to configure.
the number's digits (E.164 without the leading +), full E.164 (with +), or the numeric configuration id once one existsassistant_phone_number_configurations.phone_numberRequest body
name
string
Optional
Nullable
Reference label for the number.
nullable|string|max:255assistant_phone_number_configurations.namevapi_assistant_id
string
Optional
Nullable
Inbound routing target: the assistant that answers this number. Mutually exclusive with vapi_squad_id and vapi_workflow_id.
nullable|string|max:255assistant_phone_number_configurations.vapi_assistant_idvapi_squad_id
string
Optional
Nullable
Inbound routing target: the squad that answers this number. Mutually exclusive with vapi_assistant_id and vapi_workflow_id.
nullable|string|max:255assistant_phone_number_configurations.vapi_squad_idvapi_workflow_id
string
Optional
Nullable
Inbound routing target: the workflow that answers this number. Mutually exclusive with vapi_assistant_id and vapi_squad_id.
nullable|string|max:255assistant_phone_number_configurations.vapi_workflow_idsms_enabled
boolean
Optional
Nullable
Toggles the messaging webhook for this number.
nullable|booleanassistant_phone_number_configurations.sms_enabledstatic_ip_enabled
boolean
Optional
Nullable
Routes webhook requests through the provider's static IP range for firewall whitelisting. Always mirrored onto server.staticIpAddressesEnabled.
nullable|booleanassistant_phone_number_configurations.static_ip_enabledfallback_destination
object
Optional
Nullable
Where the call goes when the assistant is unavailable. null or {} clears the whole block.
nullable|arrayassistant_phone_number_configurations.fallback_destinationfallback_destination.type
string
Optional
Nullable
nullable|string|in:number,sipassistant_phone_number_configurations.fallback_destinationfallback_destination.number
string
Optional
Nullable
E.164 format.
nullable|required_if:fallback_destination.type,number|string|regex:/^\+[1-9]\d{6,14}$/assistant_phone_number_configurations.fallback_destinationfallback_destination.sipUri
string
Optional
Nullable
nullable|required_if:fallback_destination.type,sip|string|max:255assistant_phone_number_configurations.fallback_destinationfallback_destination.message
string
Optional
Nullable
What is said before the fallback transfer.
nullable|string|max:1000assistant_phone_number_configurations.fallback_destinationfallback_destination.description
string
Optional
Nullable
Internal note on when the fallback applies.
nullable|string|max:1000assistant_phone_number_configurations.fallback_destinationfallback_destination.extension
string
Optional
Nullable
nullable|string|max:255assistant_phone_number_configurations.fallback_destinationfallback_destination.callerId
string
Optional
Nullable
E.164 format.
nullable|string|regex:/^\+[1-9]\d{6,14}$/assistant_phone_number_configurations.fallback_destinationserver
object
Optional
Nullable
Webhook target for call events. null or {} clears the whole block.
nullable|arrayassistant_phone_number_configurations.serverserver.url
string
Optional
Nullable
nullable|string|url|max:2048assistant_phone_number_configurations.serverserver.secret
string
Optional
Nullable
Shared secret sent with webhook requests.
nullable|string|max:2048assistant_phone_number_configurations.serverserver.timeoutSeconds
numeric
Optional
Nullable
nullable|numeric|min:1|max:300assistant_phone_number_configurations.serverserver.credentialId
string
Optional
Nullable
A personal credential's id used to authenticate the webhook request (see the Tools module's Credentials group).
nullable|string|max:255assistant_phone_number_configurations.serverserver.headers
object
Optional
Nullable
Header name/value map sent with webhook requests.
nullable|arrayassistant_phone_number_configurations.serverserver.headers.*
string
Optional
Nullable
nullable|string|max:4096assistant_phone_number_configurations.serverhooks
array
Optional
Nullable
Event-triggered actions (e.g. on ringing, on call end).
nullable|arrayassistant_phone_number_configurations.hooksErrors
| Status | Meaning | Body |
|---|---|---|
404 |
Number not found, or outside your account scope | {"success":false,"message":"Phone number configuration not found."} |
422 |
More than one inbound routing target set | {"success":false,"message":"Choose only one inbound target — an assistant, a squad, or a workflow.","errors":{"vapi_assistant_id":["Only one inbound target may be set."]}} |
422 |
Number has no upstream id yet (not registered on the live voice platform) | {"success":false,"message":"This phone number is not registered on the voice platform yet, so its configuration cannot be edited."} |
422 |
Composition rejected by the live platform (4xx from the upstream write) | {"success":false,"message":"<cleaned upstream error>","errors":{"fallback_destination.number":["…"]}} |
502 |
Live platform write failed | {"success":false,"message":"Failed to update the phone number. Please try again."} |
422 |
Validation failed | {"message":"…","errors":{"field":["…"]}} |
401 |
Missing or invalid bearer token | |
403 |
Feature phone_numbers not enabled for the account |
Notes
- Custom validation messages: fallback_destination.number.regex → "The fallback number must be a valid phone number in E.164 format (e.g. +14155551234)."; fallback_destination.callerId.regex → "The caller ID must be a valid phone number in E.164 format (e.g. +14155551234)."; fallback_destination.number.required_if → "A fallback phone number is required when the destination type is a number."; fallback_destination.sipUri.required_if → "A SIP URI is required when the destination type is SIP."
- Sending server or fallback_destination as null or {} clears the whole block; a non-empty object merges onto the stored value field-by-field, so partial updates do not drop unrelated sub-fields.
- static_ip_enabled always maps onto server.staticIpAddressesEnabled — enabling it with no other server fields still produces a server patch.
- When the inbound routing target changes, the number's assistant assignment is re-synced immediately: the previous assistant's stored phone number is cleared, and the new target's local assistant record (if it is an assistant) is updated to carry this number.
- The upstream error message is cleaned into a friendlier form before being returned (field labels reworded, any remaining vendor terminology replaced) and mapped to fallback_destination.number or server.url when the message names that area.
- update never returns sms_available — it is retrieve-only (see Overview).
curl --request PUT \
--url https://app.sulus.ai/api/phone-numbers/{id} \
--header 'Authorization: Bearer <YOUR_API_KEY>' \
--header 'Content-Type: application/json' \
--data '{
"name": "Front Desk Line",
"vapi_assistant_id": "a1b2c3d4-1e2f-4a3b-8c9d-0e1f2a3b4c5d",
"sms_enabled": true,
"static_ip_enabled": false,
"fallback_destination": {
"type": "number",
"number": "+14155559876",
"message": "Please hold while we connect you.",
"description": "Used when the assistant is unavailable",
"callerId": "+14155551234"
},
"server": {
"url": "https://api.example-business.com/webhooks/calls",
"secret": "whsec_5f4dcc3b5aa765d61d8327deb882cf99",
"timeoutSeconds": 20,
"headers": {"X-Source": "sulus"}
},
"hooks": []
}'
import requests
url = "https://app.sulus.ai/api/phone-numbers/{id}"
headers = {"Authorization": "Bearer <YOUR_API_KEY>"}
payload = {
"name": "Front Desk Line",
"vapi_assistant_id": "a1b2c3d4-1e2f-4a3b-8c9d-0e1f2a3b4c5d",
"sms_enabled": true,
"static_ip_enabled": false,
"fallback_destination": {
"type": "number",
"number": "+14155559876",
"message": "Please hold while we connect you.",
"description": "Used when the assistant is unavailable",
"callerId": "+14155551234"
},
"server": {
"url": "https://api.example-business.com/webhooks/calls",
"secret": "whsec_5f4dcc3b5aa765d61d8327deb882cf99",
"timeoutSeconds": 20,
"headers": {"X-Source": "sulus"}
},
"hooks": []
}
response = requests.put(url, json=payload, headers=headers)
print(response.json())
package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
url := "https://app.sulus.ai/api/phone-numbers/{id}"
payload := strings.NewReader(`{
"name": "Front Desk Line",
"vapi_assistant_id": "a1b2c3d4-1e2f-4a3b-8c9d-0e1f2a3b4c5d",
"sms_enabled": true,
"static_ip_enabled": false,
"fallback_destination": {
"type": "number",
"number": "+14155559876",
"message": "Please hold while we connect you.",
"description": "Used when the assistant is unavailable",
"callerId": "+14155551234"
},
"server": {
"url": "https://api.example-business.com/webhooks/calls",
"secret": "whsec_5f4dcc3b5aa765d61d8327deb882cf99",
"timeoutSeconds": 20,
"headers": {"X-Source": "sulus"}
},
"hooks": []
}`)
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("Authorization", "Bearer <YOUR_API_KEY>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}
{
"success": true,
"message": "Phone number configuration updated.",
"data": {
"id": 7,
"phone_number": "+14155551234",
"vapi_phone_number_id": "c3d4e5f6-1a2b-4c3d-9e0f-1a2b3c4d5e6f",
"assistant_id": 12,
"vapi_assistant_id": "a1b2c3d4-1e2f-4a3b-8c9d-0e1f2a3b4c5d",
"vapi_squad_id": null,
"vapi_workflow_id": null,
"name": "Front Desk Line",
"provider": "twilio",
"fallback_destination": {
"type": "number",
"number": "+14155559876",
"message": "Please hold while we connect you.",
"description": "Used when the assistant is unavailable",
"callerId": "+14155551234"
},
"server": {
"url": "https://api.example-business.com/webhooks/calls",
"secret": "whsec_5f4dcc3b5aa765d61d8327deb882cf99",
"timeoutSeconds": 20,
"headers": {
"X-Source": "sulus"
},
"staticIpAddressesEnabled": false
},
"hooks": [],
"sms_enabled": true,
"static_ip_enabled": false,
"metadata": null,
"last_synced_at": "2026-07-30T14:35:19.000000Z",
"user_id": 42,
"created_by": 42,
"reseller_id": "f1e2d3c4-b5a6-4978-8901-234567890abc",
"workspace_id": "9a8b7c6d-5e4f-4a3b-9c8d-7e6f5a4b3c2d",
"created_at": "2026-06-01T14:22:03.000000Z",
"updated_at": "2026-07-30T14:35:19.000000Z",
"assistant": {
"id": 12,
"name": "Front Desk",
"vapi_assistant_id": "a1b2c3d4-1e2f-4a3b-8c9d-0e1f2a3b4c5d"
},
"user": {
"id": 42,
"name": "Jane Cooper",
"email": "[email protected]"
}
}
}
/phone-numbers/{id}
200
{
"success": true,
"message": "Phone number configuration updated.",
"data": {
"id": 7,
"phone_number": "+14155551234",
"vapi_phone_number_id": "c3d4e5f6-1a2b-4c3d-9e0f-1a2b3c4d5e6f",
"assistant_id": 12,
"vapi_assistant_id": "a1b2c3d4-1e2f-4a3b-8c9d-0e1f2a3b4c5d",
"vapi_squad_id": null,
"vapi_workflow_id": null,
"name": "Front Desk Line",
"provider": "twilio",
"fallback_destination": {
"type": "number",
"number": "+14155559876",
"message": "Please hold while we connect you.",
"description": "Used when the assistant is unavailable",
"callerId": "+14155551234"
},
"server": {
"url": "https://api.example-business.com/webhooks/calls",
"secret": "whsec_5f4dcc3b5aa765d61d8327deb882cf99",
"timeoutSeconds": 20,
"headers": {
"X-Source": "sulus"
},
"staticIpAddressesEnabled": false
},
"hooks": [],
"sms_enabled": true,
"static_ip_enabled": false,
"metadata": null,
"last_synced_at": "2026-07-30T14:35:19.000000Z",
"user_id": 42,
"created_by": 42,
"reseller_id": "f1e2d3c4-b5a6-4978-8901-234567890abc",
"workspace_id": "9a8b7c6d-5e4f-4a3b-9c8d-7e6f5a4b3c2d",
"created_at": "2026-06-01T14:22:03.000000Z",
"updated_at": "2026-07-30T14:35:19.000000Z",
"assistant": {
"id": 12,
"name": "Front Desk",
"vapi_assistant_id": "a1b2c3d4-1e2f-4a3b-8c9d-0e1f2a3b4c5d"
},
"user": {
"id": 42,
"name": "Jane Cooper",
"email": "[email protected]"
}
}
}