SKU-Based Offer using Merchant Hosted Checkout

After you create a SKU-based offer on PayU Dashboard, you can start collecting payments for products with SKU-based offer. For more information on creating a SKU-based offer, refer to Create a SKU-Based Offer.

📘

Note:

For payment journey of instant discount offers using Merchant Hosted Checkout, refer to Instant Discount or Cashback using Merchant Hosted Checkout.

Steps to integrate

  1. Fetch offers
  2. Validate offer
  3. Payment request
  4. Check the response from PayU

Step 1: Fetch offers

Additional request parameter skusDetail for SKU

In addition to the request parameters listed in the Fetch Offers API section, the skusDetail parameter is posted with the following fields are posted in an array:

Field

Description

skuAmount optional

  • String_ The price of one/ single unit of SKU is specified in this field.

skuId
mandatory

  • String_ The product identifier to select offer is specified in this field.

quantity

optional

  • String_ The quantity for the product is specified in this field.****

offerKeys
optional

  • String The offer keys to filter at SKU-level is specified in this field.

skusDetail parameter in sample request

The sample request posted will include the skusDetail parameter similar to the following:

"skusDetail": [
    {
      "skuAmount": 600,
      "quantity": 3,
      "skuId": "123",
      "offerKeys": null
    }

Sample Response

"skusDetail": [
    {
      "skuAmount": 600,
      "quantity": 3,
      "skuId": "123",
      "offerKeys": null
    }

Step 2: Validate Offer

Additional request parameters

In addition to the request parameters listed in Validate Offer API, the skusDetail parameter with skus in an JSON array is posted, where each skus contain the following fields are posted in an array:

FieldDescription
autoApplyThe flag to specify to automatically apply the offer.
skuAmountThe price of one/ single unit of SKU is specified in this field.
offerKeysThe offer keys to filter at SKU-level is specified in this field.
quantityThe quantity for the product is specified in this field.
skuIdThe product identifier to select offer is specified in this field. For more information on creating a SKU offer.

skusDetail Object in request

  "skusDetail": {
    "skus": [
      {
      "autoApply": false,
        "skuAmount": 1000,
        "offerKeys": [
          "SummerSpecialOffer2021@q1Bh0jsogwqP"
        ],
        "quantity": 1,
        "skuId": "1"
      }
    ]
  }

skusDetail Object in response

        "skusDetail": {
            "skusDiscountDetail": {
                "totalCashbackDiscount": null,
                "totalInstantDiscount": 100,
                "totalDiscountedAmount": 900
            },
            "skus": [
                {
                    "skuId": "1",
                    "quantity": 1,
                    "name": "One Plus",
                    "skuAmount": 1000,
                    "isValid": true,
                    "autoApply": false,
                    "discountDetail": {
                        "offerKey": "SummerSpecialOffer2021@q1Bh0jsogwqP",
                        "offerType": "INSTANT",
                        "discount": 100,
                        "discountedAmount": 900,
                        "discountType": "PERCENTAGE"
                    },
         "offerDetail":{
         "offerId":10005,
         "offerKey":"SummerSpecialOffer2021@q1Bh0jsogwqP",
         "offerType":"INSTANT",
         "title":"SummerSpecialOffer",
         "description":"SummerSpecialOffer discount",
         "validFrom":"2021-07-01 17:02:11",
         "validTo":"2022-08-05 15:53:16",
         "tnc":"abc",
         "tncLink":"abcd",
         "discountType":"ABSOLUTE",
         "offerPercentage":null,
         "maxDiscountPerTxn":100.00,
         "minTxnAmount":10.00,
         "maxTxnAmount":25000.00,
         "status":"ACTIVE",
         "isNce":false,
         "disallowTransactionInvalidOffer": false,
         "isSkuOffer": true,
         "isSubventedOffer": true
      }

Step 3: Payment request

Additional request parameters for SKU-Based offer

📘

Reference:

For the checkout flow and list of request parameters required for the Offer integration, refer to Instant Discount or Cashback using Merchant Hosted Checkout.

Field

Description

cart_details mandatory for SKU

  • JSON Object_ The card details is specified in this parameter in a JSON format.
  • *Note**: If given null, no cart will be created for the transaction.

cart_details.amount
mandatory

  • String_ The amount for the SKU-based offer.

cart_details.items
mandatory

  • String_ The number of the items for the SKU-based offer.

cart_details.surcharges
conditional

  • String_ Total txn amount is now increased, but the cart_details.amount is lesser, to handle the difference, the additional amount added by the merchant should be passed in surcharges field

cart_details.pre_discount
conditional

  • String_ If there are any pre discount given by merchant on their checkout page. Total txn amount is now reduced, but the cart_details.amount is higher, to handle the difference, the discount given by the merchant should be passed in pre_discount field

cart_details.sku_details
mandatory

  • JSON Object_ The SKU details is specified in this parameter in a JSON format.

cart_details.sku_details.sku_id
mandatory

  • String_ This parameter contains the unique identifier for SKU.
  • *Note**: The Product ID in the Excel file as described in theCreate a SKU-Based Offer section and the **skuId** request parameter used in the Merchant Hosted Checkout Integration for SKU-based offer have the same function, Hence, after you create Product IDs on Dashboard, use them as values for the skuId parameter.

sku_details.sku_name
mandatory

  • String _ This parameter contains the SKU name.

sku_details.quantity
mandatory

  • String _ The parameter must contain the quantity of SKU added in cart.

sku_details.amount_per_sku
mandatory

  • String _ The parameter must contain the per SKU amount.

sku_details.offer_key
optional

  • String_ This parameter must contain the Offer Key(s) which can be used for this transaction. |

sku_details.offer_auto_apply
optional

  • String_This parameter contains the flag for when to enable auto application of best offer on this SKU.

Notes:

  • The following order must be used for hashing:
    key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5|udf6|udf7|udf8|udf9|udf10|offer_key|offer_auto_apply|SALT
    For more information on hash generation process, refer to Hashing Request and Response.
  • If any of the keys is null/not configured, "|" character must be concatenated.
  • The above hash logic is for _payment API version 10 or later.

cart_details Object in sample request

"cart_details": {
    "amount": 55000,
    "items": 2,
    "surcharges":"100",
    "pre_discount":"10"
    "sku_details": [
      {
        "sku_id": "smartphone234",
        "sku_name": "Smartphone",
        "amount_per_sku": "45000",
        "quantity": 1,
        "offer_key": null,
        "offer_auto_apply": true
      },
      {
        "sku_id": "smartwatch132",
        "sku_name": "Smartwatch",
        "amount_per_sku": "10000",
        "quantity": 1,
        "offer_key": [
          "flat500@2022"
        ],
        "offer_auto_apply": false
      }
    ]
  }

Sample Request with cart_details JSON object:

curl -X POST "https://test.payu.in/_payment" \
-H "accept: application/json" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "key=JP***g" \
-d "txnid=ewP8oRopzdHEtC" \
-d "amount=10.00" \
-d "firstname=Ashish" \
-d "[email protected]" \
-d "phone=9876543210" \
-d "productinfo=iPhone" \
-d "pg=TESTPG" \
-d "bankcode=TESTPGNB" \
-d "surl=https://apiplayground-response.herokuapp.com/" \
-d "furl=https://apiplayground-response.herokuapp.com/" \
-d 'cart_details={
  "amount": 55000,
  "items": 2,
  "surcharges": 10,
  "pre_discount": 5,
  "sku_details": [
    {
      "sku_id": "smartphone234",
      "sku_name": "Smartphone",
      "amount_per_sku": "45000",
      "quantity": 1,
      "offer_key": null,
      "offer_auto_apply": true
    },
    {
      "sku_id": "smartwatch132",
      "sku_name": "Smartwatch",
      "amount_per_sku": "10000",
      "quantity": 1,
      "offer_key": ["flat500@2022"],
      "offer_auto_apply": false
    }
  ]
}' \
-d "hash=bff508ec0974b20fe4be6c86cceab8c8dde88c4061a2a70373ddd0bbd3d24b21ae13984915fad06f9802f56b01a30da4e367e4e749959a76c3b2e5f12eb43319"
/**
 * PayU Card Payment with Cart Details using Fetch API
 * 
 * IMPORTANT: This should only be executed server-side (e.g., in Node.js), never in the browser,
 * as it contains sensitive payment information.
 */

// Payment endpoint
const url = 'https://test.payu.in/_payment';

// Cart details object
const cartDetails = {
  amount: 55000,
  items: 2,
  surcharges: 10,
  pre_discount: 5,
  sku_details: [
    {
      sku_id: "smartphone234",
      sku_name: "Smartphone",
      amount_per_sku: "45000",
      quantity: 1,
      offer_key: null,
      offer_auto_apply: true
    },
    {
      sku_id: "smartwatch132",
      sku_name: "Smartwatch",
      amount_per_sku: "10000",
      quantity: 1,
      offer_key: ["flat500@2022"],
      offer_auto_apply: false
    }
  ]
};

// Form data parameters
const formData = new URLSearchParams();
formData.append('key', 'JP***g');
formData.append('txnid', 'ewP8oRopzdHEtC');
formData.append('amount', '10.00');
formData.append('firstname', 'Ashish');
formData.append('email', '[email protected]');
formData.append('phone', '9876543210');
formData.append('productinfo', 'iPhone');
formData.append('pg', 'TESTPG');
formData.append('bankcode', 'TESTPGNB');
formData.append('surl', 'https://apiplayground-response.herokuapp.com/');
formData.append('furl', 'https://apiplayground-response.herokuapp.com/');
// Add cart details as JSON string
formData.append('cart_details', JSON.stringify(cartDetails));
formData.append('hash', 'bff508ec0974b20fe4be6c86cceab8c8dde88c4061a2a70373ddd0bbd3d24b21ae13984915fad06f9802f56b01a30da4e367e4e749959a76c3b2e5f12eb43319');

// Request options
const requestOptions = {
  method: 'POST',
  headers: {
    'accept': 'application/json',
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  body: formData
};

// Execute the request
fetch(url, requestOptions)
  .then(response => {
    console.log('Status Code:', response.status);
    return response.text(); // or response.json() if you're sure it returns JSON
  })
  .then(data => {
    console.log('Response:', data);
    // Process payment response here
  })
  .catch(error => {
    console.error('Error:', error);
  });
import urllib.request
import urllib.parse
import json
from typing import Dict, Any

def process_card_payment_with_cart_details() -> Dict[str, Any]:
    """
    Process card payment with cart details using PayU's Merchant Hosted Checkout
    
    IMPORTANT: This is a server-side function. Never expose payment details to client-side code.
    
    Returns:
        Dictionary with response from PayU API
    """
    # API endpoint
    url = "https://test.payu.in/_payment"
    
    # Cart details object
    cart_details = {
        "amount": 55000,
        "items": 2,
        "surcharges": 10,
        "pre_discount": 5,
        "sku_details": [
            {
                "sku_id": "smartphone234",
                "sku_name": "Smartphone",
                "amount_per_sku": "45000",
                "quantity": 1,
                "offer_key": None,
                "offer_auto_apply": True
            },
            {
                "sku_id": "smartwatch132",
                "sku_name": "Smartwatch",
                "amount_per_sku": "10000",
                "quantity": 1,
                "offer_key": ["flat500@2022"],
                "offer_auto_apply": False
            }
        ]
    }
    
    # Prepare the form data
    payload = {
        "key": "JP***g",
        "txnid": "ewP8oRopzdHEtC",
        "amount": "10.00",
        "firstname": "Ashish",
        "email": "[email protected]",
        "phone": "9876543210",
        "productinfo": "iPhone",
        "pg": "TESTPG",
        "bankcode": "TESTPGNB",
        "surl": "https://apiplayground-response.herokuapp.com/",
        "furl": "https://apiplayground-response.herokuapp.com/",
        # Add cart details as JSON string
        "cart_details": json.dumps(cart_details),
        "hash": "bff508ec0974b20fe4be6c86cceab8c8dde88c4061a2a70373ddd0bbd3d24b21ae13984915fad06f9802f56b01a30da4e367e4e749959a76c3b2e5f12eb43319"
    }
    
    # Convert dictionary to URL-encoded form data
    data = urllib.parse.urlencode(payload).encode('utf-8')
    
    # Set headers
    headers = {
        "accept": "application/json",
        "Content-Type": "application/x-www-form-urlencoded"
    }
    
    # Create a request object
    req = urllib.request.Request(url, data=data, headers=headers, method="POST")
    
    try:
        # Send the request and get the response
        with urllib.request.urlopen(req) as response:
            response_data = response.read().decode('utf-8')
            
            # Process and return response
            return {
                "status_code": response.getcode(),
                "response": response_data
            }
            
    except urllib.error.HTTPError as e:
        # Handle HTTP errors
        error_data = e.read().decode('utf-8')
        return {
            "status_code": e.code,
            "error": e.reason,
            "response": error_data
        }
        
    except Exception as e:
        # Handle other exceptions
        return {
            "status_code": 500,
            "error": str(e),
            "response": "An error occurred during payment processing"
        }

# Example usage
if __name__ == "__main__":
    result = process_card_payment_with_cart_details()
    print(f"Status Code: {result['status_code']}")
    if 'error' in result:
        print(f"Error: {result['error']}")
    print(f"Response: {result['response']}")
<?php
/**
 * Process card payment with cart details using PayU's Merchant Hosted Checkout
 * 
 * IMPORTANT: This is a server-side function. Never expose payment details to client-side code.
 * 
 * @return array Response from PayU API
 */
function processCardPaymentWithCartDetails() {
    // API endpoint
    $url = "https://test.payu.in/_payment";
    
    // Cart details object
    $cartDetails = [
        "amount" => 55000,
        "items" => 2,
        "surcharges" => 10,
        "pre_discount" => 5,
        "sku_details" => [
            [
                "sku_id" => "smartphone234",
                "sku_name" => "Smartphone",
                "amount_per_sku" => "45000",
                "quantity" => 1,
                "offer_key" => null,
                "offer_auto_apply" => true
            ],
            [
                "sku_id" => "smartwatch132",
                "sku_name" => "Smartwatch",
                "amount_per_sku" => "10000",
                "quantity" => 1,
                "offer_key" => ["flat500@2022"],
                "offer_auto_apply" => false
            ]
        ]
    ];
    
    // Prepare the form data
    $payload = [
        "key" => "JP***g",
        "txnid" => "ewP8oRopzdHEtC",
        "amount" => "10.00",
        "firstname" => "Ashish",
        "email" => "[email protected]",
        "phone" => "9876543210",
        "productinfo" => "iPhone",
        "pg" => "TESTPG",
        "bankcode" => "TESTPGNB",
        "surl" => "https://apiplayground-response.herokuapp.com/",
        "furl" => "https://apiplayground-response.herokuapp.com/",
        // Add cart details as JSON string
        "cart_details" => json_encode($cartDetails),
        "hash" => "bff508ec0974b20fe4be6c86cceab8c8dde88c4061a2a70373ddd0bbd3d24b21ae13984915fad06f9802f56b01a30da4e367e4e749959a76c3b2e5f12eb43319"
    ];
    
    // Initialize cURL session
    $ch = curl_init($url);
    
    // Set cURL options
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($payload));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        "accept: application/json",
        "Content-Type: application/x-www-form-urlencoded"
    ]);
    
    // For additional security in production
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
    
    // Execute the request
    $response = curl_exec($ch);
    $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    $errno = curl_errno($ch);
    
    // Close cURL session
    curl_close($ch);
    
    // Handle response
    if ($errno) {
        return [
            "status_code" => 500,
            "error" => $error,
            "response" => "cURL Error: " . $error
        ];
    }
    
    return [
        "status_code" => $statusCode,
        "response" => $response
    ];
}

// Example usage
$result = processCardPaymentWithCartDetails();
echo "Status Code: " . $result["status_code"] . "\n";
if (isset($result["error"])) {
    echo "Error: " . $result["error"] . "\n";
}
echo "Response: " . $result["response"] . "\n";
?>
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;
import java.util.HashMap;
import java.util.Map;
import java.util.StringJoiner;

// For JSON processing
import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonArrayBuilder;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;

/**
 * PayU Card Payment Processor with Cart Details for Merchant Hosted Checkout
 * 
 * IMPORTANT: This is a server-side implementation. Never expose payment details to client-side code.
 */
public class PayUCardPaymentProcessor {
    
    // API endpoint
    private static final String PAYU_TEST_URL = "https://test.payu.in/_payment";
    
    /**
     * Process card payment with cart details through PayU
     * @return PaymentResponse containing status and response data
     */
    public PaymentResponse processCardPaymentWithCartDetails() {
        try {
            // Initialize URL
            URL url = new URL(PAYU_TEST_URL);
            
            // Create cart details JSON
            JsonObjectBuilder cartDetailsBuilder = Json.createObjectBuilder()
                .add("amount", 55000)
                .add("items", 2)
                .add("surcharges", 10)
                .add("pre_discount", 5);
            
            // Create SKU details array
            JsonArrayBuilder skuDetailsBuilder = Json.createArrayBuilder();
            
            // First SKU item
            JsonObjectBuilder smartphone = Json.createObjectBuilder()
                .add("sku_id", "smartphone234")
                .add("sku_name", "Smartphone")
                .add("amount_per_sku", "45000")
                .add("quantity", 1)
                .addNull("offer_key")
                .add("offer_auto_apply", true);
            
            // Second SKU item
            JsonArrayBuilder offerKeys = Json.createArrayBuilder().add("flat500@2022");
            JsonObjectBuilder smartwatch = Json.createObjectBuilder()
                .add("sku_id", "smartwatch132")
                .add("sku_name", "Smartwatch")
                .add("amount_per_sku", "10000")
                .add("quantity", 1)
                .add("offer_key", offerKeys)
                .add("offer_auto_apply", false);
            
            // Add items to the SKU details array
            skuDetailsBuilder.add(smartphone);
            skuDetailsBuilder.add(smartwatch);
            
            // Finalize cart details JSON
            JsonObject cartDetails = cartDetailsBuilder
                .add("sku_details", skuDetailsBuilder)
                .build();
            
            // Prepare form parameters
            Map<String, String> params = new HashMap<>();
            params.put("key", "JP***g");
            params.put("txnid", "ewP8oRopzdHEtC");
            params.put("amount", "10.00");
            params.put("firstname", "Ashish");
            params.put("email", "[email protected]");
            params.put("phone", "9876543210");
            params.put("productinfo", "iPhone");
            params.put("pg", "TESTPG");
            params.put("bankcode", "TESTPGNB");
            params.put("surl", "https://apiplayground-response.herokuapp.com/");
            params.put("furl", "https://apiplayground-response.herokuapp.com/");
            // Add cart details as JSON string
            params.put("cart_details", cartDetails.toString());
            params.put("hash", "bff508ec0974b20fe4be6c86cceab8c8dde88c4061a2a70373ddd0bbd3d24b21ae13984915fad06f9802f56b01a30da4e367e4e749959a76c3b2e5f12eb43319");
            
            // Convert parameters to URL-encoded form data
            StringJoiner formData = new StringJoiner("&");
            for (Map.Entry<String, String> entry : params.entrySet()) {
                formData.add(URLEncoder.encode(entry.getKey(), "UTF-8") + "=" + 
                             URLEncoder.encode(entry.getValue(), "UTF-8"));
            }
            byte[] postData = formData.toString().getBytes(StandardCharsets.UTF_8);
            
            // Configure connection
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            conn.setRequestProperty("accept", "application/json");
            conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            conn.setRequestProperty("Content-Length", String.valueOf(postData.length));
            conn.setDoOutput(true);
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(15000);
            
            // Send request
            try (DataOutputStream dos = new DataOutputStream(conn.getOutputStream())) {
                dos.write(postData);
                dos.flush();
            }
            
            // Get response
            int responseCode = conn.getResponseCode();
            
            // Read response data
            StringBuilder response = new StringBuilder();
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(
                        responseCode >= 400 ? conn.getErrorStream() : conn.getInputStream(), 
                        StandardCharsets.UTF_8))) {
                        
                String line;
                while ((line = reader.readLine()) != null) {
                    response.append(line);
                }
            }
            
            return new PaymentResponse(responseCode, response.toString(), null);
            
        } catch (IOException e) {
            // Handle exception
            return new PaymentResponse(500, null, "Error: " + e.getMessage());
        }
    }
    
    /**
     * Payment response wrapper class
     */
    public static class PaymentResponse {
        private final int statusCode;
        private final String response;
        private final String error;
        
        public PaymentResponse(int statusCode, String response, String error) {
            this.statusCode = statusCode;
            this.response = response;
            this.error = error;
        }
        
        public int getStatusCode() {
            return statusCode;
        }
        
        public String getResponse() {
            return response;
        }
        
        public String getError() {
            return error;
        }
        
        public boolean isSuccess() {
            return statusCode >= 200 && statusCode < 300;
        }
    }
    
    // Example usage
    public static void main(String[] args) {
        PayUCardPaymentProcessor processor = new PayUCardPaymentProcessor();
        PaymentResponse result = processor.processCardPaymentWithCartDetails();
        
        System.out.println("Status Code: " + result.getStatusCode());
        if (result.isSuccess()) {
            System.out.println("Response: " + result.getResponse());
        } else {
            System.out.println("Error: " + result.getError());
        }
    }
}
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using System.Text;
using System.Text.Json;

namespace PayUCardIntegration
{
    /// <summary>
    /// PayU Card Payment Processor with Cart Details for Merchant Hosted Checkout
    /// 
    /// IMPORTANT: This is a server-side implementation. Never expose payment details to client-side code.
    /// </summary>
    public class PayUCardPaymentProcessor
    {
        // API endpoint
        private const string PayuTestUrl = "https://test.payu.in/_payment";
        
        /// <summary>
        /// Process card payment with cart details through PayU
        /// </summary>
        /// <returns>PaymentResponse containing status and response data</returns>
        public async Task<PaymentResponse> ProcessCardPaymentWithCartDetailsAsync()
        {
            try
            {
                // Create cart details object
                var cartDetails = new
                {
                    amount = 55000,
                    items = 2,
                    surcharges = 10,
                    pre_discount = 5,
                    sku_details = new[]
                    {
                        new {
                            sku_id = "smartphone234",
                            sku_name = "Smartphone",
                            amount_per_sku = "45000",
                            quantity = 1,
                            offer_key = (string)null,
                            offer_auto_apply = true
                        },
                        new {
                            sku_id = "smartwatch132",
                            sku_name = "Smartwatch",
                            amount_per_sku = "10000",
                            quantity = 1,
                            offer_key = new[] { "flat500@2022" },
                            offer_auto_apply = false
                        }
                    }
                };
                
                // Serialize cart details to JSON
                string cartDetailsJson = JsonSerializer.Serialize(cartDetails);
                
                // Prepare form parameters
                var formData = new Dictionary<string, string>
                {
                    { "key", "JP***g" },
                    { "txnid", "ewP8oRopzdHEtC" },
                    { "amount", "10.00" },
                    { "firstname", "Ashish" },
                    { "email", "[email protected]" },
                    { "phone", "9876543210" },
                    { "productinfo", "iPhone" },
                    { "pg", "TESTPG" },
                    { "bankcode", "TESTPGNB" },
                    { "surl", "https://apiplayground-response.herokuapp.com/" },
                    { "furl", "https://apiplayground-response.herokuapp.com/" },
                    // Add cart details as JSON string
                    { "cart_details", cartDetailsJson },
                    { "hash", "bff508ec0974b20fe4be6c86cceab8c8dde88c4061a2a70373ddd0bbd3d24b21ae13984915fad06f9802f56b01a30da4e367e4e749959a76c3b2e5f12eb43319" }
                };
                
                // Create HttpClient with timeout
                using (var httpClient = new HttpClient())
                {
                    httpClient.Timeout = TimeSpan.FromSeconds(30);
                    
                    // Convert form data to content
                    var content = new FormUrlEncodedContent(formData);
                    
                    // Add headers
                    content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
                    httpClient.DefaultRequestHeaders.Add("accept", "application/json");
                    
                    // Send POST request
                    var response = await httpClient.PostAsync(PayuTestUrl, content);
                    
                    // Get response content
                    var responseContent = await response.Content.ReadAsStringAsync();
                    
                    return new PaymentResponse(
                        (int)response.StatusCode,
                        responseContent,
                        null
                    );
                }
            }
            catch (Exception ex)
            {
                // Handle exception
                return new PaymentResponse(
                    500,
                    null,
                    $"Error: {ex.Message}"
                );
            }
        }
        
        /// <summary>
        /// Payment response wrapper class
        /// </summary>
        public class PaymentResponse
        {
            public int StatusCode { get; }
            public string Response { get; }
            public string Error { get; }
            
            public PaymentResponse(int statusCode, string response, string error)
            {
                StatusCode = statusCode;
                Response = response;
                Error = error;
            }
            
            public bool IsSuccess => StatusCode >= 200 && StatusCode < 300;
        }
    }
    
    // Example usage
    class Program
    {
        static async Task Main(string[] args)
        {
            var processor = new PayUCardPaymentProcessor();
            var result = await processor.ProcessCardPaymentWithCartDetailsAsync();
            
            Console.WriteLine($"Status Code: {result.StatusCode}");
            if (result.IsSuccess)
            {
                Console.WriteLine($"Response: {result.Response}");
            }
            else
            {
                Console.WriteLine($"Error: {result.Error}");
            }
        }
    }
}

Step 4: Check the response from PayU

You need to look for the skusDetail object in the response. For the complete response, refer to Merchant Hosted Checkout.

Success scenario

The skusDetail JSON in the following sample response:

{"cart_details": {
    "id": "18",
    "payu_id": "999000000000983",
    "total_items": "2",
    "total_cart_amount": "55000",
    "offer_applied": null,
    "offer_availed": null,
    "instant_discount": "1000",
    "cashback_discount": "500",
    "total_discount": "1500",
    "net_cart_amount": "54000",
    "created_at": null,
    "updated_at": null,
    "sku_details": [
      {
        "id": "35",
        "cart_id": "18",
        "payu_id": "999000000000983",
        "mid": "180012",
        "sku_id": "smartphone234",
        "sku_name": "Smartphone",
        "amount_per_sku": "45000.00",
        "quantity": "1",
        "amount_before_discount": "45000",
        "discount": "1000",
        "amount_after_discount": "44000",
        "offer_key": null,
        "offer_status": null,
        "offer_type": null,
        "created_at": null,
        "updated_at": null
      },
      {
        "id": "36",
        "cart_id": "18",
        "payu_id": "999000000000983",
        "mid": "180012",
        "sku_id": "smartwatch132",
        "sku_name": "Smartwatch",
        "amount_per_sku": "10000.00",
        "quantity": "1",
        "amount_before_discount": "10000.00",
        "discount": "500",
        "amount_after_discount": "10000.00",
        "offer_key": null,
        "offer_status": null,
        "offer_type": null,
        "created_at": null,
        "updated_at": null
      }
    ]
  }}

Step 5: Verify the payment

Verify the payment using the Verify Payment API. For the sample response using the Verify Payment API from PayU involving offers, refer to Additional Info for General APIsI.