[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.

triangle-exclamation

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.

circle-exclamation

Purchase Flow in the App

In the WhatsApp customer app, the purchase flow has the following steps:

  1. Customer sends an order with selected products to the business;

Business receives the client's selected products
  1. Once it receives the order, the business must check if a receiver is eligible to an order_details message. 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 the order_details message as shown below.

Business sends to the costumer the order_message
  1. 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 client can add the payment method in the User Interface
  1. The customer then pays in the application;

Client pays the order_message
  1. 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 status on their order;

Status and Order message updates

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.

circle-info

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 codearrow-up-right for the items in the order, andupi_pc refers to the purpose of the transaction. Some sample codes are below:

Code
Title

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:

Field
Description

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:

Error Code
Customer Eligibility

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

circle-info

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:

Object
Description

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 body is 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 footer is 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

Parameters Object

Object
Description

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 100 for INR.

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

Object
Description

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_id is not present. The country of origin of the product

importer_name string

  • Required if catalog_id is not present. Name of the importer company

importer_adress string

  • Required if catalog_id is 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 100 for INR

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 100 for INR

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 100 for INR

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 100 for INR

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 type field can now have the value of payment

  • A new payment object will be included inside statuses. The new object mentions reference_id, the field supplied by the business in their order_details object

  • The status field can have the following values:

Transaction Status

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 success as 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:

Field
Description

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:

Field
Description

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

Status
Description

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:

Value
Description

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:

Value
Description

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:

Error Code
Description

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 Codesarrow-up-right.

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?