Merchant Hosted Checkout Integration
This section describes step-by-step procedure to integrate Apple Pay as a payment method using Merchant Hosted Checkout integration with two kinds of decryption integration:
Before you begin: Ensure that you have completed the prerequisites before you start the integration. For more information, refer to Prerequisites and Set up for Apple Pay Integration.
Post the required parameters to PayU for Apple Pay integration
Check and handle the response received from PayU after posting parameters
Verify the payment status and ensure transaction completion
Step 1: Authorize transaction
To initiate an Apple Pay payment, post the payment parameters to PayU's transaction endpoint.
| Environment | URL |
|---|---|
| Production | https://secure.payu.in/AuthorizeTransaction.php |
Request parameters
| Parameter | Description | Example |
|---|---|---|
keymandatory | String – Merchant key provided by PayU during onboarding. | JP***g |
txnidmandatory | String – Unique transaction ID (max 25 chars). Can be generated by merchant or PayU API. | txn_applepay_001 |
amountmandatory | String – Payment amount. | 100.00 |
authentication_infomandatory | String – String – Authentication info based on the PayU-side or Merchant-decryption. For more information, refer to:- Step 1a. Merchant-side Decryption - Step 1b. PayU-side Decryption | |
firstnamemandatory | String – Customer's first name. | John |
emailmandatory | String – Customer's email address. | [email protected] |
phonemandatory | String – Customer's phone number. | 9876543210 |
pgmandatory | String – Payment category. Must be APPLEPAY for Apple Pay integration. | APPLEPAY |
bankcodemandatory | String – Payment option. Must be CCAP for Apple Pay. | CCAP |
address1mandatory | String – Customer address line 1. | 123 Main Street |
citymandatory | String – Customer city. | New York |
statemandatory | String – Customer state. | NY |
countrymandatory | String – Customer country. | USA |
hashmandatory | String – SHA-512 hash ensuring transaction integrity. Uses the formula: sha512(key\|txnid\|amount\|productinfo\|firstname\|email\|udf1\|udf2\|udf3\|udf4\|udf5\|salt). | a1b2c3d4e5f6... |
udf1optional | String – Apple transaction identifier (max 255 chars). | apple_txn_12345 |
udf2optional | String – Should contain the value MAST:credit (max 255 chars). | MAST:credit |
Step 1a. Merchant-side Decryption
Authentication info for Apple Pay
Sample Authentication Info
{
"applicationPrimaryAccountNumber":"4832086841071751",
"applicationExpirationDate":"290228",
"currencyCode":"356",
"transactionAmount":1000,
"deviceManufacturerIdentifier":"040010030273",
"paymentDataType":"3DSecure",
"paymentData":{
"onlinePaymentCryptogram":"KgAAAAoDK12xsrcAAAAAgTtgE4A=",
"eciIndicator":"5"
},
"paymentMethod":{
"displayName":"MasterCard 0049",
"network":"MasterCard",
"type":"credit"
}
}| Field | Description |
|---|---|
applicationPrimaryAccountNumber | Tokenized Primary Account Number (FPAN). Device-specific token that replaces the real card number (DPAN). Format is card-like (e.g. 16 digits); last 4 may match the real card for display. Must not be stored as a card number; use only for the current transaction and token lifecycle. |
applicationExpirationDate | Token expiration date in YYMM format (e.g. 290228 = February 28, 2029). Indicates when this payment token expires; distinct from the underlying card’s expiry. |
currencyCode | ISO 4217 numeric currency code (e.g. 356 = INR, 840 = USD). Must match the transaction currency. |
transactionAmount | Transaction amount in minor units (e.g. paise for INR, cents for USD). Example: 1000 = ₹10.00 or $10.00 depending on currencyCode. |
deviceManufacturerIdentifier | Device-specific identifier from the Secure Element. Used for risk, fraud, and token lifecycle (e.g. linking tokens to the same device). Opaque; format is manufacturer-specific. |
paymentDataType | Type of cryptogram in paymentData. Common values: 3DSecure (e-commerce/CNP), EMV (contactless CP), ECv1 (legacy). Determines which cryptogram field to use and how to validate. |
paymentData | Cryptogram and 3DS data used to authorize the transaction. Contents depend on paymentDataType. |
paymentMethod | Display and card-method metadata (network, type, display name). For UI and routing only; not used as primary authorization data. |
paymentDatobject (whenpaymentDataTypeis3DSecure`)
object (whenpaymentDataTypeis3DSecure`)| Field | Description |
|---|---|
onlinePaymentCryptogram | One-time payment cryptogram (Base64). Generated by the device for this transaction; must be sent to the payment network/processor within its validity window. Used to prove that the transaction was authorized on the device. |
eciIndicator | E-commerce Indicator (ECI). Indicates 3DS authentication level and liability shift. Common values: 05/06 = 3DS authenticated, 07 = 3DS attempted, 01/02 = not 3DS. Used by acquirers and schemes for authentication and liability rules. |
paymentMethod object
| Field | Description |
|---|---|
displayName | User-facing label for the card (e.g. “MasterCard 0049”). Often “Network” + last 4 digits. Safe for receipts and UI; must not be used as PAN or for authorization. |
network | Card scheme/network (e.g. MasterCard, Visa, AMEX). Used for routing and scheme-specific handling. |
type | Product type of the card: e.g. credit, debit, prepaid. Used for routing, compliance, and UX. |
Step 1b. PayU-side Decryption
Authentication info for PayU-side Decryption
Sample Authentication Info
Note: You will receive the following JSON on your registered domain from Apple Pay.
{
"paymentData": {
"data": "<Base64 encrypted payload>",
"signature": "<Base64 PKCS#7 signature>",
"header": {
"publicKeyHash": "<Base64 SHA-256 hash>",
"ephemeralPublicKey": "<Base64 EC P-256 public key>",
"transactionId": "<hex string>"
},
"version": "EC_v1"
},
"paymentMethod": {
"displayName": "Visa 7013",
"network": "Visa",
"type": "debit"
},
"transactionIdentifier": "<hex string>"
}paymentData JSON object fields description
| Field | Description |
|---|---|
data | Encrypted payment data (Base64). Symmetrically encrypted payload containing tokenized card and cryptogram data. Decryption key is derived using the merchant’s private key and header.ephemeralPublicKey (ECDH). Must be decrypted by the merchant/processor to obtain the payment token used for authorization. |
signature | PKCS#7 detached signature (Base64). Contains Apple’s certificate chain and a signature over the payload. Used to verify that the token was issued by a valid Apple Pay environment and was not tampered with. |
header | Key agreement and transaction metadata. Supplies the ephemeral public key for decryption and the transaction ID. |
version | Token format version. Value EC_v1 indicates EC-based key agreement and this encrypted structure. Determines how to parse and decrypt the token. |
header.publicKeyHash | Merchant certificate public key hash (Base64, SHA-256). Identifies the merchant’s Apple Pay certificate used for this token. Used to select the correct private key for decryption and to verify the token was intended for this merchant. |
header.ephemeralPublicKey | Ephemeral EC P-256 public key (Base64). Generated per transaction by the device. The merchant combines this with their private key (ECDH) to derive the symmetric key that decrypts paymentData.data. |
header.transactionId | Unique transaction identifier (e.g., hex). Ties this token to a single transaction. Must match top-level transactionIdentifier; use for idempotency and audit. |
paymentMethod JSON object fields description
| Field | Description |
|---|---|
displayName | User-facing label for the card (e.g., “Visa 7013”). Often “Network” + last 4 digits. Safe for receipts and UI; must not be used as PAN or for authorization. |
network | Card scheme/network (e.g., Visa, MasterCard, AMEX). Used for routing and scheme‑specific handling. |
type | Product type of the card: e.g., credit, debit, prepaid. Used for routing, compliance, and UX. |
Sample request
curl --location 'https://secure.payu.in/AuthorizeTransaction.php' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'key={{key}}' \
--data-urlencode 'txnid={{txnid}}' \
--data-urlencode 'authentication_info={{info}}' \
--data-urlencode 'hash={{hash1}}' \
--data-urlencode 'pg=ApplePay' \
--data-urlencode 'bankcode=CCAP' \
--data-urlencode 'firstname=John' \
--data-urlencode 'country=IN' \
--data-urlencode 'city=Banglore' \
--data-urlencode 'state=KA' \
--data-urlencode '[email protected]' \
--data-urlencode 'address1=street1 area' \
--data-urlencode 'udf1=appleTransactionIdentifier' \
--data-urlencode 'udf2=MAST:credit' \
--data-urlencode 'lastname=Bing' \
--data-urlencode 'zipcode=45678' \
--data-urlencode 'phone=9876543210' \
--data-urlencode 'productinfo=ABC info' \
--data-urlencode 'amount={{amt}}'import requests
import urllib.parse
url = "https://secure.payu.in/AuthorizeTransaction.php"
# Form data
data = {
'key': '{{key}}',
'txnid': '{{txnid}}',
'authentication_info': '{{info}}',
'hash': '{{hash1}}',
'pg': 'ApplePay',
'bankcode': 'CCAP',
'firstname': 'John',
'country': 'IN',
'city': 'Banglore',
'state': 'KA',
'email': '[email protected]',
'address1': 'street1 area',
'udf1': 'appleTransactionIdentifier',
'udf2': 'MAST:credit',
'lastname': 'Bing',
'zipcode': '45678',
'phone': '9876543210',
'productinfo': 'ABC info',
'amount': '{{amt}}'
}
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
try:
response = requests.post(url, data=data, headers=headers)
print(f"Status Code: {response.status_code}")
print(f"Response: {response.text}")
except requests.exceptions.RequestException as e:
print(f"Error: {e}")using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
class Program
{
private static readonly HttpClient client = new HttpClient();
static async Task Main(string[] args)
{
string url = "https://secure.payu.in/AuthorizeTransaction.php";
var formData = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("key", "{{key}}"),
new KeyValuePair<string, string>("txnid", "{{txnid}}"),
new KeyValuePair<string, string>("authentication_info", "{{info}}"),
new KeyValuePair<string, string>("hash", "{{hash1}}"),
new KeyValuePair<string, string>("pg", "ApplePay"),
new KeyValuePair<string, string>("bankcode", "CCAP"),
new KeyValuePair<string, string>("firstname", "John"),
new KeyValuePair<string, string>("country", "IN"),
new KeyValuePair<string, string>("city", "Banglore"),
new KeyValuePair<string, string>("state", "KA"),
new KeyValuePair<string, string>("email", "[email protected]"),
new KeyValuePair<string, string>("address1", "street1 area"),
new KeyValuePair<string, string>("udf1", "appleTransactionIdentifier"),
new KeyValuePair<string, string>("udf2", "MAST:credit"),
new KeyValuePair<string, string>("lastname", "Bing"),
new KeyValuePair<string, string>("zipcode", "45678"),
new KeyValuePair<string, string>("phone", "9876543210"),
new KeyValuePair<string, string>("productinfo", "ABC info"),
new KeyValuePair<string, string>("amount", "{{amt}}")
};
try
{
var formContent = new FormUrlEncodedContent(formData);
formContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
HttpResponseMessage response = await client.PostAsync(url, formContent);
string responseContent = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Status Code: {(int)response.StatusCode}");
Console.WriteLine($"Response: {responseContent}");
}
catch (HttpRequestException ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
}
}async function makePayURequest() {
const url = 'https://secure.payu.in/AuthorizeTransaction.php';
const formData = new URLSearchParams({
'key': '{{key}}',
'txnid': '{{txnid}}',
'authentication_info': '{{info}}',
'hash': '{{hash1}}',
'pg': 'ApplePay',
'bankcode': 'CCAP',
'firstname': 'John',
'country': 'IN',
'city': 'Banglore',
'state': 'KA',
'email': '[email protected]',
'address1': 'street1 area',
'udf1': 'appleTransactionIdentifier',
'udf2': 'MAST:credit',
'lastname': 'Bing',
'zipcode': '45678',
'phone': '9876543210',
'productinfo': 'ABC info',
'amount': '{{amt}}'
});
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: formData
});
const responseText = await response.text();
console.log(`Status Code: ${response.status}`);
console.log(`Response: ${responseText}`);
} catch (error) {
console.log(`Error: ${error.message}`);
}
}
makePayURequest();import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
public class PayURequest {
public static void main(String[] args) {
try {
String urlString = "https://secure.payu.in/AuthorizeTransaction.php";
URL url = new URL(urlString);
String postData = "key=" + URLEncoder.encode("{{key}}", StandardCharsets.UTF_8) +
"&txnid=" + URLEncoder.encode("{{txnid}}", StandardCharsets.UTF_8) +
"&authentication_info=" + URLEncoder.encode("{{info}}", StandardCharsets.UTF_8) +
"&hash=" + URLEncoder.encode("{{hash1}}", StandardCharsets.UTF_8) +
"&pg=" + URLEncoder.encode("ApplePay", StandardCharsets.UTF_8) +
"&bankcode=" + URLEncoder.encode("CCAP", StandardCharsets.UTF_8) +
"&firstname=" + URLEncoder.encode("John", StandardCharsets.UTF_8) +
"&country=" + URLEncoder.encode("IN", StandardCharsets.UTF_8) +
"&city=" + URLEncoder.encode("Banglore", StandardCharsets.UTF_8) +
"&state=" + URLEncoder.encode("KA", StandardCharsets.UTF_8) +
"&email=" + URLEncoder.encode("[email protected]", StandardCharsets.UTF_8) +
"&address1=" + URLEncoder.encode("street1 area", StandardCharsets.UTF_8) +
"&udf1=" + URLEncoder.encode("appleTransactionIdentifier", StandardCharsets.UTF_8) +
"&udf2=" + URLEncoder.encode("MAST:credit", StandardCharsets.UTF_8) +
"&lastname=" + URLEncoder.encode("Bing", StandardCharsets.UTF_8) +
"&zipcode=" + URLEncoder.encode("45678", StandardCharsets.UTF_8) +
"&phone=" + URLEncoder.encode("9876543210", StandardCharsets.UTF_8) +
"&productinfo=" + URLEncoder.encode("ABC info", StandardCharsets.UTF_8) +
"&amount=" + URLEncoder.encode("{{amt}}", StandardCharsets.UTF_8);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setDoOutput(true);
try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) {
outputStream.writeBytes(postData);
outputStream.flush();
}
int responseCode = connection.getResponseCode();
System.out.println("Status Code: " + responseCode);
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = reader.readLine()) != null) {
response.append(inputLine);
}
reader.close();
System.out.println("Response: " + response.toString());
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
}
}
}<?php
$url = 'https://secure.payu.in/AuthorizeTransaction.php';
$data = array(
'key' => '{{key}}',
'txnid' => '{{txnid}}',
'authentication_info' => '{{info}}',
'hash' => '{{hash1}}',
'pg' => 'ApplePay',
'bankcode' => 'CCAP',
'firstname' => 'John',
'country' => 'IN',
'city' => 'Banglore',
'state' => 'KA',
'email' => '[email protected]',
'address1' => 'street1 area',
'udf1' => 'appleTransactionIdentifier',
'udf2' => 'MAST:credit',
'lastname' => 'Bing',
'zipcode' => '45678',
'phone' => '9876543210',
'productinfo' => 'ABC info',
'amount' => '{{amt}}'
);
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data)
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if ($result === FALSE) {
echo "Error: Failed to make request";
} else {
$http_response_header = $http_response_header ?? [];
$statusLine = $http_response_header[0] ?? 'Unknown status';
echo "Status: " . $statusLine . "\n";
echo "Response: " . $result;
}
?>Step 2: Check response from PayU
Hash validation logic for payment response (Reverse Hashing)
While sending the response, PayU takes the exact same parameters that were sent in the request (in reverse order) to calculate the hash and returns it to you. You must verify the hash and then mark a transaction as a success or failure. This is to make sure the transaction has not been tampered with in the response.
The order of the parameters is similar to the following:
sha512(SALT|status||||||udf5|udf4|udf3|udf2|udf1|email|firstname|productinfo|amount|txnid|key)Sample response (parsed)
Array
(
[mihpayid] => 403993715524045752
[mode] => APPLEPAY
[status] => success
[unmappedstatus] => captured
[key] => JP***g
[txnid] => txn_applepay_001
[amount] => 100.00
[discount] => 0.00
[net_amount_debit] => 100
[addedon] => 2024-01-15 10:30:00
[productinfo] => iPhone Case
[firstname] => John
[lastname] =>
[address1] =>
[address2] =>
[city] =>
[state] =>
[country] =>
[zipcode] =>
[email] => [email protected]
[phone] => 9876543210
[udf1] =>
[udf2] =>
[udf3] =>
[udf4] =>
[udf5] =>
[udf6] =>
[udf7] =>
[udf8] =>
[udf9] =>
[udf10] =>
[hash] => 1be7e6e97ab1ea9034b9a107e7cf9718308aa9637b4dbbd1a3343c91b0da02b34a40d00ac7267ebe81c20ea1129b931371c555d565bc6e11f470c3d2cf69b5a3
[field1] =>
[field2] =>
[field3] =>
[field4] =>
[field5] =>
[field6] =>
[field7] =>
[field8] =>
[field9] => Transaction Completed Successfully
[payment_source] => payu
[PG_TYPE] => APPLEPAY-PG
[bank_ref_num] => 87d3b2a1-5a60-4169-8692-649f61923b3d
[bankcode] => APPLEPAY
[error] => E000
[error_Message] => No Error
)Response parameters
| Parameter | Description | Example |
|---|---|---|
| mihpayid | String - This parameter contains the unique payment ID generated by PayU for this transaction. | 403993715524045752 |
| mode | String - This parameter contains the payment mode used for the transaction. For Apple Pay, this value is APPLEPAY. | APPLEPAY |
| status | String - This parameter contains the status of the transaction. Possible values: success, failure, pending. | success |
| unmappedstatus | String - This parameter contains the detailed status of the transaction. Possible values: captured, auth, bounced, dropped, etc. | captured |
| key | String - This parameter contains the merchant key. | JP***g |
| txnid | String - This parameter contains the transaction ID that was sent in the request. | txn_applepay_001 |
| amount | String - This parameter contains the transaction amount. | 100.00 |
| discount | String - This parameter contains the discount amount applied to the transaction. | 0.00 |
| net_amount_debit | String - This parameter contains the net amount debited from the customer. | 100 |
| addedon | String - This parameter contains the date and time when the transaction was added. | 2024-01-15 10:30:00 |
| productinfo | String - This parameter contains the product information sent in the request. | iPhone Case |
| firstname | String - This parameter contains the first name of the customer. | John |
| email | String - This parameter contains the email address of the customer. | [email protected] |
| phone | String - This parameter contains the phone number of the customer. | 9876543210 |
| hash | String - This parameter contains the hash value returned by PayU. You must validate this hash to ensure the response integrity. | 1be7e6e97... |
| field9 | String - This parameter contains additional information or error description returned by the bank or payment gateway. | Transaction Completed Successfully |
| payment_source | String - This parameter contains the source of the payment. | payu |
| PG_TYPE | String - This parameter contains the type of payment gateway used. For Apple Pay, this value is APPLEPAY-PG. | APPLEPAY-PG |
| bank_ref_num | String - This parameter contains the reference number returned by the bank for this transaction. | 87d3b2a1-5a60... |
| bankcode | String - This parameter contains the bank code used for the transaction. For Apple Pay, this value is APPLEPAY. | APPLEPAY |
| error | String - This parameter contains the error code. E000 indicates no error. | E000 |
| error_Message | String - This parameter contains the description of the error. | No Error |
Step 3: Verify the payment
Upon receiving the response, PayU recommends you performing a reconciliation step to validate all transaction details.
You can verify your payments using either of the following methods:
Configure the webhooks to monitor the status of payments.
Webhooks enable a server to communicate with another server by sending an HTTP callback or message.
These callbacks are triggered by specific events or instances and operate at the server-to-server (S2S) level.
Know how to manage Webhooks for Payments.
Updated 14 days ago
