CodePrism logoCodePrism Inc.
Back to Case Studies
Messaging & Automation

Building a Native WhatsApp Forms Engine on PrismWA

A visual builder and runtime for Meta's WhatsApp Flows - letting teams design multi-screen forms, power them with live data, and collect structured responses without a single Meta dashboard visit.

Platform

Web & WhatsApp

Duration

6 weeks

14Drag-and-drop field types
3Ways to power a screen with live data
0Duplicate submissions, by design

The Challenge

Teams running WhatsApp-based surveys, lead capture, or bookings had two bad options: build a web form and paste a link into the chat (which breaks the point of being "in WhatsApp" and loses a chunk of respondents at the tap-out), or hand-author raw WhatsApp Flow JSON and manage it through Meta's Flow Builder and Graph API directly - a process with no visual preview, a strict component schema, and a public-key encryption protocol that has to be implemented correctly before Meta will even let you publish.

  • Sending a plain link instead of a native form loses respondents at the app-switch
  • Meta's raw Flow JSON format has no visual editor and fails validation on small mistakes
  • Every dynamic screen (a dropdown fed by an API, a personalized message) requires implementing Meta's Data Exchange encryption protocol from scratch
  • Republishing a flow for a trivial config change re-triggers Meta's full validation and review pipeline unless you specifically avoid it
  • Submitted responses arrive back as a WhatsApp webhook payload, not structured data - someone still has to wire that into a CRM or spreadsheet

Project Goals

Give workspace admins a drag-and-drop builder for native WhatsApp forms - no JSON required
Implement Meta's Data Exchange protocol (RSA + AES-GCM handshake) so screens can carry live data
Support three ways to power a dynamic screen: static options, an external API, or a custom function
Publish flows to Meta with a smart diff, so unchanged flows don't get needlessly resent for review
Capture every submission automatically and forward it to an external system with field mapping

How We Built It

01

Visual Flow Builder with Live Phone Preview

Built a screen-by-screen editor with a drag-and-drop component palette covering 14 field types - headings, text inputs, dropdowns, radio and checkbox groups, date pickers, opt-ins, photo/document pickers, plus If/Switch branching and a footer action - alongside a phone-frame preview that renders the screen exactly as it will appear in WhatsApp as it's being built.

Key DecisionA real component palette mapped 1:1 to Meta's Flow JSON schema, instead of a generic form builder translated after the fact
ResultAdmins design and preview multi-screen forms entirely inside PrismWA, with no hand-written JSON
02

Meta's Data Exchange Encryption Handshake

Every WhatsApp Flow with dynamic screens needs a public/private RSA key pair: PrismWA generates a 2048-bit RSA key pair per flow, uploads the public key to Meta, and keeps the private key server-side. When a user's phone requests a screen, Meta encrypts the request with a fresh AES-128-GCM key wrapped in our RSA public key; PrismWA unwraps it, decrypts the payload, computes the response, and re-encrypts it with the same AES key under a flipped initialization vector, exactly as Meta's protocol requires.

Key DecisionImplement the full crypto handshake (RSA-OAEP unwrap → AES-128-GCM decrypt → IV-flip re-encrypt) rather than relying on an unmanaged third-party library
ResultEvery dynamic screen - dropdowns, conditional text, personalized fields - round-trips safely through Meta's encrypted channel
03

Three Ways to Power a Dynamic Screen

A screen's live data can come from three sources, configured per-screen with no code: a static list, an external API call (with input field mapping and a JMESPath expression to reshape the response), or a sandboxed custom JavaScript function with access to the user's phone number, form data, and encrypted secrets. Functions run through a safe fetch with SSRF protection (blocking private IPs and cloud metadata endpoints) and a hard timeout.

Key DecisionJMESPath for declarative response reshaping, with an escape hatch to custom functions for anything JMESPath can't express
ResultA dropdown can pull live inventory from an ERP, or a screen can greet a user by name, without a new flow version
04

Smart Publish, Submission Capture, and Forwarding

Publishing hashes the transformed flow JSON and skips the Meta round-trip entirely if nothing actually changed (e.g., only a data-source URL was edited) - so config tweaks don't re-trigger Meta's validation and asset upload pipeline unless the form itself changed. Completed forms arrive as a WhatsApp webhook (nfm_reply), get de-duplicated by flow token, stored as structured submissions (with any uploaded photos/documents downloaded automatically), and optionally forwarded to an external API with configurable field-name mapping and per-submission resend.

Key DecisionHash-based change detection before touching Meta's API, plus flow-token dedup on the inbound webhook
ResultZero duplicate submissions, fewer unnecessary Meta republishes, and structured data ready for a CRM without custom glue code
05

Challenge: Getting the Encryption Handshake Byte-Exact

Problem: Meta's Data Exchange protocol fails silently on the device ("Something went wrong") if the AES-GCM auth tag handling or IV-flip is even slightly off, with almost no error detail returned.

ResultSolution: Isolated the crypto steps (RSA-OAEP unwrap, GCM decrypt with the auth tag, GCM re-encrypt with a bitwise-flipped IV) into a single well-tested service, validated against Meta's health-check ping action before shipping real screens.
06

Challenge: Routing Between Screens When routing_model Goes Missing

Problem: Meta's publish step transforms our stored flow JSON for its own copy without writing the transformed routing_model back to our database, so the stored flow often has an empty routing model - which broke "next screen" navigation during data exchange.

ResultSolution: Added a fallback that walks the screens array in order when the routing model has no entry for the current screen, so navigation keeps working regardless of what Meta did or didn't persist.
07

Challenge: Running User-Authored Functions Safely

Problem: Letting admins write custom JavaScript to power a screen means running arbitrary code inside the same process as the API - a real sandbox escape risk if function authorship were ever opened beyond trusted roles.

ResultSolution: Scoped functions to an AsyncFunction with a controlled ctx (secrets, form data, a safe fetch with SSRF blocking and a timeout), restricted authorship to OWNER/ADMIN roles, documented the risk until this needs a real VM sandbox.

The Outcome

PrismWA now ships a complete native WhatsApp Forms feature: a visual builder, Meta's encrypted Data Exchange handshake, three ways to power live screens, and automatic, de-duplicated submission capture - with no hand-written Flow JSON and no manual data wiring.

Impact & Results

14Drag-and-drop field types available in the builder (text, choice, date, media, and branching components)
3Independent ways to power a dynamic screen (static, external API + JMESPath, custom function)
2048-bitRSA key size generated per flow for Meta's Data Exchange encryption
0Duplicate submissions, enforced via flow-token dedup on the inbound webhook

Key Takeaways

Meta's Data Exchange protocol is well-documented but unforgiving - get the encryption handshake exactly right or debug blind

Hashing the transformed output before republishing avoids needless Meta API calls and keeps config tweaks fast

Giving admins a custom-function escape hatch (not just static config) covers the long tail of "one more API" requests without new engineering work each time

Server-authored code execution is only safe with an explicit trust boundary - restricting it to trusted roles is a stopgap, not a permanent answer

Conclusion & Impact

"This project showed that Meta's WhatsApp Flows platform is genuinely capable - multi-screen native forms with conditional logic, live data, and media capture - but the protocol underneath (encrypted data exchange, strict JSON schema, opaque validation errors) is unforgiving to build against directly. Wrapping it in a visual builder and a runtime that owns the crypto handshake turned a protocol only a backend engineer could touch into something any workspace admin can design."

Technology Stack

NestJSNext.js (App Router)Meta WhatsApp Flows / Graph APIPostgreSQLPrismaRSA-OAEP + AES-128-GCM (Node crypto)JMESPathBullMQRedisTypeScript
Background

Ready to achieve similar results?

Let our dedicated engineers bring your vision to life with cutting-edge technology and unparalleled expertise.