Send a Template Message
WhatsApp requires pre-approved templates for business-initiated conversations.Send a Session Message
Once a user messages you, a 24-hour session window opens for free-form replies. Use the window-status check to confirm the window is still open before sending. Sending a template does not open the window. Only a customer reply re-opens it — Meta’s own platform rule. Once the recipient replies, the composer’s window status flips back to free-form without a page reload, and free-form sends will be accepted again. For how the WhatsApp session compares with Meta DM messaging windows and the no-window channels, see Messaging windows and off-window sends.Check the 24-Hour Window
Before composing a free-form (session) message, call the window-status endpoint to confirm the recipient is still inside Meta’s 24-hour re-engagement window. The send pipeline enforces the same check, but this pre-flight lets you gate the UI (force template-only when the window has closed) and avoid a wasted send attempt.to(required) — the contact’s E.164 number.from(optional) — the WABA number that will be the sender. When omitted, the check spans any of your WABA numbers; when supplied it is scoped to that sender pair (matching the send-time gate).
Response
reason is one of:
When the window is closed,
within_window is false and you must fall back to an approved template message.
Send a Broadcast
Fan a single approved template out to up to 256 recipients in one operation (Meta’s documented broadcast-list cap). Each recipient receives a normal 1:1 conversation — there is no shared thread, so per-recipient STOP / opt-out handling is preserved. The endpoint is persist-then-attempt: every recipient is pre-inserted as apending row in one transaction before the per-recipient send pipeline runs, so a pre-create rejection (template not approved, parameter-count mismatch, 24-hour-window block, fraud guard, quota, sender validation) flips that row to failed rather than throwing without persisting a record.
recipients(required) — 1–256 entries, each with ato(E.164) and optional per-rowtemplate_params/metadata. Per-rowtemplate_paramsoverride the batch-level sharedtemplate_params. Duplicate numbers in one request are rejected (422).template_name(required) — an approved WhatsApp template.template_language,from,template_params,scheduled_at,webhook_url,metadata(optional) — shared across the batch. Withscheduled_atset, every recipient lands asscheduledfor the worker queue.
Response
Returns a per-recipient result array plus a summary. Inspectsummary.failed and each results[].status — the HTTP status code signals whether to look at the body.
Broadcasts are rate-limited to 30 requests/minute per tenant. Larger or recurring sends belong in the campaigns module.
The Visual Flow Builder
Build a Flow in the dashboard without writing JSON: Messages → WhatsApp → Flows opens a canvas editor where each screen is a node. Drag screens from the component palette — text inputs, dropdowns, radio groups, checkboxes, date pickers, photo pickers, opt-in consent, rich text, images, embedded links, navigation lists — and connect a non-terminal screen’s Continue button to the next screen. Selecting a screen opens a drawer to edit its copy, options, and validation. A View JSON toggle exposes the raw Meta Flow JSON for power users; edits there sync back to the canvas on commit, with parse errors guarded. Export a Flow as JSON for version control, or import a Meta Flow JSON document — the builder preserves every screen it recognises and falls back to a text input for a shape it does not, so an imported Flow is still editable and re-saveable. Start blank, from one of the built-in templates, or from the AI generator’s draft (the AI Flow generator is covered in Getting started with WhatsApp). Once the Flow is published, pair the funnel view with the submissions list below: the funnel shows where customers drop off, the list shows what each completer answered.Flow Submissions Write to the Contact Profile
When a customer completes a Meta Flow sent over WhatsApp — a lead-capture form, a survey, a self-service questionnaire — the answers they submitted are written onto their contact profile as custom-field values, in addition to the conversation log. Segments and automations built on custom fields see the contact right after they submit. Define a custom field under Settings → Custom Fields with a key that matches the Flow screen’s field id (snake_case, e.g.email, company_size) and the answer lands there on completion. The write-back is additive lead capture, not a sync:
- Blank answers (
nullor empty strings) are ignored — a returning customer re-running a Flow with an optional field skipped never wipes the value they set on an earlier submission. - A Flow field id with no matching custom-field definition is skipped, never invented as a new field.
- One invalid answer (wrong type, out of range, disallowed option) is skipped without blocking the rest of the submission.
Browse Individual Flow Submissions
The funnel view tells you where customers drop off; the submissions list tells you what the completers actually answered. Every completed submission gets its own row, available over the API:YOUR_FLOW_ID accepts either the id in the flow’s dashboard URL or the Meta flow id. Query parameters: since / until (ISO timestamps — the default window is the trailing 90 days), and limit (up to 200) / offset for pagination.
Each row carries:
The landed_in_cdp Marker and the CDP Event
In addition to the custom-field write-back, every completed submission lands on the contact’s CDP profile as a whatsapp_flow_submitted event. Segments, computed traits, and event-triggered journeys built on CDP events (see The CDP event model) can react to a Flow completion the same way they react to any other behavioral event.
landed_in_cdp on a submissions row is true when that event exists for the submission — use it to confirm a Flow the journeys depend on is really feeding them. It can be false for submissions recorded before this wiring shipped; those rows still carry all their answers. Retried WhatsApp delivery of the same submission collapses onto one event, so the count you see matches the number of actual completions.
Both landing paths coexist deliberately: the write-back above keeps the latest answers on the contact’s custom fields (additive — blanks never wipe), while the CDP event preserves every submission verbatim in the event stream. Point real-time triggers at the event; use the custom fields when you need the current value.
Features
- Template messages — pre-approved message templates for outbound notifications
- Session messaging — free-form replies within the 24-hour conversation window, with a pre-flight window-status check
- Broadcast lists — fan one approved template out to up to 256 recipients with per-recipient results
- Rich media — images, videos, documents, audio, stickers, and location sharing
- Interactive messages — buttons, list pickers, quick replies, plus tap-to-share location-request and structured delivery-address prompts
- Read receipts — know when messages are delivered and read
- Catalog & product messages — share product listings directly in chat
- Flows — send Meta Flows and capture completed submissions onto the contact’s custom fields (see Flow Submissions Write to the Contact Profile)
Media Support
Send images, video, documents, audio, and stickers over WhatsApp. Each media type has its own size limit, set and enforced by WhatsApp (Meta) at the Graph API — there is no single blanket ceiling. Orbit forwards your media to WhatsApp, so keep each file within the limit for its type or WhatsApp rejects the send.
Limits are per type, not shared: a 90 MB PDF is accepted as a document but rejected if the same file is sent as an image, and a sticker must stay under 100 KB. Check each file against the limit for its media type before sending.
Platform WABA credentials (operators)
Tenants connect their own WhatsApp Business Account through the dashboard Embedded Signup flow, and Orbit uses that tenant’s stored credentials at send time. The variables below configure Orbit’s own platform-owned WABA — used today only for operator-side platform operations (platform-initiated template management and WhatsApp Calling registration). The old shared fallback send path for unverified organizations was removed on 2026-10-08: there is no longer any send that rides the platform WABA on a tenant’s behalf. Set all three in Secret Manager (or.env for local dev). They are optional at boot: when DEVOTEL_WHATSAPP_ACCESS_TOKEN is set, messaging-bootstrap.ts registers one platform-wide WhatsApp provider; when it is unset, only per-tenant connections resolve at send time.
Inbound webhook HMAC for WhatsApp still uses the shared
DEVOTEL_META_APP_SECRET / DEVOTEL_META_VERIFY_TOKEN regardless of whether the platform credentials are set.
Dashboard Embedded Signup (build-time client config)
The dashboard’s WhatsApp Embedded Signup card and the Meta Ads channel card load Meta’s JS SDK in the browser, so they need a Meta App ID and an Embedded Signup configuration ID available on the client. TwoNEXT_PUBLIC_* variables carry those values. Because they are NEXT_PUBLIC_*, they are baked into the dashboard when it is built — changing them requires rebuilding the dashboard, not just updating a server environment variable.
Both are optional. Leave them unset for standard production deployments; the defaults connect tenants to Orbit’s production Meta app.
Override both when you build the dashboard against a non-production Meta app — a staging / preview environment pointed at a test Meta app and Embedded Signup config, or a white-label deployment that runs its own Meta app rather than Orbit’s. Provide both as build-time variables when you build the dashboard, and set the matching server-side
DEVOTEL_META_APP_ID so the runtime and build-time values agree.
Template Management
Manage templates through the Orbit dashboard under Channels > WhatsApp > Templates, or via the API:POST to /whatsapp/templates (Node: orbit.whatsapp.templates.create(...), then orbit.whatsapp.templates.submitForReview(id)).
To measure how a template performs once campaigns start sending it, read its cross-campaign rollup — sends, deliveries, opens, and clicks consolidated across every campaign that used it — in the template analytics guide.
Templates go through Meta’s approval process (typically 1–24 hours).
Your WABA is required to send
The shared Devotel test account — a shared WABA that used to carry real sends to a verified phone number before your own WABA was approved — was retired on 2026-10-08. Your own WhatsApp Business Account, connected through Embedded Signup (see the WABA setup guide), is now the only send path on this channel. What you meet today when no WABA is connected:- Sends —
POST /api/v1/whatsapp/send(and every other WhatsApp send entry point) refuses up front with422 CHANNEL_NOT_CONFIGURED, before a message row is written. Connect your WABA and the same call passes; nothing about your send code changes. - Demo-account endpoints — the retired OTP / verification endpoints (
sendOtp,verifyOtp,changeNumber, and the test-account send admission) answer410 GONEwith a connect-your-own message. There is no admin override orallowOverwritebypass; the retirement is absolute. - Status reads stay readable —
GET /api/v1/whatsapp/get-statuscontinues to render a coherent state for a previously verified organization:retired: trueandverified: false, so legacy dashboards show “retired, connect your own account” rather than erroring.
Troubleshooting
Jump straight to the symptom you are seeing; each page below is the drill-down for it.- Send fails immediately — a send rejected before it leaves Orbit or refused by Meta. Work the template gates in WhatsApp template issues, or the
WHATSAPP_ACCOUNT_LOCKEDrecovery flow in WhatsApp connection issues. - Session vs template window — a free-form reply refused while a template send works. Re-check the window state in Session window expired, and review the rules in the 24-hour window guide (the window-status check is the pre-flight).
- Quality and tier — sends rejected at the per-WABA tier ceiling, or quality posture degrading. See the Messaging Tier entry in the glossary and the template gate drill-down in WhatsApp template issues.
- Migration between providers — moving WhatsApp traffic without losing the WABA or its approved templates. Follow WhatsApp migration.
- WABA billing — conversation pricing, WABA-level charges, or a billed send you did not expect. Work WhatsApp billing issues.