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.
Send a template message
The headline send operation most flows start with — a pre-approved template via the unified Messaging API. Templates are required whenever the recipient’s 24-hour freeform window is closed, which is the case for the first message of any conversation.data.id is the message id you correlate with message.sent and status webhooks. Template variables can be passed as Meta-native template.components or as the flat positional template_params map (e.g. { "1": "Acme" }) — the send rejects with 422 before it reaches Meta when a parameter count mismatches.
Using the SDKs
client.request() escape hatch, and Go, Ruby, and PHP use the plain-HTTP-client samples above. See the SDK quickstart.
Connections
Each Orbit organization can attach one or more WABA phone numbers. Connections are managed via Meta’s Embedded Signup; theconnect endpoint exchanges the resulting code for a long-lived token.
200 sample — list connections
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": {...}}.
Exchange the Embedded Signup code
POST /connect runs once per Meta Embedded Signup session — it exchanges the one-time sign-up code for the long-lived connection. The WABA setup guide walks the signup flow. If the Meta login owns more than one (WABA, phone number) pair, the first call answers with the discovered options; re-POST the same code together with the chosen waba_id and phone_number_id to finalize.
Business profile
The about line, address, vertical, websites, and profile photo that appear in the customer’s WhatsApp client.200 sample — read the business profile
{"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. List the products on your catalog:PUT /products/{productId} updates the same fields and DELETE /products/{productId} removes it):
/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
List the call permissions a contact has granted — paginate with
cursor (the call answers pagination.cursor when more rows remain):
from_phone_number_id is the calling-enabled connection from the list above (enable it first via the provisioning endpoints):
{"data": {"ok": true, "meta_call_id": "...", "wa_call_log_id": "..."}, "meta": {...}}; call lifecycle events (call.started, call.ended) ride the same webhook as message events. Reads for the dashboard follow the same auth: GET /calling/permissions and the two call mutations are shown above; the paginated call log and the 30-day KPI aggregate are listed under Dashboard surfaces below.
Dashboard surfaces
Block list
List the users currently blocked on your WABA (
after pages forward, limit caps at 100):
POST /unblock-users to reverse it:
{"data": {"ok": true}, "meta": {...}} once Meta confirms the change.
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):
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:
button_reply.id round-trips the id you sent on the button, unmodified.
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.
Marketing template sends
POST /marketing-messages/send routes a MARKETING-category template through Meta’s Marketing Messages API (MM Lite) instead of the standard send path, so Meta applies send-time and creative optimization. Required fields: to, template_name, language_code; optional components (template variables), tracking_id (echoed on status webhooks for campaign correlation), and phone_number_id (multi-WABA selector).
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 withPOST /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.
Create a draft Flow, then upload its screen definition with POST /flows/{flowId}/assets and publish:
200 sample — list flows
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 labelledflow_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:interactive.nfm_reply, with the flow_token you sent echoed back so you can correlate the reply to a session or journey:
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 abudgetUsd 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 atGET/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.
Verify WhatsApp events on your server
The events those sends produce (message status, inbound replies,button_reply, nfm_reply, order) arrive at your own webhook endpoint signed with your webhook secret. Verify the signature header before trusting the body, and dedupe on the webhook id so a retried delivery never double-processes — the full verifier and retry semantics are in Build your first webhook receiver; the WhatsApp-specific receiver is:
200 quickly and queue the work; the same delivery semantics and retry schedule as every other Orbit webhook apply. event.channel === "whatsapp" separates WhatsApp traffic from your other channels on a shared endpoint.
Quick check — read your current profile
The fastest smoke test for a fresh API key is the business-profile read — run theGET /whatsapp/business-profile sample from the Business profile section in any of the six languages; a 200 with your org’s about line confirms the key, the tenant mapping, and the WABA connection in one round trip.
See also
- Messaging API → Send WhatsApp — outbound message sending
- Channels → WhatsApp guide — concepts, template approval, pricing
- API recipes — cross-channel task cookbook (voice, numbers, OTP, loyalty, CDP). The samples on this page stay inside the WhatsApp Business surface and show the exact manager-op request + response; the recipes map those calls into multi-channel, multi-step tasks
- WhatsApp content policy