Use Tab, then Enter to open a result.
Processing payments within a chat interface reduces the steps between intent and acquisition. When users leave WhatsApp to open a mobile browser, friction increases. Session timeouts, slow page loads, and authentication prompts lead to abandoned carts. WhatsApp Flows solves this by keeping the user inside the application while they select products and confirm details. Connecting this interface to Stripe requires a secure, event-driven architecture.
The Architecture of Secure In-Chat Checkout
Automated order processing relies on a three-way handshake between the WhatsApp Cloud API, your backend server, and the Stripe API. The flow begins when a user interacts with a Flow in their chat. Your server receives the data, initiates a Stripe checkout session, and returns a payment link. Once the user pays, Stripe sends a webhook to your server to confirm the transaction. Your server then triggers a WhatsApp message to confirm the order completion.
This structure minimizes data exposure. Sensitive credit card information remains within Stripe. Your server only handles order IDs and status updates.
Prerequisites for Integration
Before writing code, ensure the following assets are ready:
- A Meta Business Account with WhatsApp Cloud API access.
- A Stripe account with API keys (Secret and Publishable).
- A publicly accessible HTTPS endpoint (for webhooks).
- An RSA key pair for WhatsApp Flow encryption (Public key uploaded to Meta).
- Node.js or Python environment for backend logic.
Step 1: Defining the WhatsApp Flow Schema
The Flow schema defines the UI components. For order processing, the schema must collect the user's selection and address details. The data_exchange action sends this information to your server.
{
"version": "3.1",
"screens": [
{
"id": "ORDER_ENTRY",
"title": "Complete Your Order",
"terminal": false,
"data": {
"products": {
"type": "array",
"items": {
"id": "string",
"name": "string",
"price": "number"
}
}
},
"layout": {
"children": [
{
"type": "Dropdown",
"label": "Select Item",
"name": "selected_item",
"data-source": "products"
},
{
"type": "Footer",
"label": "Continue to Payment",
"on-click-action": {
"name": "data_exchange",
"payload": {
"item_id": "${form.selected_item}"
}
}
}
]
}
}
]
}
Step 2: Handling the WhatsApp Flow Webhook
Meta encrypts Flow payloads using your RSA public key. Your server must decrypt the request, process the logic, and return an encrypted response. Failure to follow the specific encryption standard (AES-GCM) results in a Flow error for the user.
const crypto = require('crypto');
function decryptRequest(payload, privateKey) {
const { encrypted_flow_data, encrypted_aes_key, initial_vector } = payload;
// Decrypt the AES key using your RSA Private Key
const aesKey = crypto.privateDecrypt(
{ key: privateKey, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING },
Buffer.from(encrypted_aes_key, 'base64')
);
// Decrypt the flow data using the AES key
const decipher = crypto.createDecipheriv('aes-128-gcm', aesKey, Buffer.from(initial_vector, 'base64'));
let decrypted = decipher.update(encrypted_flow_data, 'base64', 'utf8');
decrypted += decipher.final('utf8');
return JSON.parse(decrypted);
}
Step 3: Creating the Stripe Checkout Session
Once you receive the item_id from the Flow, use the Stripe API to generate a payment link. Embed the WhatsApp User ID in the Stripe metadata field. This step is vital for mapping the payment back to the correct chat session later.
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
async function createPaymentLink(userId, itemId) {
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
line_items: [{
price: itemId, // Stripe Price ID
quantity: 1,
}],
mode: 'payment',
success_url: 'https://yourserver.com/success',
cancel_url: 'https://yourserver.com/cancel',
metadata: {
whatsapp_user_id: userId
}
});
return session.url;
}
Step 4: Automating Order Confirmation via Stripe Webhooks
When the user completes the payment, Stripe triggers a checkout.session.completed event. Your server receives this event and retrieves the whatsapp_user_id from the metadata. Use this ID to send an automated confirmation message via the WhatsApp API.
For businesses using the official API, this requires a pre-approved Utility template. For developers seeking lower overhead or testing flexibility, WASenderApi provides an alternative for message delivery. WASenderApi allows sending messages via an active WhatsApp session without the rigorous template approval process of the official Cloud API. This is useful for internal order notifications or rapid prototyping where official template constraints are too restrictive.
Security and Compliance Risks
Handling financial data and PII requires strict adherence to security protocols. Do not store full credit card numbers in your database. Stripe handles PCI compliance. Your responsibility is to secure the communication channels.
Webhook Signature Verification
Stripe signs every webhook request. Your server must verify the signature using the stripe-signature header and your endpoint secret. This prevents attackers from spoofing successful payments to trigger fraudulent orders.
Idempotency
Network issues cause webhooks to retry. Your system must be idempotent. Before processing an order, check if the Stripe Session ID already exists in your database. If the record exists, ignore the duplicate request to prevent double-fulfillment.
Data Residency
If you operate in a regulated region like the EU, ensure your webhook server and database comply with GDPR. Encrypt PII at rest and in transit. Minimize the data requested in the WhatsApp Flow to only what is necessary for the transaction.
Troubleshooting Common Failures
- Flow Decryption Failures: This usually stems from a mismatch between the RSA key uploaded to Meta and the private key used by your server. Ensure you use the exact PEM format required.
- Stripe Metadata Missing: If the
whatsapp_user_idis missing from the Stripe webhook, the system cannot close the loop. Always verify metadata injection during the session creation step. - Webhook Timeout: Meta requires Flow responses within 10 seconds. If your Stripe API call is slow, the Flow will time out. Use an asynchronous pattern where the Flow screen acknowledges receipt immediately, and the payment link is sent as a separate message.
Frequently Asked Questions
Does Stripe work directly inside WhatsApp?
No. Users click a link within the WhatsApp Flow that opens a Stripe Checkout page. While the user remains inside the WhatsApp browser, the payment processing happens on Stripe servers for security and compliance.
Are there extra fees for using Flows with Stripe?
Meta charges for the conversation (Marketing or Utility category). Stripe charges its standard transaction fees. There is no additional Meta fee specifically for the Flow interaction itself.
Can I use this for subscriptions?
Yes. Stripe Checkout supports both one-time payments and subscriptions. You must update your Flow logic to handle the recurring payment metadata and lifecycle events.
How do I handle payment failures?
If a Stripe session expires or a card is declined, Stripe sends a checkout.session.expired or payment_intent.payment_failed webhook. Configure your server to send a follow-up WhatsApp message encouraging the user to try again or choose a different payment method.
Is an official WhatsApp Business API account required?
Flows are a feature of the official Meta WhatsApp Business Platform. While tools like WASenderApi help with sending standard messages or notifications, the Flow UI and its secure data exchange require the official Cloud API infrastructure.
Integrating WhatsApp Flows with Stripe creates a professional commerce experience. By centralizing the transaction logic and securing the webhooks, you provide users with a fast, safe way to purchase products without leaving their preferred messaging app. Prioritize endpoint security and idempotency to maintain a reliable system.