Document WhatsApp inbound voice calling - #687
Merged
Merged
Conversation
Contributor
…nse as app or room
…, and link from Voice
Devon-White
reviewed
Sep 17, 2026
Devon-White
left a comment
Collaborator
There was a problem hiding this comment.
Revalidated the ten findings from the earlier review against commit c92109a7c7, the API schemas, the platform implementation, and the available preview. Three actionable findings remain; the inline comments include suggested edits for #5 (REST forwarding), #7 (current-handler troubleshooting), and #8 (onboarding paragraph placement).
I would not carry forward the other findings as proposed:
- #1 — SWML contents: The platform parser explicitly accepts both strings and objects. Changing the examples to objects is not justified by the narrower public schema alone.
- #2 — Phone Routes 201: The controller returns
created. Both Server SDK reference pages embed the shared endpoint schema/response, so they do not have a separate hardcoded 200 to update. - #3 — One Address: The assignment operation passes one handler to a service that processes both channels and tears down the omitted channel's Address. Separate nullable model fields do not establish that this assignment preserves both.
- #4 — Highlight: Not verified. Counting the source JSON does not establish the rendered line number; endpoint snippets did not render in the preview session, so I am not suggesting a speculative line-number change.
- #6 — Topic:
<YOUR_TOPIC>is defined in the replacement table, and the Relay section explains its relationship totopicandcontexts. Explicitly mentioning the example valuebookingwould be an optional clarity improvement, rather than a missing required setup step. - #9 — Picker naming: The cited paragraphs refer to differently named controls; their wording alone does not establish a contradiction. I could not confirm which UI label should replace the glossary wording.
- #10 — Navigation: The explicit slug is deliberate and preserves the reference URL used throughout the guide. Matching the shorter neighboring entry is not a correctness fix.
Validation was by source inspection and preview inspection; no live WhatsApp call was placed.
Devon-White
reviewed
Sep 17, 2026
Devon-White
left a comment
Collaborator
There was a problem hiding this comment.
Four minor guide-consistency comments; none is a merge blocker. I verified the disputed response highlight in the rendered preview and did not carry that finding forward.
Devon-White
self-requested a review
September 17, 2026 22:28
Devon-White
approved these changes
Sep 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Additions
Adds inbound WhatsApp calling docs under
/docs/platform/voice/whatsapp:mdx-capability-guidesskeleton: task-by-surface matrix, Prepare, a four-step first run with a verification step, task sections per surface (Dashboard, REST API, Relay, SWML), and complete Server SDK samples pinned tosignalwire-sdk==3.4.1and@signalwire/sdk@2.0.5Spec:
POST /api/fabric/resources/{id}/whatsapp_numbersas the WhatsApp Routes tag, so the guide can embed the assignment request; the response is a oneOf of the app, room, and call Address shapesChanges
voice_enabledandvoice_capablefield descriptions in the WhatsApp numbers spec to match and point at the guides.calling.transfercommand's destination description and example in the REST Calling API reference.Note
Outbound calls to WhatsApp users are not supported. The overview's "What WhatsApp calling supports" section says so, and the guide's Prepare section points there.
Decisions
Outbound calling to WhatsApp users doesn't exist.
The outbound routing work was closed unmerged in March 2026, so the docs cover inbound only and never list
whatsapp:as a dial destination.Four attachable Resource types fail on the first call.
The allowed-types list and the call handlers were built from different tickets and never reconciled, so the guide lists only the five types with working handlers (AI Agent, Call Flow, SWML Script, Relay Application, Video Room) and omits SIP Endpoint, SIP Gateway, FreeSWITCH Connector, and Dialogflow Agent.
The assignment endpoint was live but absent from the public spec.
Added as "WhatsApp Routes" mirroring Phone Routes, declared 201 as the controller returns, and placed under Resource Management right after Phone Routes.
A WhatsApp number holds one address at a time.
Both the Dashboard and the API call the same service with a single handler, which discards the other channel's Address, so the guide and the endpoint description state it rather than hide it.
The assignment response is an app, room, or call Address.
A Video Room handler returns
roomand a SIP endpoint or connector returnscall, so the response is a oneOf of the three Address shapes instead of copying Phone Routes' app-only model. The description names thecallcase even though the guide doesn't list those Resource types as handlers, because the schema has to match what the API can return.Raw SWML
condreplaced with a Server SDK dynamic-config callback.The SDK builders can't emit
condand the house direction is to showcase the Server SDKs, so the channel branch readscall.toinsideset_dynamic_config_callback. The agent is Ada at Bayview Taxi, the running example the AI guides share.First run uses a SWML Script hosted on SignalWire, not an agent on the reader's server.
It's the smallest thing a reader can verify without a public URL; the agent example follows as a task section with a pointer to the Mapping Numbers guide for the External URL step.
contentsis sent as a JSON string in the SDK samples.Both SDKs type the field as a string and the platform accepts a string or an object; the guide says so under the cURL sample, which sends an object.
Matrix columns exclude Browser SDK and Fabric API.
Subscribers can't be WhatsApp handlers and assignment isn't a call-handling surface, so each gets one sentence under the table instead of a column. The Browser SDK column the guide rule asks for was added and then removed at Nirav's request.
Constraints live on the overview, not in Prepare.
At Nirav's request the inbound-only, audio-only, and no-hold limits sit in one overview section, "What WhatsApp calling supports", and the guide's Prepare section points there instead of repeating them as Warnings.
calling.transferaccepts only SWML destinations.Review asked to mark REST forwarding as supported because the command's reference listed SIP URIs and phone numbers. The engine accepts an HTTP(S) URL or a section name, so the reference now says a SWML URL or inline document, and the matrix keeps its cross.
Relay gets one task section, Call Flow Builder none.
"Answer the call from your own code with Relay" creates a Relay Application, attaches the number, and runs a complete inbound client in both languages. Call Flow Builder stands on its link.
Relay is omitted from "Read the caller's number".
The Relay Call exposes numbers only in device params and their shape on a WhatsApp call is unverified.
Voice logs got explicit named examples.
The endpoint had none, so "Phone call" is declared first to keep the reference default stable and "WhatsApp call" lets the guide select and highlight
to, with values taken from the Relay PSTN leg the platform writes for these calls.voice_enabledcan flip back to false.The platform renews the number's calling registration with Meta and a refused renewal clears the flag, so Enable voice carries a titled Warning and the verification step checks the field.
No "Registered first" gate on enabling calling.
The platform registers a number with Meta as part of enabling calling, so Enable voice says a Pending number can fail with a Meta error until its setup is complete, rather than claiming the Dashboard blocks it.
Video Room is the canonical name.
The Dashboard's Resource list, the platform docs, and the call handlers say Video Room; the REST reference and the Dashboard Address picker say Conference Room. The glossary entry records the alias and the guide links the name to it.
Capitalization: Resource and Address.
Review asked for both capitalized. The glossary, as the source of truth, now capitalizes Address as the name of the routing entity (Resource Address, Phone Number Address), with a lowercase
fromaddress kept only in its generic messaging sense. The WhatsApp pages, the WhatsApp Routes spec strings, and the glossary follow that.Onboarding is shared by snippet, not by a single page.
Voice readers shouldn't hop to the messaging section, so the Dashboard steps and the verification calls live in two snippets while each page keeps one paragraph on what its channel reads from the response.
Deviations from the guide rule are deliberate, and the rule is untouched.
The imperative title and three-segment slug follow the WhatsApp messaging siblings. The
via the Dashboardandvia the REST APIheadings and thecURL — REST APIblock title name management surfaces the rule has no shape for. Whether channel guides get a variant or an exemption is a separate decision.The WhatsApp Routes nav entry keeps its explicit slug.
The bare package form makes Fern derive
whats-app-routesfrom the tag name and breaks every link to the reference page.For reviewers
exampleandhighlightonEndpointResponseSnippetare documented Fern props but first uses in this repo (Receive calls, logs section); Fern sorts the example's keys alphabetically when it renders the snippet, so the highlight is line 20, wheretolands after sorting; confirm on the preview./voice/whatsapp/...to mirror/messaging/whatsapp/..., while the nav places WhatsApp beside Voice under Calling. Deliberate; ruling welcome.Verification
yarn build:specs,yarn fern-md-check, andyarn fern-checkpass (the latter reports only the unauthenticated redirects check).calldisplay type, thevoice_enableddefault, reset, and enable flow,voice_capablelogic, the Dashboard picker's Add action, the destination formstransferaccepts, the leg and log type a WhatsApp call writes, and thewhatsapp:prefix onto.bash -n, andtsc --strictreports no errors in the TypeScript samples against the SDK source checkout. Not run: pyflakes and a live first-run call.Preview:
Type of Change
Related Issues
#650
Testing
Checklist
🤖 Generated with Claude Code