FlowKit

WhatsApp Flows and n8n: capturing structured data without leaving the conversation

Published 24 August 2026 · 5 min read

A WhatsApp message that links out to a Typeform or Google Forms page loses a share of respondents at the exact moment they leave the app to open a browser. A study by Soni et al., published in 2022 in Frontiers in Digital Health, compared a conversational agent against a regular online form for the same health-data collection task: 69.9% of participants preferred the conversational agent, with a markedly higher Net Promoter Score (24 versus 13) — a gap that largely comes down to staying inside one environment instead of switching apps (Soni et al., 2022, Google Scholar). Meta's WhatsApp Flows apply the same principle to business messaging: a native form that renders inside the conversation itself, with no outbound link. Making it dynamic, by wiring it to n8n, means dealing with a piece that gets far less attention than other WhatsApp integrations: the end-to-end encryption required on every exchange.

What a WhatsApp Flow actually is

A Flow is triggered by a call-to-action button embedded in an approved message template. On tap, WhatsApp opens a native screen — not a WebView, not a browser — built from a JSON declaring standard components: text fields, dropdowns, checkboxes, date pickers. The user moves from screen to screen without ever leaving the app, and the final screen sends the collected answers to your system.

Two modes exist:

  • Static Flow: every screen and its sequencing are fixed at design time. On final submission, WhatsApp delivers the data through a regular webhook message — the same mechanism used to receive a text message, already covered in our WhatsApp Business connection guide.
  • Dynamic Flow (data_exchange): every screen transition queries your own endpoint to decide what comes next — useful to prefill a field, validate an entry in real time, or only show an appointment slot if it's actually available. This mode is what requires encryption, and it's also what makes n8n genuinely useful here: without business logic to query at each screen, a plain static Flow is already enough.

End-to-end encryption: the real difficulty

As soon as a Flow uses data_exchange, Meta systematically encrypts exchanges with your endpoint, in both directions. Setting it up takes three steps:

  1. Generate a 2048-bit RSA key pair and upload the public key through the Graph API, tied to your WhatsApp Business number.
  2. Receive hybrid requests: every call to your endpoint carries an AES key encrypted with your RSA public key (RSA-OAEP), plus the actual payload encrypted with that AES key in AES-128-GCM mode, along with its initialization vector.
  3. Reply following the same scheme: decrypt the AES key with your private key, decrypt the payload, produce the business response, then re-encrypt it with the same AES key — flipping every bit of the received initialization vector, a precise requirement from Meta's specification.

n8n's native Crypto node, already detailed in our guide on hashing and signatures, can decrypt RSA content — which covers the step of recovering the AES key. But it doesn't offer the AES-GCM mode needed for the main payload. That means routing through a Code node using Node.js's native crypto module (crypto.privateDecrypt then crypto.createDecipheriv('aes-128-gcm', ...)), which in turn means allowing this built-in module via NODE_FUNCTION_ALLOW_BUILTIN=crypto on your self-hosted instance — the exact variable detailed in our guide on npm and built-in modules in the Code node.

Building the endpoint in n8n

The typical setup looks like this:

  1. Webhook — with Raw Body enabled, to receive the encrypted payload exactly as sent, without n8n trying to parse it as JSON.
  2. Code (decryption) — pulls the AES key and IV from the request body, decrypts the key with the RSA private key, then decrypts the payload with AES-128-GCM. The result is a regular JSON object containing the requested action (ping, INIT, or the current screen name) and the data already entered.
  3. Switch on the action type — an immediate branch for the health check (ping), which must trigger no business logic at all and directly return { "data": { "status": "active" } }.
  4. Business logic — for a lead-qualification Flow, for example, a call to your CRM or Supabase base to check availability, enrich a field, or compute the next screen to show, following the same principles as our guides on qualifying inbound leads with AI or scheduling appointments automatically.
  5. Code (re-encryption) — rebuilds the JSON response WhatsApp expects, encrypts it with the same AES key and the bit-flipped IV, and base64-encodes the result.
  6. Respond to Webhook — returns this raw base64 text, with Content-Type: text/plain. This is the most common trap: n8n often defaults to a JSON response, while Meta expects a pure string, with no { } wrapper at all.

Isolating steps 2 and 5 into a reusable sub-workflow avoids duplicating the encryption logic across every Flow workflow you build afterward — a practice already recommended in our guides on GDPR audit trails and AI workflow evaluations.

Checking that the request really comes from Meta

Like any publicly exposed webhook, every WhatsApp Flow request carries an X-Hub-Signature-256 header, an HMAC signature computed with your Meta app secret over the raw request body. Verifying it before even attempting RSA decryption avoids spending compute time on a forged request — the same reflex already covered for Stripe or GitHub webhooks.

Concrete use cases for a small business

  • Appointment booking: a three-screen Flow (desired service, time slot, contact details) that only shows genuinely available slots, queried in real time through data_exchange — the conversational equivalent of our guide on AI-driven appointment scheduling.
  • Lead qualification: a handful of structured questions before handing off to a sales rep, with a score computed on the fly by n8n instead of after the fact.
  • Post-purchase satisfaction survey: rating scales inside a Flow show a markedly higher completion rate than an external link sent by SMS, on the same principle covered in our analysis of AI-driven NPS responses.

Common pitfalls

  • Forgetting the health check: an endpoint that doesn't handle the ping action separately from the rest of the business logic can fail this check and get its Flow suspended, even if real submissions work fine.
  • Returning structured JSON instead of an encrypted string: Meta always expects a plain-text base64 string, never an object.
  • Timeouts on the n8n side: every screen transition expects a fast reply; business logic that's too slow (an unoptimized third-party API call) degrades the experience to the point of breaking the exchange, a risk already documented in our guide on HTTP Request retries and timeouts.
  • Testing only in development: Meta's Flow Builder offers a preview mode that bypasses the real endpoint; only validate end-to-end encryption with actual requests hitting your n8n webhook in production or staging.

Going further

A lead-qualification Flow is only as good as what happens after submission: triage, prioritization, response. That's exactly the role of the Inbox AI Pack (€79), which takes over once the structured data has been captured — classification, urgency scoring, daily digest. If your AI stack also covers compliance or a documentary assistant, the Complete FlowKit Bundle (€269) brings all three packs together on that same automated-processing logic.

FAQ

Frequently asked questions

Do I need to write code to use a WhatsApp Flow with n8n?

For a static Flow (fixed screens that end with a simple data submission), no: a regular n8n Webhook is enough to capture the submission. As soon as the Flow is dynamic (data_exchange, several screens that depend on previous answers), the endpoint must decrypt and re-encrypt every exchange, which requires a Code node using Node.js's native crypto module — a few dozen lines, but real code.

Can n8n's native Crypto node handle the whole encrypted exchange?

Partially. The Crypto node can decrypt RSA content, which covers the AES key Meta embeds in every request. But the main payload is encrypted with AES-128-GCM using that key, a mode the Crypto node doesn't offer natively: you need a Code node with crypto.createDecipheriv from Node's built-in module.

Why does my WhatsApp Flow endpoint return an error even though decryption works?

The most common cause is the response format: Meta expects a raw base64 string as text/plain, not a JSON object. A Respond to Webhook node left in its default JSON mode, or a Code node returning { status: 'ok' } instead of the expected encrypted text, breaks the exchange even when all the decryption logic is correct.

Does Meta check that my endpoint is working before publishing the Flow?

Yes, through a health check request ({ "action": "ping" }) sent at regular intervals, which the endpoint must answer with an encrypted payload containing { "data": { "status": "active" } }. A Flow whose endpoint fails to answer this ping correctly can be automatically suspended, even if real exchanges worked fine the day before.

Bundle FlowKit Complet

€269