[beta] Receive WhatsApp UPI Payments
UPI Payments Integration allow customers to pay for their orders without leaving the WhatsApp customer app
This feature added to the available set of WhatsApp commerce messaging solutions, which includes Single Product Message, Multi Product Message, and Product Detail Page can enhance the user experience.
The UPI Payment Integration feature is available only for Indian businesses using the 360dialog WhatsApp Business API with phone numbers only from India. Review WhatsApp Business Compliance for India.
On this page, you'll find the inputs and outputs to use the Payment API feature as a 360dialog client. See below how to send customers order_details messages, and get payment status updates via webhook notifications.
How it Works
When the conversation starts, it is necessary to check if the user can receive order_details messages. This is only possible if the user's phone number is also from India and if the WhatsApp Consumer App version supports it (iOS suggested version is 2.21.210 and Android suggested version is 2.21.19). In case the customer is not eligible, the business should use another payment method.
The order_details message is a new type of interactive message, which contains 4 main components: header, body, footer, and action. Inside the action component, the business will include all information required for the customer to complete their payment.
Each order_details message contains a unique reference_id provided by the business, and that unique number is used throughout the flow to track the order.
Once the message is sent, the business must wait for a payment or transaction status update. There are three payment statuses currently supported by WhatsApp: pending, captured, and failed. Each payment can include one or more transactions.
Notifications will be transmitted when the transaction status changes, but do not solely rely on these webhooks notifications due to security reasons. WhatsApp provides a payment-lookup API to retrieve the payment statuses directly, and, is possible to query payment status using different phone numbers under the same Business Manager account.
Please note that neither 360dialog nor WhatsApp supports payment reconciliations.
You must reconcile the payment with the business payment service provider using the respective order reference_id.
Purchase Flow in the App
In the WhatsApp customer app, the purchase flow has the following steps:
Customer sends an order with selected products to the business;

Once it receives the order, the business must check if a receiver is eligible to an
order_detailsmessage. If the customer is not eligible to receive it, the business is notified with a webhook and the business can, instead, send a link for the customer to complete payment on a separate surface. If the user is eligible, the customer receives theorder_detailsmessage as shown below.

When the user taps the payment button, they will be able to add a payment method if they don’t already have one in place;

The customer then pays in the application;

Once the payment is complete, the business receives a notification from WhatsApp and looks up the payment or transaction status with their payment provider. The customer can also get an update for
statuson their order;

Security Considerations for Payments API
To ensure secure financial processing, payment configurations such as the business’ VPA shared by all WhatsApp phone numbers must belong to the same Business Manager account. If you wish to separate payments for different phone numbers, then additional Business Manager Accounts must be created.
Furthermore, businesses should not rely solely on the status of the payment or transaction provided in the webhook status. It is possible to use Payment lookup API to retrieve the statuses directly from WhatsApp.
It is very important to implement robust data validation and sanitization processes to protect against SSRF attacks while handling payment data in API responses or webhooks.
Review our WABA Security documentation.
Before You Start
To receive payments through WhatsApp, you must have the WhatsApp Business Platform On-Premises client hosted by us. Additionally, you must work with the 360Dialog team to configure payment settings.
Each configuration must have a unique name, merchant categorization code (mcc), purpose code, and VPA handles as shown below. A business can have multiple payment configurations, but for each order you must specify a specific configuration to be used for payment. See payment_configuration field in order_details message.
name for each payment type must be unique. name will be used to reference the specific configurations for each payment type. If WA is unable to find a payment configuration name, the user will not be able to make the payment upon receiving the order_details message. mcc refers to a merchant categorization code for the items in the order, andupi_pc refers to the purpose of the transaction. Some sample codes are below:
00
Default
01
SEMI
02
AMC
03
Travel
04
Hospitality
05
Hospital
06
Telecom
07
Insurance
08
Education
09
Gifting
10
Others
Note: For test accounts use upi_pc: 00 and mcc: 0000
Get Started
The steps outlined in this tutorial assume that the business has received a webhook notification indicating that a customer has placed an order. A sample webhook notification for the On-Premises API implementation is as follows:
The following sequence diagram demonstrates the typical integration flow for WhatsApp Payments API:

Step 1: Check Customer Eligibility
First, businesses need to check if a customer is eligible to receive an order_details message. To do that, they must make a POST call to /v1/messages and set the dry_run parameter to True. The request can include the following fields:
type
String
Required.
The type of interactive message that will be sent. In this case, it must be set to order_details.
dry_run
Boolean
Required.
Set to true in order to trigger the dry-run mode.
parameters.type
String
Required.
This field should be set to digital-goods or physical-goods.
The complete API call is as follows:
A dry run message is never sent to the customer. However, the business will receive a webhook notification indicating whether or not the customer is eligible to receive an order_details message:
1026
Not eligible to receive order_details messages. the customer a link so they can complete their payment outside of WhatsApp
1030
Eligible to receive order_details messages. Proceed to Step 2
To avoid problems with the end-to-end encryption, we recommend checking the customer’s payment eligibility at most once per session.
Step 2: Assemble the Interactive Object
To send an order_details message, businesses must assemble an interactive object of type order_details with the following components:
type
object
Required.
Must be set to "order_details".
header
object
Optional.
Header content displayed on top of a message. If a header is not provided, the API uses an image of the first available product as the header
body
object
Required.
An object with the body of the message. The object contains the following field:
text string
Required if
bodyis present. The content of the message. Emojis and markdown are supported. Maximum length is 1024 characters
footer
object
Optional.
An object with the footer of the message. The object contains the following field:
text string
Required if
footeris present. The footer content. Emojis, markdown, and links are supported. Maximum length is 60 characters
action
object
Required.
An action object you want the user to perform after reading the message. This action object contains the following fields:
name string
Required. Use
review_and_pay
parameters object
See Parameters Object for information
Parameters Object
reference_id
string
Required.
Unique identifier for the order or invoice provided by the business. This cannot be an empty string and can only contain English letters, numbers, underscores, dashes, or dots, and should not exceed 35 characters.
The reference_id must be unique for each order_details message for the same business. If the partner would like to send multiple order_details messages for the same order, invoice, etc. it is recommended to include a sequence number in the reference_id (for example, -) to ensure reference_id uniqueness.
type
object
Required.
The type of goods being paid for in this order. Current supported options are digital-goods
payment_configuration
Required.
The name of the pre-configured payment configuration to use for this order and must not exceed 60 characters.
currency
Required.
The currency for this order. Currently the only supported value is INR
total_amount
object
Required.
The total_amount object contains the following fields:
offset integer
Required. Must be
100forINR.
value integer
Required. Positive integer representing the amount value multiplied by offset. For example, ₹12.34 has value 1234.
total_amount.value must be equal to order.subtotal.value + order.tax.value + order.shipping.value - order.discount.value.
order
object
Required.
See order object for more information.
Order Object
status
string
Required.
Only supported value in the order_details message is pending.
In an order_status message, status can be: pending, captured, or failed.
items
object
Required.
An object with the list of items for this order, containing the following fields:
retailer_id string
Required. Unique identifier of the Facebook catalog being used by the business
name string
Required. The item’s name to be displayed to the user. Cannot exceed 60 characters
amount string
Required. The price per item
sale_amount amount object with value and offset as described above in total_amount field
Optional. The discounted price per item. This should be less than the original amount. If included, this field is used to calculate the subtotal amount
quantity integer
Required. The number of items in this order - only supports integer, API Client returns validation error if sent decimal.
country_of_origin string
Required if
catalog_idis not present. The country of origin of the product
importer_name string
Required if
catalog_idis not present. Name of the importer company
importer_adress string
Required if
catalog_idis not present. Address of importer company
subtotal
object
Required.
The value must be equal to sum of order.amount.value * order.amount.quantity. Refer to total_amount description for explanation of offset and value fields
The following fields are part of the subtotal object:
offset integer
Required. Must be
100forINR
value integer
Required. Positive integer representing the amount value multiplied by offset. For example, ₹12.34 has value 1234
tax
object
Required.
The tax information for this order which contains the following fields:
offset integer
Required. Must be
100forINR
value integer
Required. Positive integer representing the amount value multiplied by offset. For example, ₹12.34 has value 1234
description string
Optional. Max character limit is 60 characters
shipping
object
Optional.
The shipping cost of the order. The object contains the following fields:
offset integer
Required. Must be
100forINR
value integer
Required. Positive integer representing the amount value multiplied by offset. For example, ₹12.34 has value 1234
description string
Optional. Max character limit is 60 characters
discount
object
Optional.
The discount for the order. The object contains the following fields:
offset integer
Required. Must be
100forINR
value integer
Required. Positive integer representing the amount value multiplied by offset. For example, ₹12.34 has value 1234
description string
Optional. Max character limit is 60 characters
discount_program_name string
Optional. Text used for defining incentivised orders. If order is incentivised, the merchant needs to define this information. Max character limit is 60 characters
catalog_id
object
Optional.
Unique identifier of the Facebook catalog being used by the business.
If you do not provide this field, you must provide the following fields inside the items object: country_of_origin, importer_name, and importer_address
expiration
object
Optional.
Expiration for that order. Business must define the following fields inside this object:
timestamp string – UTC timestamp in seconds of time when order should expire. Minimum threshold is 300 seconds
description string – Text explanation for expiration. Max character limit is 120 characters
By the end, the interactive object should look something like this for a catalog-based integration:
For a non-catalog based integration, i.e. when catalog-id is not present, an example payload looks as follows:
Step 3: Add Common Message Parameters
Once the interactive object is complete, append the other parameters that make a message: recipient_type, to, and type. Remember to set the type to interactive.
These are parameters common to message types.
Step 4: Make a POST Call to /messages
Make a POST call to the /messages endpoint with the JSON object you have assembled in steps 1 and 2. If your message is sent successfully, you get the following response:
For all errors that can be returned and guidance on how to handle them, see Errors while Messaging
Step 5: Get Notified About Transaction Status Updates
Businesses receive updates via WhatsApp webhooks when the status of the user-initiated transaction changes. To support payments, webhook notifications will include the following updates:
The
typefield can now have the value ofpaymentA new
paymentobject will be included insidestatuses. The new object mentionsreference_id, the field supplied by the business in theirorder_detailsobjectThe
statusfield can have the following values:
Transaction Status
pending
The transaction started
failed
The transaction failed
success
The transaction succeeded
canceled
The transaction was canceled
A webhook notification for an updated payment status looks like this:
Step 6: Get Payment Confirmation
When a transaction with a customer is successful, the business gets the following:
A transaction status update with the status as
successas seen in the transaction status table above.A payment confirmation message webhook notification
The payment confirmation message webhook is an interactive type and includes the following fields:
transaction_id
Unique id of UPI transaction
transaction_type
Type of payment interface for processing the transaction. Currently in India it is upi
reference_id
The partner supplied an ID that uniquely identifies the order_details message for this partner
total_amount
The total amount for this payment
currency
The currency for this payment. Currently the only supported value is INR
status
The new transaction status. See transaction status table for possible values.
An example payment confirmation notification looks like this:
Step 7: Confirm Payment Status
After receiving the payment status change notification, or at any time, the business can look up the status of the payment or transaction. To do that, businesses must make a GET call to /v1/payments/{reference_ID}, using the reference ID provided in the order_details message.
Businesses should expect a response in the same HTTP session (not in a webhook notification). A response can return the following values:
reference_id
The ID provided by the partner in the order_details message
status
The payment status. See the payment status table for possible values. Note that this is not the same as transaction status.
currency
The currency for this payment. Currently the only supported value is INR.
total_amount
The total amount for this payment
transactions
The complete list of transactions for this payment
transactions.id
The ID of the transaction
transactions.type
The payment type for this transaction. Currently, only upi is supported
transactions.status
The status of the transaction. Currently at most one transaction for each payment can have a pending or success status.
Payment Status
new
The partner sent an order_details message but the user didn’t start a payment yet
pending
The user started the payment process and the payment object was created
captured
The payment was captured
canceled
The payment was canceled by the user and no retry is possible
failed
The payment attempt failed but the user can retry
A successful response looks like this:
In the case of any errors, this is the response:
For all errors that can be returned and guidance on how to handle them, see Errors while Messaging
Step 8: Update Order Status
Once an order has been updated, the business must update the order status to keep the user up to date. Currently we support the following order status values:

pending
User has not successfully paid yet
processing
User payment authorized, merchant/partner is fulfilling the order, performing service, etc.
partially-shipped
A portion of the products in the order have been shipped by the merchant
shipped
All the products in the order have been shipped by the merchant
completed
The order is completed and no further action is expected from the user or the partner/merchant
canceled
The partner/merchant would like to cancel the order_details message for the order/invoice. The status update will fail if there is already a successful or pending payment for this order_details message
Typically businesses update the order_status using either the WhatsApp payment status change notifications or their own internal processes. To update order_status, the partner sends an order_status message to the user.
The following table describes the returned values:
reference_id
The ID provided by the partner in the order_details message
status
The new order status
description
Optional text for sharing status related information in order_details. Could be useful while sending cancellation. Max character limit is 120 characters
For all errors that can be returned and guidance on how to handle them, see Errors while Messaging.
Step 9: Receive UPI Payment
When the business receives a Unified Payments Interface (UPI) payment notification from their bank or PSP, they must check their reference_id and confirm the order has not been canceled. See Step 7 for information.
Rarely, the business can receive payments for a canceled order, so a refund must be processed for the customer.
Step 10: Reconcile Payments
Businesses should use their bank statements to reconcile the payments using the reference_id provided in the order_details messages.
Errors and Statuses
These are the relevant errors for the WhatsApp Payments API:
2040 - Message is not supported
The message you are trying to send cannot be received by this user
2046 - Order status invalid transition
The order status cannot be updated from the existing value to the new one
2047 - Order cancellation failure
The order could not be cancelled
For a comprehensive list with detailed descriptions of error codes and HTTP status codes, please refer to this page: Errors while Messaging and HTTP Status Codes.
Checklist for Integrated Merchants
Ensure the merchant is verified and WABA contact is marked with a verified check.
Verify the WABA is mapped to appropriate merchant initiated messaging tier (1k, 10k and 100k per day)
Ensure that the bot supports inter-op. NPCI has mandated to have other payment options along with WhatsApp pay option.

Last updated
Was this helpful?