Use Tab, then Enter to open a result.
Building a basic WhatsApp Flow is a great first step. You create a screen, collect some data, and receive a success message. Most developers start there. Problems arise when you need that data to affect someone else. Imagine a team lunch order where five people need to add items to a single cart. Or a manager who needs to approve a request initiated by an employee inside a Flow.
Standard WhatsApp Flows are sandboxed. The state exists only for the person interacting with the screen. To build collaborative experiences, you must move the 'brain' of your operation to a centralized server. This approach uses webhooks to manage a shared state across multiple user sessions.
The Architecture of Shared State
To enable multi-user logic, your infrastructure requires three components working in sync.
- The WhatsApp Flow: This is the front-end. It collects user input and sends it to your endpoint.
- A Centralized Webhook Server: This acts as the orchestrator. It receives data from various users and decides what happens next.
- A Persistent Database: This stores the collaborative state. It tracks who is doing what and the current progress of the shared task.
When User A performs an action in a Flow, your webhook updates the database. When User B opens their Flow, your server fetches the current state from that database and populates User B's screen with the updated information.
Prerequisites for Multi-User Workflows
Before you write your first line of logic, ensure your environment is ready.
- A Meta Developer App with WhatsApp Business API access.
- An HTTPS-enabled server for webhooks (Node.js, Python, or Go work well).
- A database with fast read/write capabilities like Redis for temporary sessions or PostgreSQL for permanent data.
- Familiarity with JSON Web Encryption (JWE) for Flow payload security.
If you prefer a simpler setup for testing, WASenderApi offers a way to handle webhooks and messaging via standard WhatsApp accounts. While it is an unofficial alternative, it provides a lower barrier to entry for developers who want to experiment with multi-user logic without the heavy configuration requirements of the official Business API.
Step 1: Designing the Collaborative Database Schema
Multi-user logic fails without a unique identifier to tie users together. In a team environment, this is often a group_id or a session_id.
Your database needs to track these fields at a minimum:
| Field Name | Data Type | Purpose |
|---|---|---|
session_id |
String (UUID) | Links multiple users to the same collaborative task. |
initiator_id |
String | The WhatsApp ID of the person who started the flow. |
participants |
JSON/Array | A list of WhatsApp IDs allowed to interact with the state. |
current_data |
JSON | The actual content (e.g., items in a cart, vote counts). |
status |
String | Tracks if the flow is 'open', 'pending_approval', or 'completed'. |
Step 2: Initiating the Multi-User Session
Everything starts when User A triggers the Flow. Your backend must generate a unique flow_token. This token is your key to identifying the session when the webhook receives a payload later.
Store the relationship between the flow_token and your session_id in your database immediately.
// Example: Storing the session mapping in Node.js
const startSession = async (initiatorId, groupId) => {
const flowToken = generateSecureToken();
const sessionId = groupId; // Use your internal group reference
await db.sessions.create({
data: {
token: flowToken,
sessionId: sessionId,
initiator: initiatorId,
status: 'active',
currentData: {}
}
});
return flowToken;
};
Step 3: Handling Collaborative Webhook Payloads
When a user submits a screen in the Flow, WhatsApp sends a POST request to your webhook. The payload contains the flow_token.
Your server performs these tasks:
- Decrypt the JWE payload.
- Lookup the
session_idusing theflow_token. - Update the
current_datain your database based on the user's input. - Determine if other users need a notification.
{
"action": "data_exchange",
"flow_token": "session_abc_123",
"data": {
"item_added": "Coffee",
"quantity": 2,
"user_id": "123456789"
}
}
Step 4: Syncing State Across Different Users
This is the most difficult part. WhatsApp Flows do not have a 'real-time socket' to push UI updates to a screen that is already open on another user's phone. To solve this, you have two options.
Option A: The Pull Model (On-Open Sync)
When User B opens the Flow, the first action should be a ping to your server. Your server looks up the session_id and returns the latest data. This ensures User B always sees the current state at the moment they start their interaction.
Option B: The Push Model (Template Notifications)
When User A finishes their part of the Flow, your server sends a WhatsApp Template message to User B. This message contains a button to open the same Flow. You pass the same session_id (or a linked flow_token) to User B so they join the existing state instead of starting a new one.
Practical Example: Multi-User Approval Workflow
Let's build a scenario where an employee requests a vacation day and a manager approves it within the same Flow logic.
- Employee Action: The employee opens the Flow, selects dates, and hits 'Submit'.
- Webhook Logic: The server saves the request to the database with a status of
pending_manager. - Manager Notification: The server sends a WhatsApp message to the manager's phone with a 'Review Request' button.
- Manager Action: The manager clicks the button. The Flow opens and performs a
data_exchange. Your server sees the manager's ID and fetches the employee's specific request data from the database. - Resolution: The manager selects 'Approve'. The webhook updates the database to
approvedand sends a final confirmation message to the employee.
Managing Concurrency and Race Conditions
In multi-user environments, two people might try to update the same state at the same time. This happens frequently in inventory or booking systems.
To prevent data corruption, implement optimistic locking. Before updating the database, check if the data changed since the user last fetched it.
- Include a
versionnumber in your Flow state. - When the user submits data, send the
versionnumber back to the server. - If the database
versionis higher than the submittedversion, reject the update and ask the user to refresh the Flow.
// Pseudocode for version checking
const updateSharedState = async (sessionId, submittedVersion, newData) => {
const currentRecord = await db.sessions.findUnique({ where: { id: sessionId } });
if (currentRecord.version !== submittedVersion) {
throw new Error("State has changed. Please refresh.");
}
return await db.sessions.update({
where: { id: sessionId },
data: {
...newData,
version: currentRecord.version + 1
}
});
};
Troubleshooting Common State Issues
Building collaborative logic introduces specific errors that single-user flows never encounter.
Token Expiration
flow_token values have a limited lifespan. If a collaborative process takes days (like a multi-stage mortgage approval), do not rely on the same token. Instead, store your own internal permanent_session_id and generate new tokens for each individual interaction.
Payload Size Limits
WhatsApp Flow payloads have a 64KB limit. If you have 50 users adding items to a list, the JSON object grows quickly. Avoid sending the entire history back and forth. Only send the specific change (the delta) to your webhook. Let your server handle the heavy lifting of merging that change into the master record.
User Identity Mismatches
Always verify the sender_id provided by the WhatsApp webhook against your allowed participants list. Do not trust the data inside the Flow payload alone. Use the metadata provided by the WhatsApp API to ensure the person clicking 'Approve' is the person authorized to do so.
Frequently Asked Questions
Do I need a separate Flow for each user?
No. You use the same Flow definition for everyone. Your backend logic determines which screen to show based on the user's role or the current status of the session_id in your database.
What happens if two users submit at the exact same millisecond?
Use a database that supports atomic operations or transactions. If you use Redis, the WATCH command helps manage these collisions. If you use SQL, use a TRANSACTION block to ensure only one write succeeds.
Is there a limit to how many users can join a session? Technically, no. Your server and database performance are the only limits. However, the WhatsApp API has rate limits for sending the outbound messages needed to notify participants. Monitor your throughput if you plan to have hundreds of users in a single session.
Can I use this for real-time chat inside a Flow? Flows are not designed for high-frequency updates. Each interaction requires a round-trip to your server. For real-time chat, use the standard WhatsApp messaging interface. Use Flows for structured data collection and decision-making.
Final Implementation Steps
To move forward, focus on the handoff between users. Build a small prototype where User A sends a message and User B sees that message inside a Flow. Once you master the database lookup via flow_token, you are able to scale that logic to any number of participants.
Next, investigate how to use dynamic routing within your Flow screens. Use the server's response to the data_exchange action to tell the Flow which screen to display. This enables you to show a 'Submission' screen to employees and an 'Approval' screen to managers using the exact same Flow ID. This reduces maintenance and keeps your logic centralized in one place.