Fiat Currency Asynchronous Notification

# Asynchronous Notification of Collection

This interface is provided by the merchant. The platform requests this interface when the collection is successful When an HTTP request is received, please respond with httpcode=200 (HTTP Response Status Code). Otherwise, 16 notifications will be repeatedly sent within 5 hours.

⚠️⚠️Note: Users might only pay part of the amount, so it is necessary to check the 'actual payment amount'.⚠️⚠️

# Best Practice

  1. To determine successful payment, the orderStatus is 1.
  2. For partial payment determination: orderStatus is 3. Merchants should handle this according to their own business logic.
  3. On refund determination: orderStatus is 2. This situation generally occurs in case of customer complaints and bank risk control returns. Merchants should record related information and handle it according to their own business processes (a callback success will be received before getting this callback status).
  4. If the merchant's business logic fails to process, please change the HTTP response status code to 400 or 500 (non-200).
  5. Cheezeepay may send multiple callbacks with the same status. The merchant should handle this compatibility accordingly. If the merchant's own business has been processed successfully, they must return the HTTP response status code to 200.
  6. Please ensure to verify the callback IP➕signature verification.
Parameter Type Required Description Example
merchantId string Y Merchant ID CH10001165
mchOrderNo string Y Merchant Order Number C202401090023
platOrderNo string Y Platform Order Number 1746060142200229888
orderStatus int Y Order Status 1-Success 2-Refund 3-Partial Payment
payAmount string Y Order Actual Payment Amount 800
amountCurrency string Y Order Amount Currency INR
fee string Y Handling Fee 88
feeCurrency string Y Handling Fee Currency INR
payerUpiId string N Payer UPIID (not a required field) xxxxxx1@iob
gmtEnd long Y Completion Time (Timestamp: Milliseconds) 1705128180000
sign string Y Signature EcCs7GlN1UzEAflgpyJ4lKIHe9+lS/gdkcEvWI
+nSlcvvz1c+Dg4Zi8sFmpYaoOMGxS3/BY66F
Gq2TXzVGhAciq2kFmwZFtYbFvr7xPTaNf/n0R
u7ZtV/jo3uBnfc9/JI6XlEWlIbPtGsVpH7CLhzgh
dqIT+YbPEdhX2ZKETFTTfIj6PzctY9eOsZ51Yb
HYnXv0jTWn1hdPoDofAF9RmoNaXK4FGYibQ
BSvVA6w4rM6hCXlbTeHdMc4askrZlrHeG3uhyD
34VlXs74cdzAZ+oROMXBcgXR4ObsJVDFz9tsJ
H92iaxlKTF0lEFZa/To5ezLpHvTOAK0uY/K6IxvO
AAg==

# Asynchronous Notification Message Example

{
  "merchantId":"CH10001165",
  "mchOrderNo":"C202401090023",
  "platOrderNo":"1746060142200229888",
  "orderStatus":1,
  "payAmount":"800",
  "amountCurrency":"INR",
  "fee":"88",
  "feeCurrency":"INR",
  "payerUpiId": "xxxxxx1@iob",
  "gmtEnd":1705128180000,
  "sign":"EcCs7GlN1UzEAflgpyJ4lKIHe9+lS/gdkcEvWI+nSlcvvz1c+Dg4Zi8sFmpYaoOMGxS3/BY66FGq2TXzVGhAciq2kFmwZFtYbFvr7xPTaNf/n0Ru7ZtV/jo3uBnfc9/JI6XlEWlIbPtGsVpH7CLhzghdqIT+YbPEdhX2ZKETFTTfIj6PzctY9eOsZ51YbHYnXv0jTWn1hdPoDofAF9RmoNaXK4FGYibQBSvVA6w4rM6hCXlbTeHdMc4askrZlrHeG3uhyD34VlXs74cdzAZ+oROMXBcgXR4ObsJVDFz9tsJH92iaxlKTF0lEFZa/To5ezLpHvTOAK0uY/K6IxvOAAg=="
}

# Asynchronous Notification Code Implementation Demo

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

@RestController
@RequestMapping("callback")
public class TestCallbackController {

    /**
     * Platform public key
     */
    public static String PLATFORM_PUB_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1dad35S74jfLPbHJh8P0jDHiTvkxwrtITK97ovVu19B24UdiHyHoEZgtNlS6alFQj1ULQ71d6EPh2rWCNkS2b5HGQXwDYBtwvesVQ8h4Sf3eVPTTLGw3BS7Os4vtDEN6BezMdv3sUG2N5i6JF+5H4CQTq3MD2Cx6u/Cv7oFOdFqeDT0AH+TR7uyZxn69OtkJaHHr834EUcdShJKKMQtbC11WCcut7ilDUgdvZnThiVTq7cfl8mcC9FDKcQ9bMWamScWIB5cJQdUW23Kr0c1NvZlpgPS8U5VODM4Uc4muHJPD2cJmquuJ+4AGP36rEk27lUB3h7B6JI1QGiuh1yyPDwIDAQAB";

    /**
     * payInCallback
     * @param paramMap
     * @param response
     */
    @PostMapping("payIn")
    public void payInCallback(@RequestBody Map<String, Object> paramMap, HttpServletResponse response) throws Exception{
        boolean verifyResult = CheeseTradeRSAUtil.verifySign(paramMap, PLATFORM_PUB_KEY);
        if (verifyResult) {
            //Signature verification successful
            //Order notification business processing logic
            String merchantId = (String)paramMap.get("merchantId");
            String mchOrderNo = (String)paramMap.get("mchOrderNo");
            String platOrderNo = (String)paramMap.get("platOrderNo");
            Integer orderStatus = (Integer)paramMap.get("orderStatus");
            String payAmount = (String)paramMap.get("payAmount");
            String amountCurrency = (String)paramMap.get("amountCurrency");
            String fee = (String)paramMap.get("fee");
            String feeCurrency = (String)paramMap.get("feeCurrency");
            //payerUpiId——Please note that this parameter is not required
            String payerUpiId = paramMap.containsKey("payerUpiId") ? (String) paramMap.get("payerUpiId") : "";
            Long gmtEnd = (Long)paramMap.get("gmtEnd");
        } else {
            //Signature verification failed
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
        }
    }

}
<?php
//This code has been verified in PHP5.6 version
class TestCallbackController 
{

    /**
     * Platform public key
     */
    const PLATFORM_PUB_KEY = '-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyVqixSZsLJ75yL7r1SwFn0QsOrDAIv4JU6PCIyLwH5Y1m7QY3nm5k+D4VX9qNvTq9R6CT9fPuXH8AVfx7iDCahHA0j//SiTUNlRqgXZVwrhYoytW4PqSl8+QkMimS6Mm9zPC8JsyaUrv0DfIfVxLPZ42JMrKo6+/neIORTduhyO8VYcfNbFAa+fzKl1B0dmXyvat9BmMDYexKPtqKb3WkXKzAERPSizdbib6GvpV6boEnEDlyLT32rtWNEb26NWvmyiaQjBb2J32sDHSPga5kOT8L1dyi3YA4T2JtHMCAMyw9hPz7tjtl1XwSBsJ3h4q9Zra6G2K+NfPxQsBIFVgtwIDAQAB
-----END PUBLIC KEY-----';

    /**
     * payInCallback
     * @param paramMap
     * @param response
     */
    public function payInCallback($paramMap, $response) {
        //Sign
        $Sign = $paramMap["sign"];
        
        //$paramMap need remove sign
        unset($paramMap['sign']); 
        
        //Splicing callback parameters
        $keys = array_keys($paramMap);
        sort($keys);
        $str = '';
        foreach ($keys as $key) {
            $str .=  $key . '=' . $paramMap[$key] . '&';
        }
        $str = rtrim($str, '&');
        echo $str;

        //Verify the signature    
        $verifyResult = verifySign($str,$Sign ,self::PLATFORM_PUB_KEY);
        if ($verifyResult) {
        //Verification is successful, you can implement your logic
            //Signature verification successful
            //Order notification business processing logic
            $merchantId = $paramMap["merchantId"];
            $mchOrderNo = $paramMap["mchOrderNo"];
            $platOrderNo = $paramMap["platOrderNo"];
            $orderStatus = $paramMap["orderStatus"];
            $payAmount = $paramMap["payAmount"];
            $amountCurrency = $paramMap["amountCurrency"];
            $fee = $paramMap["fee"];
            $feeCurrency = $paramMap["feeCurrency"];
            //payerUpiId——Please note that this parameter is not required
            $payerUpiId = isset($paramMap["payerUpiId"]) ? (string) $paramMap["payerUpiId"] : "";
            $gmtEnd = $paramMap["gmtEnd"];
        //After implementing the logic, we finally need to return an HTTP200 response to us.
        } else {
            //Signature verification failed
            http_response_code(400);
        }
    }

}
//校验签名
function verifySign($data, $sign, $pubKey){
    $sign = base64_decode($sign);
    $key = openssl_pkey_get_public($pubKey);
    $result = openssl_verify($data, $sign, $key, OPENSSL_ALGO_SHA256) === 1;
    return $result;
}

?>

const express = require('express');
const bodyParser = require('body-parser');
//The functions of the introduced signature tool class (CheeseTradeRSAUtil). 
//The signature tool class can refer to the DEMO in "Signature & Verification Algorithm"
const  {verifySign}= require('./CheeseTradeRSAUtil');

const app = express();
//Parsing JSON request body
app.use(bodyParser.json()); 

// Platform public key
const platPublicKey = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1dad35S74jfLPbHJh8P0jDHiTvkxwrtITK97ovVu19B24UdiHyHoEZgtNlS6alFQj1ULQ71d6EPh2rWCNkS2b5HGQXwDYBtwvesVQ8h4Sf3eVPTTLGw3BS7Os4vtDEN6BezMdv3sUG2N5i6JF+5H4CQTq3MD2Cx6u/Cv7oFOdFqeDT0AH+TR7uyZxn69OtkJaHHr834EUcdShJKKMQtbC11WCcut7ilDUgdvZnThiVTq7cfl8mcC9FDKcQ9bMWamScWIB5cJQdUW23Kr0c1NvZlpgPS8U5VODM4Uc4muHJPD2cJmquuJ+4AGP36rEk27lUB3h7B6JI1QGiuh1yyPDwIDAQAB
-----END PUBLIC KEY-----`;

// callback interface
app.post('/callback/payIn', (req, res) => {
    const paramMap = req.body; // Get the parameters in the request body

    try {
        const verifyResult = verifySign(paramMap,platPublicKey);
        if (verifyResult) {
            // Signature verification successful
            const merchantId = paramMap.merchantId;
            const mchOrderNo = paramMap.mchOrderNo;
            const platOrderNo = paramMap.platOrderNo;
            const orderStatus = paramMap.orderStatus;
            const payAmount = paramMap.payAmount;
            const amountCurrency = paramMap.amountCurrency;
            const fee = paramMap.fee;
            const feeCurrency = paramMap.feeCurrency;
            //payerUpiId——Please note that this parameter is not mandatory.
            const payerUpiId = paramMap.payerUpiId || ''; 
            const gmtEnd = paramMap.gmtEnd;

            // Order notification business processing logic
            console.log('Signature verification successful, order processed:', {
                merchantId,
                mchOrderNo,
                platOrderNo,
                orderStatus,
                payAmount,
                amountCurrency,
                fee,
                feeCurrency,
                payerUpiId,
                gmtEnd,
            });

            // Return a successful response
            res.status(200).json({ message: 'Successful processing' });
        } else {
            // Signature verification failed
            res.status(400).json({ message: 'Signature verification failed' });
        }
    } catch (error) {
        // Handling Exceptions
        console.error('An error occurred while processing the callback:', error);
        res.status(500).json({ message: 'Internal server error' });
    }
});