Send WhatsApp Pay Messages
The WhatsApp Pay feature allows businesses to send an order payment link to the end customers on WhatsApp. Customers can pay the order amount using any of the UPI apps using the link or pay from WhatsApp natively.
The WhatsApp pay feature is built on existing messaging solutions such as Single Product Messages, Multi Product Messages, and Product Detail Messages that help in placing orders using the product catalog. Further, the feature is powered with payment solutions by partner payment gateways.
Prerequisites
The following are the prerequisites for sending catalog messages:
- An active kaleyra.io account, if you do not have one, you can contact a kaleyra representative to sign up for free to the platform. Before you get started, Create a Kaleyra Account and Create an API Key.
To view the API Key and the SID, see View API Key and SID.. - An active WhatsApp for Business plan.
- Prerequisites specified for WhatsApp Pay.
Order_details API request message
An order details message is an interactive message that contains the list of items selected along with the items’ prices and the total bill amount to be paid and a payment link using which the customer can complete the order payment.
Base URL
https://api.kaleyra.io/v1/<SID>
Request format
The following is the request format to send an order details request message.
curl --location --request POST '<base_url>/messages' \
--header 'api-key: <api_key>' \
--form 'to="<to>"' \
--form 'type="order_details"' \
--form 'channel="WhatsApp"' \
--form 'from="<from>"' \
--form 'body="message body"' \
--form 'footer="Footer"' \
--form 'action="{
\"name\": \"Review_and_Pay\",
\"parameters\": {
\"reference_id\": \"<reference_id>\",
\"type\": \"<goods type>\",
\"payment_settings\": [
{
\"type\": \"payment_gateway\",
\"payment_gateway\": {
\"type\": \"razorpay\",
\"configuration_name\": \"<configuration name>\",
\"razorpay\": {
\"receipt\": \"receipt-value\",
\"notes\": {
\"key1\": \"value1\"
}
}
}
}
],
\"currency\": \"INR\",
\"total_amount\": {
\"value\": <value>,
\"offset\": 100
},
\"order\": {
\"status\": \"pending\",
\"items\": [
{
\"retailer_id\": \"<retailer_id>\",
\"name\": \"<item name>\",
\"amount\": {
\"value\": <value>,
\"offset\":100
},
\"sale_amount\": {
\"value\": <value>,
\"offset\": 100
},
\"quantity\": 1
}
],
\"subtotal\": {
\"value\": <value>,
\"offset\": 100
},
\"tax\": {
\"value\": 00,
\"offset\": 100,
\"description\": \"0%\"
},
\"shipping\": {
\"value\": 0,
\"offset\": 100,
\"description\": \"<Discount message>\"
},
\"discount\": {
\"value\": 0,
\"offset\": 100,
\"description\": \"0% discount\",
\"discount_program_name\": \"optional_text\"
}
}
}
}"' \
--form 'header="<header text>"' \
--form 'callback_url="<https://<callback URL>"'
Sample Request
The following is a sample API request to send an order details message.
curl ----request POST 'https://api.kaleyra.io/v1/HXIN17787xxxxxIN/messages' \
--header 'api-key: xxxxxe49xxxx13ce3f53613dad5xxxxxx' \
--form 'to="xx99865xxxxx"' \
--form 'type="order_details"' \
--form 'channel="WhatsApp"' \
--form 'from="+9180452xxxxx"' \
--form 'body="They`re good for your eye health too"' \
--form 'footer="Footer"' \
--form 'action="{
\"name\": \"Review_and_Pay\",
\"parameters\": {
\"reference_id\": \"Hello_2abcdxyabxyaab\",
\"type\": \"physical-goods\",
\"payment_settings\": [
{
\"type\": \"payment_gateway\",
\"payment_gateway\": {
\"type\": \"razorpay\",
\"configuration_name\": \"razor_pay_config\",
\"razorpay\": {
\"receipt\": \"receipt-value\",
\"notes\": {
\"key1\": \"value1\"
}
}
}
}
],
\"currency\": \"INR\",
\"total_amount\": {
\"value\": 1000,
\"offset\": 100
},
\"order\": {
\"status\": \"pending\",
\"expiration\":
{
\"timestamp\": \"1721198395\",
\"description\": \"cancellation-explanation\"
},
\"items\": [
{
\"retailer_id\": \"6f5gcuihud\",
\"name\": \"Bushel of carrots\",
\"amount\": {
\"value\": 100,
\"offset\":100
},
\"sale_amount\": {
\"value\": 100,
\"offset\": 100
},
\"quantity\": 10
}
],
\"subtotal\": {
\"value\": 1000,
\"offset\": 100
},
\"tax\": {
\"value\": 100,
\"offset\": 100,
\"description\": \"10% tax on your order\"
},
\"shipping\": {
\"value\": 100,
\"offset\": 100,
\"description\": \"10% off on your order\"
},
\"discount\": {
\"value\": 200,
\"offset\": 100,
\"description\": \"20% discount\",
\"discount_program_name\": \"optional_text\"
}
}
}
}"' \
--form 'header="Bushel of carrots"' \
--form 'callback_profile_id="IN_b86b078e-046b-4565-892c-XXXXXXXXXXXX"'
Parameters description table
The following table shows the list of parameters for order details API request.
Parameter | Data Type | Description | Examples | Mandatory? |
---|---|---|---|---|
sid | String | Account SID (Security Identifier). | HXXXXXXX071US | Yes |
api_key | String | The API Key generated by kaleyra.io. | Ac4XXXXX21f | Yes |
to_number | String | A valid WhatsApp number of the recipient. Ensure that the country code is prefixed to the number. (E164 format). Note: You can add multiple numbers, separate each number using the comma (,). | 919886517012 | Yes |
type | String | Message format for the message. The type must be 'order_details'. | order_details | Yes |
channel_name | String | Only the WhatsApp channel is supported for the WhatsApp catalog template. | Yes | |
from_number | String | The number registered with WhatsApp business from which the message is to be sent. Ensure that the country code is prefixed to the number. (E164 format). | 918045210677 | Yes |
callback_url | String | Specifies the callback URL to receive notifications regarding the WhatsApp message status (sent, delivered, read, and failed). For more information related to callback profiles, see the Callback profiles page. The URL can be accessed publicly. Click here for an example. | https://webhook.site/e5xxxx3f-cxx4-4xx4-axx8-2exxxxxxxx95 | No |
header | Object | Header content is 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. | Message header | No |
footer | Object | 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 | Message footer | No |
body | Object | An object with the message body. The object contains the following field: text string: Required, if the body is present. This is the content of the message. Emojis and markdown are supported. Maximum length of the body text is 1024 characters. | They`re good for your eye health too | Yes |
action | Object | An action that you want the end customer to perform after reading the message. This action object contains the following fields: name string: Required. Must be "review_and_pay". Parameters object-See Parameters Object description table for information. | See Parameters Object for information | Yes |
Parameters object description table
The following table shows the list of parameters for the 'Parameters' object.
Parameter | Data Type | Description | Example | Mandatory? |
---|---|---|---|---|
reference_id | String | Unique ID given by the business. It is case sensitive and cannot be an empty string. It can only contain English letters, numbers, underscores, dashes, or dots, and should not exceed 35 characters. If there is a need to send multiple order_details messages for the same order, add a sequence number in the reference_id (for example, "BM345A-12") to ensure reference_id uniqueness. | Hello_2abcdxyabxyaab | Yes |
type | Object | The type of goods in this order. The supported options are digital-goods and physical-goods. | digital-goods | Yes |
beneficiaries | Array | Required for shipped physical-goods. Beneficiary information is not shown to users but is needed for legal and compliance reasons. | beneficiary1 | No |
Payment Settings object description table
The following table shows the list of parameters for Payment Settings object.
Parameter Description Data Type Example Mandatory? type Must be set to 'payment_gateway' String payment_gateway Yes payment_gateway This object contains the following fields:
1)type: Required.
Unique identifier for an item in the order. Must set this to "razorpay" or "payu", if you have linked your Razorpay or PayU payment gateway to accept payments
2) configuration_name: Required.
The name of the pre-configured payment configuration to use for this order and must not exceed 60 characters. This value must match with a payment configuration set up on the WhatsApp Business Manager as shown here.
Note: When the configuration_name is invalid, the customer will be unable to pay for their order.
3) razorpay/payu object: Optional.
For merchants/partners that want to use notes, receipt(for Razorpay) and UDF fields(for PayU), they can now pass these values in Order Details message and we would use these to create transactoin/order at respective PGs.Object {
"type": "razorpay",
"configuration_name": "razor_pay_config",
"razorpay": {
"receipt": "receipt-value",
"notes": {
"key1": "value1"
}Yes
Razorpay Notes and PayU UDF field description table
The following table shows the list of parameters for Razorpay Notes and PayU UDF fields.
Parameter | Data Type | Description | Example | Mandatory? |
---|---|---|---|---|
notes | Object | Only supported for Razorpay payment gateway The object can be key value pairs with maximum 15 keys and each value limits to 256 characters. | “Key1”: ”value1”, “key2”: ”value2” | No |
receipt | String | Only supported for Razorpay payment gateway. Receipt number that corresponds to this order, set for your internal reference. Maximum length of 40 characters supported with minimum length greater than 0 characters. | receipt-value | No |
udf1-4 | String | Only supported for PayU payment gateway. User-defined fields (udf) are used to store any information corresponding to a particular order. Each UDF field has a maximum character limit of 255. | value1, value2, value3, value4 | No |
Order object parameters description table
The following table shows the list of parameters for Order Object.
Parameter | Data Type | Description | Example | Mandatory? |
---|---|---|---|---|
status | string | The only supported value in the order_details message is 'pending' status. | pending | Yes |
type | string | The only supported value is 'quick_pay'. When this field value is provided, the "Review and Pay" button is hidden and only the "Pay Now" button is shown in the order details bubble. | quick_pay | No |
items | Object | This is an object with the list of items for the order that contains the following fields: 1. retailer_id: string Optional. Content ID for an item in the order from the catalog. 2. name: string Required. The item’s name to be displayed. Cannot exceed 60 characters. 3. image: object Optional. Custom image for the item to be displayed to the user. See item image object for information. Using this image field will limit the items array to a maximum of 10 items and this cannot be used with retailer_id or catalog_id. 4. amount: amount object with value and offset; Required. The price per item. 5. sale_amount: amount object 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. 6. quantity: integer Required. The number of items in this order, this field cannot have a decimal value. 7. country_of_origin: string Required, if the catalog_id is not present. The country of origin of the product. 8. importer_name: string Required, if the catalog_id is not present. Name of the importer company. 9. importer_adress: string Required, if the catalog_id is not present. Address of importer company. | "items": { "retailer_id": "6f5gcuihud", "name": "Bushel of carrots", "amount": { "value": 12.34, "offset":100 }, "sale_amount": { "value": 12.34, "offset": 100 }, "quantity": 1 } ], "subtotal": { "value": 12.34, "offset":100 }, "tax": { "value": 00, "offset": 100, "description": "0%" }, "shipping": { "value": 0, "offset": 100, "description": "0% off on your order" }, "discount": { "value": 0, "offset": 100, "description": "0% discount", "discount_program_name": "optional_text" } } } } | Yes |
subtotal | Object | The value must be equal to sum of order.amount.value * order.amount.quantity. The following fields are part of the subtotal object: 1. offset: integer Required. This value must be 100 for INR. Offset is a positive integer used to multiply with the price amount to make it a whole number. For example, Rs.12.34 has a value 1234 where 100 is the offset value. | "subtotal": { "value": 12.34, "offset": 100 } | Yes |
tax | Object | The tax information for this order which contains the following fields: 1. offset: integer Required. Must be 100 for INR 2. value: integer Required. Positive integer representing the amount value multiplied by offset. For example, ₹12.34 has value 1234 3)description: string Optional. Max character limit is 60 characters. | "tax": { "value": 00, "offset": 100, "description": "0%" } | Yes |
shipping | Object | The shipping cost of the order. The object contains the following fields: 1)offset: integer Required. Must be 100 for INR 2)value: integer Required. Positive integer representing the amount value multiplied by offset. For example, ₹12.34 has value 1234 3)description: string Optional. Max character limit is 60 characters. | "shipping": { "value": 0, "offset": 100, "description": "0% off on your order" } | No |
discount | Object | The discount for the order. The object contains the following fields: 1)offset: integer Required. Must be 100 for INR 2)value: integer Required. Positive integer representing the amount value multiplied by offset. For example, ₹12.34 has value 1234 3)description: string Optional. Max character limit is 60 characters 4)discount_program_name: string Optional. Text used for defining the orders with incentive. If an order is incentivized, the merchant needs to define this information. Max character limit is 60 characters. | "discount": { "value": 0, "offset": 100, "description": "0% discount", "discount_program_name": "optional_text" } | No |
catalog_id | Object | The unique identifier of the Facebook catalog being used by the business. If you do not provide this field, make sure you provide the following fields inside the items object: country_of_origin, importer_name, and importer_address. | the-catalog_id | No |
expiration | Object | The expiration time for that order. Business must define the following fields inside this object: 1. timestamp: string – UNIX timestamp, after which the order expires. The minimum validity interval is 300 seconds. The specified time interval is calculated from the time the order message is delivered. 2. description: string – Text explanation for expiration. Max character limit is 120 characters. | "expiration": {"timestamp": "1721198395 ", "description": "cancellation-explanation" | No |
Item Image object parameters description table
The following table shows the list of parameters for Item Image Object.
Parameter | Data Type | Description | Example | Mandatory? |
---|---|---|---|---|
link | String | A link to the item image that is shown to the end customer. Must be an image/jpeg or image/png and 8-bit, RGB or RGBA. Follows same requirements as image in media. | @/C:/Users/company_A/Downloads/videoplayback.mp4 | Yes |
Sample Success Response
The following is a sample success message with the status 202 Accepted.
{
"id": "5d34d9e5-d36c-4ad2-b6d5-f5a4abc460bc",
"type": "order_details",
"body": "They`re good for your eye health too",
"createdDateTime": "2024-04-25 12:20:51+00:00",
"totalCount": 1,
"data": [
{
"message_id": "5d34d9e5-d36c-4ad2-b6d5-f5a4abc460bc:0",
"recipient": "xxxx8651xxxx"
}
],
"error": {}
}
Sample Error Response
The following is a sample error response.
{
"code": "E413",
"message": "Invalid/incorrect inputs",
"data": [],
"error": {
"body": "For the type order_details, body field is mandatory and cannot be empty!"
}
}
Order status API
An order status API request sends the latest order status to the end customer with a reference to the original order_details message.
Base URL
https://api.kaleyra.io/v1/<SID>
Request format
The following is the request format to send an order status update message.
curl --location --request POST '<base_url>/messages' \
--header 'api-key: A6292e49b8d313ce3f53613dad588dda9' \
--form 'to="<to number>"' \
--form 'type="order_status"' \
--form 'channel="WhatsApp"' \
--form 'from="<from number>"' \
--form 'body="<body text>"' \
--form 'footer="Footer"' \
--form 'action="{
\"name\": \"review_order\",
\"parameters\": {
\"reference_id\": \"<reference id>\",
\"order\": {
\"status\": \"<status\",
\"description\": \"<status description>\"
}
}
}"' \
--form 'callback_url="<callback url>"'
Sample API request
The following is a sample API request to send an order status update message.
curl location --request POST 'https://api.kaleyra.io/v1/xxxx177871xxxxxx/messages' \
--header 'api-key: xxxxxe49xxxx13ce3f53613dad58xxxxx' \
--form 'to="+9199865xxxxx"' \
--form 'type="order_status"' \
--form 'channel="WhatsApp"' \
--form 'from="+xxxx45210xxx"' \
--form 'body="Hello user"' \
--form 'footer="Footer"' \
--form 'action="{
\"name\": \"review_order\",
\"parameters\": {
\"reference_id\": \"Hello_2hyabfabkeabzahi\",
\"order\": {
\"status\": \"partially_shipped\",
\"description\": \"Order status update\"
}
}
}"' \
--form 'callback_url="https://webhook.site/e79a769e-e523-4662-a3cc-a4ae09a9045d"'
Parameters description table
The following table shows the parameter descriptions for order status API request.
Parameter | Data Type | Description | Example | Mandatory? |
---|---|---|---|---|
sid | String | Account SID (Security identifier) | HXXXXXXX071US | Yes |
api_key | String | The API key generated by kaleyra.io | Ac4XXXXX21f | Yes |
to_number | String | A valid WhatsApp number of the recipient. Ensure that the country code is prefixed to the number. (E164 format). Note: You can add multiple numbers, separate each number using the comma (,). | xx988xxx70xx | Yes |
type | String | Message format for the message. The type must be 'order_details'. | order_status | Yes |
from_number | String | The number registered with WhatsApp business from which the message is to be sent. Ensure that the country code is prefixed to the number. (E164 format). | xx80452xxxxx | Yes |
body | String | Message body | Hello User | Yes |
footer | String | An object with the footer of the message. The object contains the following fields: text string. Required if footer is present. The footer content. Emojis, markdown, and links are supported. Maximum length is 60 characters. | Footer text | No |
reference_id | String | The ID sent by the business in the order_details message | Hello_2hyabfabkeabzahi | Yes |
order | Object | This object contains the following fields: 1. status: string Required. The represents the new order status. The status values can be: processing, partially_shipped, shipped, completed, canceled. 2. description: string Optional. This is the text that shows the status related information in the order_details. This is useful while sending cancellation. Maximum character limit is 120 characters. | "order": { "status": "partially_shipped", "description": "Order status update" | Yes |
action | Object | An action object you want the user to perform after reading the message. This action object contains the following fields: 1. name:string Required. Must be "review_and_pay". 2. parameters object See, [Parameters_object_description](Parameters description table) table for information. | 'action=" { "name": "review_order", ` "parameters": { `"reference_id": "Hello_2hyabfabkeabzahi", "order": { "status": "partially_shipped", "description": "Order status update" } } | Yes |
Callback_ profile_id | String | The callback ID created for WhatsApp channel to receive updates about the message delivery status. Note: You can also use callback_url to get updates about the message delivery status to the specified URL. | xx_b86b078e-046b-4565-892c-XXXXXXXXXXXX | No |
Sample success response
The following is a sample success response for order status API request.
{
"id": "cbc7725a-8199-4e32-8af0-25e7ed261c52",
"type": "order_status",
"body": "Hello user",
"createdDateTime": "2024-05-02 13:39:15+00:00",
"totalCount": 1,
"data": [
{
"message_id": "cbc7725a-8199-4e32-8af0-25e7ed261c52:0",
"recipient": "xx99865xxxxx"
}
],
"error": {}
}
Sample error response
The following shows an error response for order status API request.
{
"code": "E413",
"message": "Invalid/incorrect inputs",
"data": [],
"error": {
"type": "type field is mandatory"
}
}
Payment status API
A payment status API request fetches the status about the order payment made by the customer for the businesses.
Note:
The message status webhooks also retrieve the payment status updates. This can be shared with the business via callbacks.
Base URL
https://api.kaleyra.io/v1/<SID>
API request format
The following is the GET request format to obtain the customer payment status.
curl --location --request GET 'https://api.kaleyra.io/v1/<SID/ <phone_no>/<payment_configuration>/reference_id'
where the 'payment configuration' and the 'reference ID' are the same values sent for the order details message and the phone number is the customer WhatsApp phone number for which the payment status is fetched.
Sample API request
The following is a sample API that uses 'GET' request to fetch payment update.
curl --location --request GET 'https://api.kaleyra.io/v1/v1/xxxx17787121xxxx/whatsapp/payment/status?number=%2xx18045210677&reference_id=Hiabqidaq_1abcdeabyzqabq&payment_config_id=razor_pay_config' \
--header 'api-key: A6292e49b8d313ce3f53613dad588dda9'
Sample success response
The following sample success response is shown for the payment update GET request.
{
"code": "WA200",
"message": "Request Processed Successfully",
"data": {
"payments": [
{
"amount": {
"offset": 100,
"value": 100
},
"currency": "INR",
"reference_id": "Hiabqidaq_1abcdeabyzqabq",
"status": "CAPTURED",
"transactions": [
{
"amount": {
"offset": 100,
"value": 100
},
"created_timestamp": 1708424916,
"currency": "INR",
"id": "order_Nd6JAsbEscE2gY",
"status": "success",
"type": "razorpay",
"updated_timestamp": 1708424916
}
]
}
]
},
"error": {}
}
Payment Refund API
A business can refund the order payment money back to the customer under specific business conditions.
Base URL
https://api.kaleyra.io/v1/<SID>
Request format
The following is the request format to refund the order payment money to the customer.
curl --location --request POST '<base_url>/whatsapp/payment/refund' \
--header 'api-key: xxxxxe49b8dxxxxe3f53613dad5xxxxxx' \
--header 'Content-Type: application/json' \
--data '{
"reference_id": "<reference id>",
"speed": "instant",
"payment_config_id": "razor_pay_config",
"currency": "INR",
"value": "<value>",
"offset": "<value>",
"number": "<from no>"
}'
Sample request format
The following sample API request refunds the order payment money to the customer.
curl --location --request POST 'https://api.kaleyra.io/v1/whatsapp/payment/refund' \
--header 'api-key: xxxxxe49b8d313ce3f53613dad5xxxxxx' \
--header 'Content-Type: application/json' \
--data '{
"reference_id": "Hiabqidaq_1abcdeabyzqabq",
"speed": "instant",
"payment_config_id": "razor_pay_config",
"currency": "INR",
"value": "100",
"offset": "100",
"number": "+xxxx45210xxx"
}'
Parameter description table
The following table shows the parameter description for Refund API.
Refer to the Order Details parameters description tables for the remaining parameters used in the API request.
Parameter | Data Type | Description | Example | Mandatory? |
---|---|---|---|---|
sid | String | Account SID (Security Identifier). | HXXXXXXX071US | Yes |
api_key | String | The API Key generated by kaleyra.io. | Ac4XXXXX21f | Yes |
reference_id | String | Unique ID given by the business for every transaction. It is case sensitive and cannot be an empty string. It can only contain English letters, numbers, underscores, dashes, or dots, and should not exceed 35 characters. If there is a need to send multiple order_details messages for the same order, add a sequence number in the reference_id (for example, "BM345A-12") to ensure reference_id uniqueness. | Hello_2abcdxyabxyaab | |
Speed | String | The time at which the refund should be done. For Instant speed, the refund is done immediately. For normal speed, the refund may be done with a time delay. | Instant, Normal | Yes |
Payment_ config_id | String | The name of the pre-configured payment configuration to use for this order and must not exceed 60 characters. This value must match with a payment configuration set up on the WhatsApp Business Manager Note: When the configuration_name is invalid, the customer will be unable to pay for their order. | xxxxxo_2abcdxyabxyaab | Yes |
currency | String | Name of the currency used in the payment transaction. | INR | Yes |
value | Integer | The refund amount to be paid to the customer. | 100 | Yes |
offset | Integer | The offset value is to be calibrated with the currency value. | 100 | Yes |
number | Integer | The customer number to which the refund has to be made. | xx99xxx17xx6 | Yes |
Sample success message
The following is a sample success message for the Refund API request.
{
"id": "refund-id",
"status": "pending",
"speed_processed": "normal"}
Sample error message
The following is a sample error message for the Refund API request.
{
"code": "WA400",
"message": "valid refund speed required, accepted values are normal/instant",
"data": [],
"error": {
"speed": "valid refund speed required, accepted values are normal/instant"
}
}
Updated about 1 month ago