Skip to content

Document WhatsApp inbound voice calling - #687

Merged
hey-august merged 26 commits into
mainfrom
august-20260903-whatsapp-voice
Sep 17, 2026
Merged

hey-august merged 26 commits into
mainfrom
august-20260903-whatsapp-voice

Conversation

@hey-august

@hey-august hey-august commented Sep 15, 2026

Copy link
Copy Markdown
Collaborator

Description

Additions

Adds inbound WhatsApp calling docs under /docs/platform/voice/whatsapp:

  • overview
  • guide to connecting a business number (shares its Dashboard steps and its verification section with the messaging onboarding page through two snippets)
  • guide to enabling calling on a connected business number
  • guide to receiving calls, written to the in-progress mdx-capability-guides skeleton: 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 to signalwire-sdk==3.4.1 and @signalwire/sdk@2.0.5
  • a Video Room glossary entry, with Conference Room recorded as the alias the REST reference and the Dashboard Address picker use

Spec:

  • POST /api/fabric/resources/{id}/whatsapp_numbers as the WhatsApp Routes tag, so the guide can embed the assignment request; the response is a oneOf of the app, room, and call Address shapes
  • named "Phone call" and "WhatsApp call" examples on List voice logs, so the guide can select and highlight the WhatsApp entry
  • Phone Routes now declares 201, which is what the API returns

Changes

  • Adds links to the new section from the Calling index, the Voice overview, the WhatsApp messaging overview, and the top-level llms.txt (channels list and Popular features → Calling).
  • Edited the voice_enabled and voice_capable field descriptions in the WhatsApp numbers spec to match and point at the guides.
  • Messaging onboarding includes the shared snippets and names the Numbers scope the way the spec does.
  • Corrected the calling.transfer command's destination description and example in the REST Calling API reference.
  • The glossary's Resource type list says Video Room where it said Conference Room.

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 room and a SIP endpoint or connector returns call, so the response is a oneOf of the three Address shapes instead of copying Phone Routes' app-only model. The description names the call case 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 cond replaced with a Server SDK dynamic-config callback.
    The SDK builders can't emit cond and the house direction is to showcase the Server SDKs, so the channel branch reads call.to inside set_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.

  • contents is 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.transfer accepts 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_enabled can 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 from address 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 Dashboard and via the REST API headings and the cURL — REST API block 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-routes from the tag name and breaks every link to the reference page.

For reviewers

  • example and highlight on EndpointResponseSnippet are 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, where to lands after sorting; confirm on the preview.
  • The pages live at /voice/whatsapp/... to mirror /messaging/whatsapp/..., while the nav places WhatsApp beside Voice under Calling. Deliberate; ruling welcome.
  • The REST reference still titles the room Resource "Conference Room"; renaming it is a spec change for a later PR.
  • Neither Server SDK exposes the assignment endpoint, so the first run's attach step uses the endpoint directly and says so. An SDK issue is drafted, not yet filed.

Verification

  • yarn build:specs, yarn fern-md-check, and yarn fern-check pass (the latter reports only the unauthenticated redirects check).
  • Facts checked against the platform source: handler types, Address replacement and the call display type, the voice_enabled default, reset, and enable flow, voice_capable logic, the Dashboard picker's Add action, the destination forms transfer accepts, the leg and log type a WhatsApp call writes, and the whatsapp: prefix on to.
  • Every SDK method checked against the 3.4.1 and 2.0.5 tags, including the Relay inbound client. Python samples compile, the cURL block passes bash -n, and tsc --strict reports no errors in the TypeScript samples against the SDK source checkout. Not run: pyflakes and a live first-run call.
  • Anchors resolved by hand against target headings.

Preview:

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • Code cleanup / refactor

Related Issues

#650

Testing

  • Added/updated unit tests
  • Tested manually
  • Tested with live SignalWire credentials (if applicable)

Checklist

  • I have read the CONTRIBUTING guidelines
  • My code follows the project's style guidelines
  • I have added tests for my changes (if applicable)
  • I have updated documentation (if applicable)
  • All existing tests pass

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

@hey-august hey-august changed the title WhatsApp voice Document WhatsApp inbound voice calling Sep 17, 2026

@Devon-White Devon-White left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 to topic and contexts. Explicitly mentioning the example value booking would 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.

Comment thread fern/products/platform/pages/calling/whatsapp/receive-calls.mdx Outdated
Comment thread fern/products/platform/pages/calling/whatsapp/receive-calls.mdx Outdated
Comment thread fern/products/platform/pages/messaging/whatsapp/onboarding.mdx Outdated

@Devon-White Devon-White left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread fern/products/platform/pages/calling/voice/overview.mdx Outdated
Comment thread fern/products/platform/pages/calling/whatsapp/overview.mdx
Comment thread fern/products/platform/pages/calling/whatsapp/overview.mdx Outdated
Comment thread fern/products/platform/pages/calling/whatsapp/receive-calls.mdx Outdated
@Devon-White
Devon-White self-requested a review September 17, 2026 22:28
@hey-august
hey-august merged commit 4c17c8a into main Sep 17, 2026
2 checks passed
@hey-august
hey-august deleted the august-20260903-whatsapp-voice branch September 17, 2026 22:30
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