Logo
Search
Docs

Update phone number

PUT 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.

Validation: the number's digits (E.164 without the leading +), full E.164 (with +), or the numeric configuration id once one exists
Stored in assistant_phone_number_configurations.phone_number

Request body

name string Optional Nullable

Reference label for the number.

Validation: nullable|string|max:255
Stored in assistant_phone_number_configurations.name
vapi_assistant_id string Optional Nullable

Inbound routing target: the assistant that answers this number. Mutually exclusive with vapi_squad_id and vapi_workflow_id.

Validation: nullable|string|max:255
Stored in assistant_phone_number_configurations.vapi_assistant_id
vapi_squad_id string Optional Nullable

Inbound routing target: the squad that answers this number. Mutually exclusive with vapi_assistant_id and vapi_workflow_id.

Validation: nullable|string|max:255
Stored in assistant_phone_number_configurations.vapi_squad_id
vapi_workflow_id string Optional Nullable

Inbound routing target: the workflow that answers this number. Mutually exclusive with vapi_assistant_id and vapi_squad_id.

Validation: nullable|string|max:255
Stored in assistant_phone_number_configurations.vapi_workflow_id
sms_enabled boolean Optional Nullable

Toggles the messaging webhook for this number.

Validation: nullable|boolean
Stored in assistant_phone_number_configurations.sms_enabled
static_ip_enabled boolean Optional Nullable

Routes webhook requests through the provider's static IP range for firewall whitelisting. Always mirrored onto server.staticIpAddressesEnabled.

Validation: nullable|boolean
Stored in assistant_phone_number_configurations.static_ip_enabled
fallback_destination object Optional Nullable

Where the call goes when the assistant is unavailable. null or {} clears the whole block.

Validation: nullable|array
Stored in assistant_phone_number_configurations.fallback_destination
fallback_destination.type string Optional Nullable
Validation: nullable|string|in:number,sip
Stored in assistant_phone_number_configurations.fallback_destination
fallback_destination.number string Optional Nullable

E.164 format.

Validation: nullable|required_if:fallback_destination.type,number|string|regex:/^\+[1-9]\d{6,14}$/
Stored in assistant_phone_number_configurations.fallback_destination
fallback_destination.sipUri string Optional Nullable
Validation: nullable|required_if:fallback_destination.type,sip|string|max:255
Stored in assistant_phone_number_configurations.fallback_destination
fallback_destination.message string Optional Nullable

What is said before the fallback transfer.

Validation: nullable|string|max:1000
Stored in assistant_phone_number_configurations.fallback_destination
fallback_destination.description string Optional Nullable

Internal note on when the fallback applies.

Validation: nullable|string|max:1000
Stored in assistant_phone_number_configurations.fallback_destination
fallback_destination.extension string Optional Nullable
Validation: nullable|string|max:255
Stored in assistant_phone_number_configurations.fallback_destination
fallback_destination.callerId string Optional Nullable

E.164 format.

Validation: nullable|string|regex:/^\+[1-9]\d{6,14}$/
Stored in assistant_phone_number_configurations.fallback_destination
server object Optional Nullable

Webhook target for call events. null or {} clears the whole block.

Validation: nullable|array
Stored in assistant_phone_number_configurations.server
server.url string Optional Nullable
Validation: nullable|string|url|max:2048
Stored in assistant_phone_number_configurations.server
server.secret string Optional Nullable

Shared secret sent with webhook requests.

Validation: nullable|string|max:2048
Stored in assistant_phone_number_configurations.server
server.timeoutSeconds numeric Optional Nullable
Validation: nullable|numeric|min:1|max:300
Stored in assistant_phone_number_configurations.server
server.credentialId string Optional Nullable

A personal credential's id used to authenticate the webhook request (see the Tools module's Credentials group).

Validation: nullable|string|max:255
Stored in assistant_phone_number_configurations.server
server.headers object Optional Nullable

Header name/value map sent with webhook requests.

Validation: nullable|array
Stored in assistant_phone_number_configurations.server
server.headers.* string Optional Nullable
Validation: nullable|string|max:4096
Stored in assistant_phone_number_configurations.server
hooks array Optional Nullable

Event-triggered actions (e.g. on ringing, on call end).

Validation: nullable|array
Stored in assistant_phone_number_configurations.hooks

Errors

StatusMeaningBody
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))
}
Response 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]"
        }
    }
}