Hosted SIM API

Phone numbers

Your lines (the IncomingPhoneNumbers resource): their webhook URLs, the dongle behind each one, and the line's SIP login. Lines are assigned in the console; v1 has no buying or releasing of numbers.

GET /Accounts/{AccountSid}/IncomingPhoneNumbers.json

List your lines.

Lists your lines, one page at a time. A filter value that isn't valid, or a query parameter not listed here, answers 400 with code 790005.

Parameters

NameInRequiredDescription
PhoneNumber query

Only the line with this number (E.164).

PageSize query

Items per page, ≤ 1000, default 50. List pages with PageSize over 50 are rate-limited at 2/s per account.

Page query

The page number, from 0. Use the *_page_uri values rather than building it yourself.

PageToken query

An opaque paging token. It comes inside next_page_uri / previous_page_uri.

Responses

StatusMeaning
200

One page of lines.

400

A list filter value that isn't valid, or a query parameter the list doesn't take (790005, naming it in parameter).

401

Authentication failed (20003), or the account isn't active (20005). This comes before any lookup.

429

Over a rate (20429, with Retry-After in seconds): per account, GET 10/s (burst 30), list pages with PageSize over 50 at 2/s, POST/DELETE 5/s (burst 10); per source IP before auth, 20/s; a gateway-wide ceiling with a fair share per account. Failed auth from one source IP (10/min) also answers 429 with code 20429, for 15 min.

500

An internal error (799999).

Response fields

FieldTypeAlways thereDescription
page integer

The page number, from 0.

page_size integer
uri string
first_page_uri string
next_page_uri string or null

The next page, or null.

previous_page_uri string or null

The previous page, or null.

incoming_phone_numbers array of object

Your lines on this page.

incoming_phone_numbers[].sid stringrequired

PN + 32 hex.

incoming_phone_numbers[].account_sid stringrequired
incoming_phone_numbers[].friendly_name stringrequired
incoming_phone_numbers[].phone_number stringrequired

The line's number, E.164.

incoming_phone_numbers[].voice_url string or nullrequired

Where incoming calls are sent (the incomingCall webhook).

incoming_phone_numbers[].voice_method string: GET, POSTrequired
incoming_phone_numbers[].voice_fallback_url string or nullrequired
incoming_phone_numbers[].voice_fallback_method string: GET, POSTrequired
incoming_phone_numbers[].status_callback string or nullrequired

The line's StatusCallback. An incoming call's status events go here, and so do runtime errors when the Call or Message has none of its own.

incoming_phone_numbers[].status_callback_method string: GET, POSTrequired
incoming_phone_numbers[].sms_url string or nullrequired

Where incoming texts are sent (the incomingMessage webhook).

incoming_phone_numbers[].sms_method string: GET, POSTrequired
incoming_phone_numbers[].sms_fallback_url string or nullrequired
incoming_phone_numbers[].sms_fallback_method string: GET, POSTrequired
incoming_phone_numbers[].capabilities objectrequired

What the line can do.

incoming_phone_numbers[].capabilities.voice booleanrequired

True only on a calling dongle.

incoming_phone_numbers[].capabilities.sms booleanrequired

Always true.

incoming_phone_numbers[].capabilities.mms booleanrequired

Always false (no MMS in v1).

incoming_phone_numbers[].capabilities.fax booleanrequired

Always false.

incoming_phone_numbers[].date_created stringrequired

RFC 2822.

incoming_phone_numbers[].date_updated stringrequired

RFC 2822.

incoming_phone_numbers[].uri stringrequired
incoming_phone_numbers[].dongle oursobjectrequired

Ours, showing the state of the dongle behind the line.

incoming_phone_numbers[].dongle.state oursstring: serving, not_servingrequired

Whether the line is on the network now.

incoming_phone_numbers[].dongle.callable oursbooleanrequired

Whether it can make or take a call now.

incoming_phone_numbers[].dongle.why_not oursstring: no_calling_dongle, dongle_offline, line_suspended, temporarily_unavailable or nullrequired

Why the line can't call now, or null: no_calling_dongle (texts only; a permanent state), dongle_offline (not connected now), line_suspended (not rented, moving, or ended), temporarily_unavailable (anything brief on our side).

incoming_phone_numbers[].dongle.why_not_text oursstring or nullrequired

The why_not reason in our fixed words (one per code), or null when the line can call.

incoming_phone_numbers[].dongle.sip oursobject or nullrequired

The line's SIP login, or null on a texts-only line (no calling dongle). It's made automatically, and it's for softphones and for PBXs as a "SIP trunk with registration": TLS 1.2+, SRTP required, digest auth. Its fields: username, domain (voice.dongleswithwings.com), port (5061), transport (tls), srtp (required), state (not_set or active) and password_set_at.

One call per dongle, across API and SIP. The password is never shown back. SIP stays OFF on an API-mode line until a password is set (state not_set), using DwwSipPassword. The exception: a line that already had a working login when it entered API mode keeps that login working until the customer sets their own. That login stays active, with no outage.

incoming_phone_numbers[].dongle.sip.username oursstringrequired

The SIP username (made automatically).

incoming_phone_numbers[].dongle.sip.domain oursstringrequired
incoming_phone_numbers[].dongle.sip.port oursintegerrequired
incoming_phone_numbers[].dongle.sip.transport oursstringrequired
incoming_phone_numbers[].dongle.sip.srtp oursstringrequired
incoming_phone_numbers[].dongle.sip.state oursstring: not_set, activerequired
incoming_phone_numbers[].dongle.sip.password_set_at oursstring or nullrequired

When the SIP password was last set (RFC 2822), or null if it has never been set.

incoming_phone_numbers[].dww_sip_password oursstring

Only in the response to DwwSipPassword=generate, and only that once. It's never shown again.

Example request

curl -X GET "https://api.dongleswithwings.com/2010-04-01/Accounts/{AccountSid}/IncomingPhoneNumbers.json" \
  -u "$ACCOUNT_SID:$AUTH_TOKEN"

Example response

{
  "page": 0,
  "page_size": 50,
  "uri": "/2010-04-01/Accounts/ACa61cd972830fc5bc41386edc0a9f8463/IncomingPhoneNumbers.json?PageSize=50&Page=0",
  "first_page_uri": "/2010-04-01/Accounts/ACa61cd972830fc5bc41386edc0a9f8463/IncomingPhoneNumbers.json?PageSize=50&Page=0",
  "next_page_uri": null,
  "previous_page_uri": null,
  "incoming_phone_numbers": [
    {
      "sid": "PN3e18acd0169a00c48635e530c42a01ca",
      "account_sid": "ACa61cd972830fc5bc41386edc0a9f8463",
      "friendly_name": "Reception",
      "phone_number": "+61491570156",
      "voice_url": "https://hooks.example.com/voice/incoming",
      "voice_method": "POST",
      "voice_fallback_url": "https://hooks-backup.example.com/voice/incoming",
      "voice_fallback_method": "POST",
      "status_callback": "https://hooks.example.com/status",
      "status_callback_method": "POST",
      "sms_url": "https://hooks.example.com/sms/incoming",
      "sms_method": "POST",
      "sms_fallback_url": null,
      "sms_fallback_method": "POST",
      "capabilities": {
        "voice": true,
        "sms": true,
        "mms": false,
        "fax": false
      },
      "date_created": "Fri, 16 Oct 2026 02:15:00 +0000",
      "date_updated": "Mon, 02 Nov 2026 01:30:00 +0000",
      "uri": "/2010-04-01/Accounts/ACa61cd972830fc5bc41386edc0a9f8463/IncomingPhoneNumbers/PN3e18acd0169a00c48635e530c42a01ca.json",
      "dongle": {
        "state": "serving",
        "callable": true,
        "why_not": null,
        "why_not_text": null,
        "sip": {
          "username": "dww-4b7e19c2",
          "domain": "voice.dongleswithwings.com",
          "port": 5061,
          "transport": "tls",
          "srtp": "required",
          "state": "active",
          "password_set_at": "Mon, 02 Nov 2026 01:30:00 +0000"
        }
      }
    },
    {
      "sid": "PN71a08432464f72a5c066b5937cde1ae7",
      "account_sid": "ACa61cd972830fc5bc41386edc0a9f8463",
      "friendly_name": "Reminders (texts only)",
      "phone_number": "+61491570157",
      "voice_url": null,
      "voice_method": "POST",
      "voice_fallback_url": null,
      "voice_fallback_method": "POST",
      "status_callback": null,
      "status_callback_method": "POST",
      "sms_url": "https://hooks.example.com/sms/incoming",
      "sms_method": "POST",
      "sms_fallback_url": null,
      "sms_fallback_method": "POST",
      "capabilities": {
        "voice": false,
        "sms": true,
        "mms": false,
        "fax": false
      },
      "date_created": "Fri, 16 Oct 2026 02:20:00 +0000",
      "date_updated": "Fri, 16 Oct 2026 02:20:00 +0000",
      "uri": "/2010-04-01/Accounts/ACa61cd972830fc5bc41386edc0a9f8463/IncomingPhoneNumbers/PN71a08432464f72a5c066b5937cde1ae7.json",
      "dongle": {
        "state": "serving",
        "callable": false,
        "why_not": "no_calling_dongle",
        "why_not_text": "this line has no calling dongle: texts only",
        "sip": null
      }
    }
  ]
}

GET /Accounts/{AccountSid}/IncomingPhoneNumbers/{PNSid}.json

Read one line.

Returns one line with its dongle extension. The SIP password is never shown back.

Responses

StatusMeaning
200

The line.

401

Authentication failed (20003), or the account isn't active (20005). This comes before any lookup.

404

Not found (20404). That includes a Sid that isn't on the path's account; the answer never hints at another tenant.

429

Over a rate (20429, with Retry-After in seconds): per account, GET 10/s (burst 30), list pages with PageSize over 50 at 2/s, POST/DELETE 5/s (burst 10); per source IP before auth, 20/s; a gateway-wide ceiling with a fair share per account. Failed auth from one source IP (10/min) also answers 429 with code 20429, for 15 min.

500

An internal error (799999).

Response fields

FieldTypeAlways thereDescription
sid string

PN + 32 hex.

account_sid string
friendly_name string
phone_number string

The line's number, E.164.

voice_url string or null

Where incoming calls are sent (the incomingCall webhook).

voice_method string: GET, POST
voice_fallback_url string or null
voice_fallback_method string: GET, POST
status_callback string or null

The line's StatusCallback. An incoming call's status events go here, and so do runtime errors when the Call or Message has none of its own.

status_callback_method string: GET, POST
sms_url string or null

Where incoming texts are sent (the incomingMessage webhook).

sms_method string: GET, POST
sms_fallback_url string or null
sms_fallback_method string: GET, POST
capabilities object

What the line can do.

capabilities.voice booleanrequired

True only on a calling dongle.

capabilities.sms booleanrequired

Always true.

capabilities.mms booleanrequired

Always false (no MMS in v1).

capabilities.fax booleanrequired

Always false.

date_created string

RFC 2822.

date_updated string

RFC 2822.

uri string
dongle oursobject

Ours, showing the state of the dongle behind the line.

dongle.state oursstring: serving, not_servingrequired

Whether the line is on the network now.

dongle.callable oursbooleanrequired

Whether it can make or take a call now.

dongle.why_not oursstring: no_calling_dongle, dongle_offline, line_suspended, temporarily_unavailable or nullrequired

Why the line can't call now, or null: no_calling_dongle (texts only; a permanent state), dongle_offline (not connected now), line_suspended (not rented, moving, or ended), temporarily_unavailable (anything brief on our side).

dongle.why_not_text oursstring or nullrequired

The why_not reason in our fixed words (one per code), or null when the line can call.

dongle.sip oursobject or nullrequired

The line's SIP login, or null on a texts-only line (no calling dongle). It's made automatically, and it's for softphones and for PBXs as a "SIP trunk with registration": TLS 1.2+, SRTP required, digest auth. Its fields: username, domain (voice.dongleswithwings.com), port (5061), transport (tls), srtp (required), state (not_set or active) and password_set_at.

One call per dongle, across API and SIP. The password is never shown back. SIP stays OFF on an API-mode line until a password is set (state not_set), using DwwSipPassword. The exception: a line that already had a working login when it entered API mode keeps that login working until the customer sets their own. That login stays active, with no outage.

dongle.sip.username oursstringrequired

The SIP username (made automatically).

dongle.sip.domain oursstringrequired
dongle.sip.port oursintegerrequired
dongle.sip.transport oursstringrequired
dongle.sip.srtp oursstringrequired
dongle.sip.state oursstring: not_set, activerequired
dongle.sip.password_set_at oursstring or nullrequired

When the SIP password was last set (RFC 2822), or null if it has never been set.

dww_sip_password oursstring

Only in the response to DwwSipPassword=generate, and only that once. It's never shown again.

Example request

curl -X GET "https://api.dongleswithwings.com/2010-04-01/Accounts/{AccountSid}/IncomingPhoneNumbers/{PNSid}.json" \
  -u "$ACCOUNT_SID:$AUTH_TOKEN"

Example response

{
  "sid": "PN3e18acd0169a00c48635e530c42a01ca",
  "account_sid": "ACa61cd972830fc5bc41386edc0a9f8463",
  "friendly_name": "Reception",
  "phone_number": "+61491570156",
  "voice_url": "https://hooks.example.com/voice/incoming",
  "voice_method": "POST",
  "voice_fallback_url": "https://hooks-backup.example.com/voice/incoming",
  "voice_fallback_method": "POST",
  "status_callback": "https://hooks.example.com/status",
  "status_callback_method": "POST",
  "sms_url": "https://hooks.example.com/sms/incoming",
  "sms_method": "POST",
  "sms_fallback_url": null,
  "sms_fallback_method": "POST",
  "capabilities": {
    "voice": true,
    "sms": true,
    "mms": false,
    "fax": false
  },
  "date_created": "Fri, 16 Oct 2026 02:15:00 +0000",
  "date_updated": "Mon, 02 Nov 2026 01:30:00 +0000",
  "uri": "/2010-04-01/Accounts/ACa61cd972830fc5bc41386edc0a9f8463/IncomingPhoneNumbers/PN3e18acd0169a00c48635e530c42a01ca.json",
  "dongle": {
    "state": "not_serving",
    "callable": false,
    "why_not": "dongle_offline",
    "why_not_text": "the line's dongle isn't connected right now",
    "sip": {
      "username": "dww-4b7e19c2",
      "domain": "voice.dongleswithwings.com",
      "port": 5061,
      "transport": "tls",
      "srtp": "required",
      "state": "active",
      "password_set_at": "Mon, 02 Nov 2026 01:30:00 +0000"
    }
  }
}

POST /Accounts/{AccountSid}/IncomingPhoneNumbers/{PNSid}.json

Change a line's webhook URLs, its name, or its SIP password.

v1 changes only the parameters listed here; DwwSipPassword is ours. Others answer 700009.

Updates the line's settings. Every URL must pass the fetch rules (see the Webhooks guide) when it's set, and again each time it's used. Any parameter not listed here is refused with code 700009, which names it, and a value that isn't valid (e.g. VoiceMethod=PUT) with code 700012.

Setting the SIP password (not yet available: today DwwSipPassword answers 700009, like any parameter not listed): it will use DwwSipPassword. The console uses this same API; there's no other way in. Until then, a line that already has a SIP login keeps it, and a line without one has SIP off. How it will work: - DwwSipPassword=generate makes a strong password and returns it ONCE, as dww_sip_password in this response. - Rules: ≥ 16 characters of printable ASCII, from 3 of the 4 character classes. It must not contain the username, the line's number or the AccountSid, and must not be on a deny list. Otherwise the answer is 740001, with reason one of too_short, charset, classes, contains_identity, deny_list. - ≤ 5 changes per line per hour, otherwise 740002. - How it's stored: the gateway computes the SIP digest hash (HA1) in memory with your line's SIP username and realm, then drops the password. Only the HA1 is kept. - The owner is emailed on every change, and every change is logged as an event with no value. - SIP stays OFF on an API-mode line until a password is set (dongle.sip.state not_set), unless the line already had a working login when it entered API mode. That login keeps working until the customer sets their own. - There's no recovery: if the password is lost, set a new one. The password is never shown back.

Request body

Form-encoded (application/x-www-form-urlencoded).

FieldTypeRequiredDescription
FriendlyName string

A name for the line.

VoiceUrl string

Where incoming calls are sent (the incomingCall webhook). Refused URL 790001; invalid URL 21205.

Errors: 21205, 790001

VoiceMethod string: GET, POST

Errors: 700012

VoiceFallbackUrl string

Runs only after a FAST failure of VoiceUrl with ≥ 4 s left of the 12 s window.

Errors: 21205, 790001

VoiceFallbackMethod string: GET, POST

Errors: 700012

StatusCallback string

The line's StatusCallback. An incoming call's status events go here, and so do runtime errors when the Call or Message has none of its own.

Errors: 21205, 790001

StatusCallbackMethod string: GET, POST

Errors: 700012

SmsUrl string

Where incoming texts are sent (the incomingMessage webhook).

Errors: 21205, 790001

SmsMethod string: GET, POST

Errors: 700012

SmsFallbackUrl string

Asked once within a try of SmsUrl when SmsUrl errors or times out.

Errors: 21205, 790001

SmsFallbackMethod string: GET, POST

Errors: 700012

DwwSipPassword oursone of string

Sets the line's SIP password, or generate to have a strong one made and returned once as dww_sip_password. Rules: ≥ 16 characters of printable ASCII, from 3 of the 4 character classes. It must not contain the username, the line's number or the AccountSid, and must not be on a deny list (740001, with reason too_short, charset, classes, contains_identity or deny_list). ≤ 5 changes per line per hour (740002). Only the HA1 is kept, and there's no recovery.

Errors: 740001, 740002

Any parameter not listed here is refused with 700009, naming it in parameter: v1 never ignores one.

Responses

StatusMeaning
200

The updated line. dww_sip_password appears only in the response to DwwSipPassword=generate.

400

A value or a parameter was refused: 21205, 700009, 700012, 740001 or 790001.

401

Authentication failed (20003), or the account isn't active (20005). This comes before any lookup.

404

Not found (20404). That includes a Sid that isn't on the path's account; the answer never hints at another tenant.

413

The request body is over 64 KiB (790006). It's refused before parsing.

429

Too many requests (20429), or too many SIP password changes on this line (740002).

500

An internal error (799999).

Response fields

FieldTypeAlways thereDescription
sid string

PN + 32 hex.

account_sid string
friendly_name string
phone_number string

The line's number, E.164.

voice_url string or null

Where incoming calls are sent (the incomingCall webhook).

voice_method string: GET, POST
voice_fallback_url string or null
voice_fallback_method string: GET, POST
status_callback string or null

The line's StatusCallback. An incoming call's status events go here, and so do runtime errors when the Call or Message has none of its own.

status_callback_method string: GET, POST
sms_url string or null

Where incoming texts are sent (the incomingMessage webhook).

sms_method string: GET, POST
sms_fallback_url string or null
sms_fallback_method string: GET, POST
capabilities object

What the line can do.

capabilities.voice booleanrequired

True only on a calling dongle.

capabilities.sms booleanrequired

Always true.

capabilities.mms booleanrequired

Always false (no MMS in v1).

capabilities.fax booleanrequired

Always false.

date_created string

RFC 2822.

date_updated string

RFC 2822.

uri string
dongle oursobject

Ours, showing the state of the dongle behind the line.

dongle.state oursstring: serving, not_servingrequired

Whether the line is on the network now.

dongle.callable oursbooleanrequired

Whether it can make or take a call now.

dongle.why_not oursstring: no_calling_dongle, dongle_offline, line_suspended, temporarily_unavailable or nullrequired

Why the line can't call now, or null: no_calling_dongle (texts only; a permanent state), dongle_offline (not connected now), line_suspended (not rented, moving, or ended), temporarily_unavailable (anything brief on our side).

dongle.why_not_text oursstring or nullrequired

The why_not reason in our fixed words (one per code), or null when the line can call.

dongle.sip oursobject or nullrequired

The line's SIP login, or null on a texts-only line (no calling dongle). It's made automatically, and it's for softphones and for PBXs as a "SIP trunk with registration": TLS 1.2+, SRTP required, digest auth. Its fields: username, domain (voice.dongleswithwings.com), port (5061), transport (tls), srtp (required), state (not_set or active) and password_set_at.

One call per dongle, across API and SIP. The password is never shown back. SIP stays OFF on an API-mode line until a password is set (state not_set), using DwwSipPassword. The exception: a line that already had a working login when it entered API mode keeps that login working until the customer sets their own. That login stays active, with no outage.

dongle.sip.username oursstringrequired

The SIP username (made automatically).

dongle.sip.domain oursstringrequired
dongle.sip.port oursintegerrequired
dongle.sip.transport oursstringrequired
dongle.sip.srtp oursstringrequired
dongle.sip.state oursstring: not_set, activerequired
dongle.sip.password_set_at oursstring or nullrequired

When the SIP password was last set (RFC 2822), or null if it has never been set.

dww_sip_password oursstring

Only in the response to DwwSipPassword=generate, and only that once. It's never shown again.

Example request

curl -X POST "https://api.dongleswithwings.com/2010-04-01/Accounts/{AccountSid}/IncomingPhoneNumbers/{PNSid}.json" \
  --data-urlencode "FriendlyName=Reception" \
  --data-urlencode "VoiceUrl=https://hooks.example.com/voice/incoming" \
  --data-urlencode "VoiceMethod=POST" \
  --data-urlencode "SmsUrl=https://hooks.example.com/sms/incoming" \
  --data-urlencode "SmsMethod=POST" \
  --data-urlencode "DwwSipPassword=generate" \
  -u "$ACCOUNT_SID:$AUTH_TOKEN"

Example response

{
  "sid": "PN3e18acd0169a00c48635e530c42a01ca",
  "account_sid": "ACa61cd972830fc5bc41386edc0a9f8463",
  "friendly_name": "Reception",
  "phone_number": "+61491570156",
  "voice_url": "https://hooks.example.com/voice/incoming",
  "voice_method": "POST",
  "voice_fallback_url": "https://hooks-backup.example.com/voice/incoming",
  "voice_fallback_method": "POST",
  "status_callback": "https://hooks.example.com/status",
  "status_callback_method": "POST",
  "sms_url": "https://hooks.example.com/sms/incoming",
  "sms_method": "POST",
  "sms_fallback_url": null,
  "sms_fallback_method": "POST",
  "capabilities": {
    "voice": true,
    "sms": true,
    "mms": false,
    "fax": false
  },
  "date_created": "Fri, 16 Oct 2026 02:15:00 +0000",
  "date_updated": "Mon, 02 Nov 2026 01:30:00 +0000",
  "uri": "/2010-04-01/Accounts/ACa61cd972830fc5bc41386edc0a9f8463/IncomingPhoneNumbers/PN3e18acd0169a00c48635e530c42a01ca.json",
  "dongle": {
    "state": "serving",
    "callable": true,
    "why_not": null,
    "why_not_text": null,
    "sip": {
      "username": "dww-4b7e19c2",
      "domain": "voice.dongleswithwings.com",
      "port": 5061,
      "transport": "tls",
      "srtp": "required",
      "state": "active",
      "password_set_at": "Mon, 02 Nov 2026 01:30:00 +0000"
    }
  },
  "dww_sip_password": "5wf9KFrC7L-GiRUx9WVl1UF-"
}