Skip to main content
A static flow defines all of its screens up front in the Flow JSON. A dynamic flow builds screens at runtime: when the customer opens the flow or submits a screen, WhatsApp calls an HTTPS endpoint you host, and your endpoint answers with the next screen and its data. Use it when screen content depends on live information — available time slots, account details, product lists. This page covers the contract your endpoint implements. For sending flows through the API, see Send WhatsApp Flows.
WhatsApp calls your endpoint directly — the traffic does not pass through Connectly. You configure the endpoint URL and its encryption key on the flow in WhatsApp Manager. Meta’s reference documentation, including sample endpoint implementations, is at Implementing your Flow endpoint.

Request lifecycle

Your endpoint receives one POST per event: A completed flow (a screen whose action is complete) does not call your endpoint. The customer’s answers are delivered as a flow response message — see Webhooks.

Encryption

Every request body carries three base64 fields:
To decrypt the request:
  1. Decrypt encrypted_aes_key with your RSA private key, using OAEP padding with SHA-256. The result is a 128-bit AES key.
  2. Decrypt encrypted_flow_data with AES-128-GCM using that key and initial_vector. The last 16 bytes of the ciphertext are the GCM authentication tag.
  3. The plaintext is the JSON request.
To encrypt your response:
  1. Flip every byte of the request’s initial_vector (XOR each byte with 0xFF).
  2. Encrypt your response JSON with AES-128-GCM using the same AES key from the request and the flipped IV. Append the 16-byte authentication tag to the ciphertext.
  3. Return the result base64-encoded as the raw response body — plain text, not JSON — with HTTP status 200.
If you cannot decrypt a request (for example, after rotating keys), return HTTP 421. WhatsApp then re-fetches your public key and retries.
The private key stays on your server. Its public key is registered on your WhatsApp phone number — one key pair per phone number. If you generate a new key pair, the public key must be registered again before your endpoint can decrypt traffic.

Requests and responses

The decrypted request:
Your decrypted response — the next screen and the data it needs:
Every screen your endpoint returns must exist in the published Flow JSON. Returning a screen name the flow does not contain is the most common endpoint bug: the customer sees “Something went wrong” when the flow opens, while your logs show successful 200 responses. Keep your Flow JSON and endpoint in sync — when you rename or add screens, update both.

Dynamic screen data

List components in the Flow JSON (RadioButtonsGroup, CheckboxGroup, Dropdown) bind to data your endpoint returns:
The number of options is the length of the array you return — 2 items render 2 options, 5 items render 5. Each item needs a string id and a title; optional fields include description and enabled. Limits: 20 items for radio buttons and checkboxes, 200 for a dropdown. To personalize from the very first screen, use the flowToken you set when sending the flow: it is echoed to your endpoint on every request, including INIT, so it can carry a customer reference your endpoint resolves before building the first screen.

Example endpoint

A complete Node.js implementation of the contract, with the crypto and a two-screen booking handler. The same structure ports directly to other languages.

Production checklist

  • Respond fast. WhatsApp allows only a few seconds per request. Cache slow upstream calls; keep the endpoint close to your data.
  • Use a stable HTTPS URL. Tunnel tools such as ngrok are fine for development, but free tunnels change their URL on every restart — and the flow keeps calling the old one. Host production endpoints on a fixed domain.
  • Log every exchange. Log the incoming action and screen and the screen you return. Most flow issues are diagnosed from exactly these two lines.
  • Return 421 on decryption failures so WhatsApp refreshes your public key instead of retrying blindly.

Troubleshooting