Skip to main content

WhatsApp API

Manage everything that surrounds WhatsApp Business messaging — your WABA connection, business profile, product catalogs, Flows, voice calls, and block lists. Sending messages themselves uses the unified Messaging API (POST /api/v1/messages/whatsapp); this surface is for the configuration that backs those sends. Base path: /api/v1/whatsapp Authentication: API key (X-API-Key) or session JWT.

Connections

Each Orbit organization can attach one or more WABA phone numbers. Connections are managed via Meta’s Embedded Signup; the connect endpoint exchanges the resulting code for a long-lived token.

200 sample — list connections

Returns every connected phone number with the org default flagged (is_default: true) — send this connection’s phone_number_id to any endpoint that accepts a multi-WABA selector:
PUT /connections/{phoneNumberId}/default, PATCH /connections/{phoneNumberId}, and both DELETE variants answer with {"data": {"ok": true}, "meta": {...}}. POST /connect runs once from Meta’s Embedded Signup (it exchanges a one-time sign-up code) — the WABA setup guide walks that flow. The corresponding Node SDK call is:
The corresponding Python call — the Python SDK doesn’t wrap this page’s surface, so its client.request escape hatch runs the same resource (source-only; vendor it from packages/sdk-python):

Business profile

The about line, address, vertical, websites, and profile photo that appear in the customer’s WhatsApp client.

200 sample — read then update the business profile

Send only the fields you’re changing — everything else stays untouched:
A successful update answers {"data": {"ok": true}, "meta": {...}} — Meta re-renders the profile in the customer’s client within minutes. Field caps are validated before the call reaches Meta: about 139 chars, address 256, description 512, email 128, websites at most 2 entries (each an https URL). Exceeding one returns a 422 naming the field, so you never see Meta’s terse error_subcode.

Catalogs & products

Used by template messages and the in-WhatsApp shopping experience.

200 sample — catalog lifecycle

Manage products on a catalog the org owns, then send one to a customer:
/catalog/send accepts the same body with catalog_id inside it instead of in the path; /catalog/send-list takes sections (each with title and product_retailer_ids) and returns the same send envelope. A recipient’s cart checkout returns on the inbound webhook as an order message.

Calls — Business Calling

WhatsApp Business Calling lets a customer place a voice call to your business from inside the WhatsApp client, and lets your business call any contact who has granted call permission. See the WhatsApp Business Calling guide for end-to-end setup, country gates, billing, and lifecycle webhooks.

Provisioning (per phone number)

Outbound calls + permissions

Dashboard surfaces

Block list

Interactive, Flow & marketing sends

Most WhatsApp sends go through the unified Messaging API. Five send types have dedicated endpoints on this surface because they use Meta message types the unified send doesn’t cover: The interactive action is either { buttons } (max 3 reply buttons) or { button, sections } (a list menu, max 10 sections × 10 rows each). The recipient’s tap returns as button_reply/list_reply on the inbound webhook. For marketing sends, tracking_id is echoed on status webhooks so you can correlate delivery back to a campaign or journey.

200 sample — send → receipt → decoded reply

The send answers with the platform send envelope (status: "sent" on every send endpoint, 200 OK transport):
Watch message.sent on your tenant webhook to correlate the send, then the inbound Meta webhook carries the recipient’s tap — here a reply-button tap, decoded:
The button_reply.id round-trips the id you sent on the button, unmodified. The corresponding Node SDK call (the SDK has no helper for these five send types yet — use the low-level request escape hatch):

Location & delivery-address requests

Two more interactive prompts send inside the same 24-hour customer-service window with no template review, and the recipient’s reply threads straight back into the conversation. POST /messages/send-location-request shows a “Send location” button. When the recipient taps it and shares their location, it lands on the inbound webhook as a plain location message (not an interactive reply) — useful for “find your nearest store” or pickup-confirmation flows. Body: to and body (the prompt text, 1-1024 chars).
POST /messages/send-address-request shows a structured delivery-address form. country is an ISO 3166-1 alpha-2 code (available in India and Singapore as of Meta’s 2026 rollout) and selects the field set Meta renders — it is a wire-format check only, never a coverage or compliance gate. The completed form returns on the inbound webhook as an interactive.address_message reply, so you can attach it straight to an order. Optionally pass values to pre-fill fields you already know, or saved_addresses to offer a returning customer their prior addresses to pick from.

WhatsApp Flows

WhatsApp Flows are native multi-screen forms — appointment booking, lead capture, surveys, support triage — that render inside the WhatsApp client without sending the customer to a browser. Build and publish a Flow, send it to a recipient with POST /messages/send-flow, then read each submission back on the inbound webhook (as interactive.nfm_reply) and in the per-step funnel.

Build & manage flows

categories accepts one or more of APPOINTMENT_BOOKING, LEAD_GENERATION, CONTACT_US, CUSTOMER_SUPPORT, SURVEY, and OTHER. Publish a Flow before you send it; only draft Flows can be deleted.

200 sample — list flows

A draft with validation_errors can’t be published until the upload those errors refer to is fixed — fix the offending screens, re-post the assets, then re-publish.

Send a flow

Send a published Flow to a recipient as an interactive message. The recipient sees a button labelled flow_cta that opens the form; their submission returns as interactive.nfm_reply on the inbound webhook, with flow_token echoed back so you can correlate the reply to a session or journey.

200 sample — send-flow → receipt

The send answers with the same send envelope as every other send endpoint:
The recipient’s submission returns on the inbound webhook as interactive.nfm_reply, with the flow_token you sent echoed back so you can correlate the reply to a session or journey:
Every submission is also listed on GET /api/v1/whatsapp/flows/{flowId}/submissions, so a reply that arrived before your webhook consumer was ready is never lost. flow_cta is capped at 20 characters and body at 1024. flow_action is navigate (open at a fixed first screen) or data_exchange (drive screens dynamically from your Flow endpoint). Set mode to draft to preview an unpublished Flow against a test recipient.

Completion endpoint

Flows built on Meta’s dynamic data-exchange channel post each screen submission to a dedicated, encrypted endpoint mounted under its own base path: Meta signs each /endpoint request with X-Hub-Signature-256 and identifies the tenant with the X-Devotel-Org-Id header; the response is the AES-128-GCM-encrypted next-screen payload returned as text/plain, per Meta’s Flow Endpoint spec. Like the inbound webhook, it’s configured in Meta and called by Meta — you don’t call it yourself. It’s listed here for completeness.

Test-account analytics

This is a read-only aggregate for the dashboard’s test-account view — it has no provider or billing side-effect.

Cost optimization

Plan a batch of WhatsApp sends before they go out. The optimizer picks the cheapest valid Meta conversation category per recipient, sequences utility/authentication ahead of marketing to ride open conversation windows, and (when a budgetUsd cap is supplied) defers the sends that would exceed it — returning a projected-spend and savings report. This endpoint is pure planning: it never sends a message.

Inbound webhook

The platform also exposes the inbound Meta webhook at GET/POST /api/v1/whatsapp/webhook — Meta verifies it on subscription (GET, with the hub.challenge token) and posts message + status events to the POST handler. This endpoint is not callable by your application; it’s listed here for completeness.

Example — read current profile

See also