Static vs Dynamic Flows
Every WhatsApp Flow is either static or dynamic.
| Static | Dynamic | |
|---|---|---|
| Screens | Fixed. Navigation happens on the phone. | The server can choose the next screen and fill it with data. |
| Live data | Only on the first screen, loaded when the flow is sent. | On any screen, loaded when the screen opens or the user submits. |
| Data from your backend | No | Yes, through a webhook data source |
| Server-side validation | No (on-device rules only) | Yes, every data_exchange submission is validated |
| Plans | Every plan with WhatsApp | Scale and higher |
| WhatsApp Coexistence numbers | Yes | No |
Start static. Most forms (callback requests, lead capture, surveys, newsletter preferences, profile updates) work as static flows. Choose dynamic when the options on a later screen depend on earlier answers or on your own systems: free appointment slots, stock levels, a price quote, a customer lookup.
What makes a flow dynamic
A flow is dynamic when its builder doc sets meta.kind to "dynamic". Two features only work in dynamic flows:
data_exchangeactions (in a static flow:static.data_exchangeerror).- Data bindings with
kind: "webhook"(in a static flow:static.binding_kinderror).
For the plan check, SendSeven counts a doc as dynamic if any of these is present: meta.kind: "dynamic", a data_exchange action, or a webhook binding. So a static doc that contains a data_exchange action is still refused on plans without dynamic flows.
You do not set up an endpoint yourself. When you push a dynamic flow, SendSeven registers its own managed data endpoint and the encryption keys with WhatsApp for you. See Managed endpoint and data sources.
Live data in static flows
A static flow can still show personal or workspace data on its entry screen. Bindings of kind static (a fixed value) or internal (a SendSeven resolver) on the first screen are resolved when the flow is sent and travel with the message.
{
"data_sources": [
{
"id": "profile",
"kind": "internal",
"screen_id": "PROFILE",
"resolver": "contact_profile",
"outputs": { "first_name": "first_name", "email": "email" }
}
]
}
Bindings on later screens of a static flow are reported as static.binding_not_entry. A data_exchange action in a static flow is reported as static.data_exchange.
Because the data is captured at send time, it is a snapshot: if the contact opens the form two days later, they see the values from the moment it was sent.
Plan gate
Dynamic flows need the Scale plan or higher. On a lower plan:
-
Creating, saving a version, cloning, pushing or publishing a dynamic flow returns:
{
"detail": {
"code": "feature_not_available",
"message": "Dynamic WhatsApp Flows need the Scale plan or higher.",
"feature": "whatsapp_flows_dynamic"
}
}with status
403. -
Validation reports
kind.dynamic_not_allowedfor each part that needs the endpoint. -
Creating a webhook data source returns
403("Webhook data sources need the Scale plan or higher.").
Static flows, including entry-screen internal bindings, work on every plan with WhatsApp.
During the free trial you can use the WhatsApp Flows builder and the AI builder. Dynamic flows still need the Scale plan or higher, so the trial returns the same 403 for them.
If a workspace is downgraded while a dynamic flow is live, the flow stays on WhatsApp but SendSeven answers its data requests with a friendly "not available" message on the screen instead of loading data.
WhatsApp Coexistence numbers
Numbers connected in Coexistence mode (WhatsApp Business app and API on the same number) can send and receive static flows only. GET /whatsapp-flows/publish-targets tells you per channel:
curl https://api.sendseven.com/api/v1/whatsapp-flows/publish-targets \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00"
{
"items": [
{
"channel_id": "8c1d0f5e-…",
"channel_name": "Support DE",
"phone_number": "+49301234567",
"waba_id": "102938475610293",
"waba_name": "Example GmbH",
"is_active": true,
"is_coexistence": false,
"supports_dynamic": true
}
]
}
supports_dynamic is true only when your plan includes dynamic flows and the number is not a Coexistence number. Only publish dynamic flows to channels where it is true. Pushing or publishing a dynamic flow to a Coexistence number is refused with 409 dynamic_not_supported_on_coexistence.