Skip to content

docs(voice): add inbound calling guide - #697

Open
Devon-White wants to merge 10 commits into
mainfrom
devon/inbound-calling-guide
Open

Devon-White wants to merge 10 commits into
mainfrom
devon/inbound-calling-guide

Conversation

@Devon-White

Copy link
Copy Markdown
Collaborator

Summary

  • New guide at /docs/platform/voice/inbound-calling, a companion to the outbound calling guide with the same shape: prepare, answer a first call, follow the call, examples, next steps.
  • Opens with how a call reaches a Resource through its addresses (phone number, SIP address, alias), based on the live Dashboard: Addresses & Phone Numbers tab, Inbound Call Settings → Assign Resource, Relay Application Topic, SWML Script External URL / Hosted Script.
  • First call in three tabs: SWML served by the Server SDKs (default), WebSocket (Relay), Browser SDK. Number assignment shown in the Dashboard and with REST plus the Python and TypeScript wrappers. Hosted-script REST flow is in an Accordion.
  • Examples: AI agent, phone menu, forward with whisper, voicemail, background recording, audio streaming, answer in the browser.
  • Two new themed SVG lifecycle diagrams with <llms-only> Mermaid equivalents.
  • Adds an "Answer an inbound call" card to the Voice overview and a link in the root llms.txt.

Review notes

  • REST assignment uses PUT /api/relay/rest/phone_numbers/{id} with relay_script and relay_topic. The TypeSpec core model marks the Relay topic status callback URL as required, but the request model and both SDK wrappers make it optional; the guide follows the SDKs.
  • Subscriber assignment via REST uses the beta phone-number-addresses endpoint and is labeled beta.
  • SIP address format sip:<user>@<space>-<context>.dapp.signalwire.com is taken from the Dashboard form's fixed prefix and suffix; confirm it's stable.
  • Relay samples omit host, per the RelayClient reference; the outbound guide passes the Space host.

Verification

yarn fern-md-check: all 2749 MDX files valid.

Companion to the outbound calling guide. Covers how a call reaches a
Resource through its addresses (phone number, SIP address, alias), then
answers a first call with SDK-served SWML, Relay, or the Browser SDK,
assigns the number in the Dashboard or with REST, follows the call, and
adds AI agent, phone menu, whisper, voicemail, recording, streaming, and
browser-answering examples. Adds two themed lifecycle diagrams, a card on
the Voice overview, and a root llms.txt link.
@github-actions

github-actions Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Turn the Addresses page from a one-snippet stub into the reference for
how a Resource is reached: phone numbers, SIP addresses, and aliases;
contexts and channels; how SignalWire resolves an address; one Resource
with many addresses; and how to manage addresses in the Dashboard, the
REST API, and the Browser SDK. Add a shared snippet for assigning a
Resource to a phone number, use it from Resources, Addresses, and the
inbound calling guide, and trim the guide's addressing section to a
summary that links here.
Frame the guide around where the logic runs and how SignalWire reaches
it: SWML over HTTP (Server SDK), serverless SWML (hosted in the Space),
WebSocket from your server (Relay), and WebSocket from the browser.
Give serverless SWML its own tab in the handler and assignment steps
instead of an aside and accordion, compare all four in one table, and
state that only Subscriber tokens receive calls in the browser while
guest and embed tokens are outbound-only.
Add a step that chooses how callers reach the handler: phone number,
SIP address, or alias, independent of the handler choice. Split the old
number-assignment step into creating the Resource (per handler) and
giving it an address (per address type), with Dashboard and REST paths
for each, and make the test-call step follow the chosen address.
…er SDK

Name the four approaches by SDK and transport: Server SDK over HTTP
(SWML), Server SDK over WebSocket (Relay), Browser SDK over WebSocket,
and serverless SWML. Say outright that SWML is what the Server SDK
serves and that the Browser SDK is Relay in the browser, so the
comparison no longer sets SWML against a WebSocket it also uses.
@Manny-r31

Copy link
Copy Markdown
Collaborator

Errors

  • Default alias context for AI Agents is private, not public. The addresses page says an AI Agent named Support Agent lands at /public/support-agent. In prime-rails the RelayBin adapter, which covers AI Agents, SWML Scripts, and Call Flows, sets the auto-created alias to the private context. Relay Applications are private too. Only Video Rooms, SIP Credentials, SIP Gateways, cXML Scripts, FreeSWITCH Connectors, and the external webhook handlers default to public. Line 84 to 87 of addresses.mdx.
  • The Dashboard cannot re-point an alias to another Resource. The page says to "open the alias and change its assigned Resource" in the Dashboard. Neither alias edit form (the Resource's Addresses tab or the Space-wide Addresses page) has a Resource field, and both update contracts accept only name, display name, display type, context, channels, codecs, and Call Flow version. The Dashboard's own helper text promises the Resource "can be changed later," but the forms don't deliver it. Re-pointing is delete and recreate in both the Dashboard and the REST API. Line 98 to 101.
  • The picker offers "Video Room", not "Conference Room". The Resource picker view lists Script, AI Agent, Video Room, Relay Application, Subscriber, FreeSWITCH Connector, Call Flow, SIP, and Queue behind a feature flag. Script, AI Agent, and SIP open sub-choices (SWML or cXML Script, Custom or Google DialogFlow Agent, SIP Credential or SIP Gateway). resources.mdx line 124.
  • Wrong endpoint linked for listing a Resource's addresses. The Resources page links "list a Resource's addresses" to the client endpoint that requires a Subscriber token and lists what that Subscriber can reach. The admin endpoint is List Resource Addresses at /api/fabric/resources/{id}/addresses, slug /docs/apis/rest/addresses/list-resource-addresses. resources.mdx line 75.

Minor issues

  • The phone number context is stored and returned by the API as lowercase external. The Dashboard title-cases it to "External". The page writes External in code font on lines 51 and 115, which matches neither exactly. Use lowercase in code font or plain text without code font.
  • The call handler list on line 57 reads as complete but omits cXML Scripts and Applications, Video Rooms, SIP Gateways, FreeSWITCH Connectors, and DialogFlow Agents, all of which the phone route allows. Adding "such as" fixes it.
  • The Resources page calls the type "SIP Endpoints" while the Dashboard picker and the addresses page say "SIP Credential". Pick one across both pages.
  • The Browser SDK section names client.directory. Our own Browser SDK address book page documents it as the observable client.directory$. I could not check the SDK source since it is not in the local tree.
  • I could not confirm the "Assign Resource" button label under Inbound Call Settings from the phone route form source. The section headings "Inbound Call Settings", "Inbound Message Settings", and "Edit Settings" do match.

Verified correct

Two independent handlers per number. Message handlers restricted to messaging-capable types. SIP host format <space>-<context>.dapp.signalwire.com with user defaulting to *, domain defaulting to the public context, and password, IP allowlist, encryption, codec, and cipher options. Alias auto-creation from the Resource name via parameterize, so john.doe becomes john-doe in the private context and names allow lowercase letters, digits, underscores, and dashes. Channels audio, video, messaging. Display As app, room, call, subscriber. REST alias update has no resource_id. Context omission works for Subscriber-originated dials. WhatsApp appears in the Resource's Add an Address menu. Sidebar groups, My Resources columns, and Addresses page columns all match the views.

Devon-White and others added 2 commits September 17, 2026 13:21
- Default alias context for AI Agents, scripts, and applications is
  private, not public; note which types get a public alias instead
- Aliases can't be re-pointed in the Dashboard or REST: delete and
  re-create
- Resource picker offers Video Room, not Conference Room, with its
  sub-choices
- Link the admin List Resource Addresses endpoint, not the client one
- Lowercase external context; 'such as' on the call handler list;
  SIP Credentials card; client.directory$ observable
@Manny-r31

Manny-r31 commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator

Review: Resources and Addresses pages

Gaps in the model

  • Per-type defaults. Nothing says which context/channels a new Resource's alias gets. Customers need this to know a new AI Agent is unreachable from a public widget until they add a public alias. Suggest a small table: type, default context, default channels, Display As.
  • Relationship rules never stated. One address → one Resource; one Resource → many addresses; names unique per context so /public/support and /private/support coexist; a phone number is two addresses (calling, messaging) in external, each independently assignable. A Context → Address → Resource diagram next to the resolution flowchart would carry it.
  • Deletion. Neither page says what happens when you delete a Resource with addresses or delete an address. Dashboard copy confirms: deleting an address leaves the Resource and in-progress calls intact; removing a handler leaves the number in the account unassigned.
  • WhatsApp It behaves like a phone number: two handlers (calling, messaging) assigned to Resources. Move the mention from the Aliases section to the end of Phone numbers, and keep it light since the Add an Address option is feature-flagged and the public REST API exposes it only via the WhatsApp Numbers endpoints.
  • Contexts. Explain that a context has an access type (public/private) that governs reachability, that public/private are the built-in read-only ones, and that SIP domains are contexts. guest and custom contexts can stay light (feature-flagged).
  • Omitting the context (line ~118) only works for calls placed by an authenticated Subscriber. REST dials and SWML connect need the full /context/name. Current wording will trip server-side devs.
  • Address properties are scattered: display name vs URL-safe name, Display As, channels, codecs (aliases too, not just SIP), Call Flow version pinning. A short property list would match the REST response.
  • "Handler" is used ~15 times and never defined. One clause at first use.

Structure

  • Resources page duplicates the addresses page (Resource addresses section, Give it an address, the same snippet) and includes the "What's a Resource?" admonition that links back to itself. Suggest: Resources owns what/types/create/manage; Addresses owns reaching one; Resources keeps a short handoff.

Already strong

Two-handler phone number explanation, SIP address vs Credential vs gateway, resolution flowchart, swap-a-handler example, REST task table.

- Define handler at first use; state address/Resource relationship rules
- Per-type table for the first alias's context; External URL scripts are public
- Alias property list matching the REST object; display_type is derived
- WhatsApp number as its own address type; deletion behavior
- Contexts: public/private built in; only Subscriber dials may omit the context
- Resources page hands off to Addresses instead of duplicating it; drop the
  self-referencing admonition; snippet says SIP Credentials
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants