Fiat Currency Disbursement Asynchronous Notification

# Asynchronous Notification of Disbursement

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.

# Best Practice

  1. For determining success, orderStatus is 1.
  2. On refund determination: orderStatus is 2. This situation generally occurs in case of user 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).
  3. If the merchant's business logic fails to process, please change the HTTP response status code to 400 or 500 (non-200).
  4. 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.
  5. 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 20240109021317
platOrderNo String Y Platform Order Number 1746070852804415488
orderStatus int Y Order Status 1-Success 2-Refund 4-Failure
payAmount String Y Order Actual Payment Amount 900
amountCurrency String Y Order Amount Currency INR
fee String Y Handling Fee 90
feeCurrency String Y Handling Fee Currency INR
gmtEnd long Y Completion Time (Timestamp: Milliseconds) 1705130760000
sign String Y Signature uoEdxeji3auJ0GwrBGTBZBqKw+kwrxIgomNI0
uaViTMSvzRZZcySg3LKs9t0G95ksPL89EqgA
C9VVIclSLNulbJ+g3oQKD5OpEHS0X6M8BnS
li+7tkesbpI7jcG6LvGF3r7PkfSImYFtVgK4Ink3T
11e6+slsLcjDHW5rYqxSkaFRHN049GgazsO82
UHwEntWQH50lGaaRIegVtf8ra3c9xo3pZ4TMlH
74Ce3kMffCw37D2trtuUQA9TBdHn6bWrNbpwv
gKlxtb6HJBNDurdz74s1t4gl6g5YVnvS1EaOz3/M
u0n1ipcJ5qfppzJZmr/unVfyumqfi8yJPDLPXSwug==

# Asynchronous Notification Message Example

{
    "merchantId":"CH10001165",
    "mchOrderNo":"20240109021317",
    "platOrderNo":"1746070852804415488",
    "orderStatus":1,
    "payAmount":"900",
    "amountCurrency":"INR",
    "fee":"90",
    "feeCurrency":"INR",
    "gmtEnd":1705130760000,
    "sign":"uoEdxeji3auJ0GwrBGTBZBqKw+kwrxIgomNI0uaViTMSvzRZZcySg3LKs9t0G95ksPL89EqgAC9VVIclSLNulbJ+g3oQKD5OpEHS0X6M8BnSli+7tkesbpI7jcG6LvGF3r7PkfSImYFtVgK4Ink3T11e6+slsLcjDHW5rYqxSkaFRHN049GgazsO82UHwEntWQH50lGaaRIegVtf8ra3c9xo3pZ4TMlH74Ce3kMffCw37D2trtuUQA9TBdHn6bWrNbpwvgKlxtb6HJBNDurdz74s1t4gl6g5YVnvS1EaOz3/Mu0n1ipcJ5qfppzJZmr/unVfyumqfi8yJPDLPXSwug=="
}

# 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";

    /**
     * payOutCallback
     * @param paramMap
     * @param response
     */
    @PostMapping("payOut")
    public void payOutCallback(@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");
            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"];
            $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/payOut', (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;
            const gmtEnd = paramMap.gmtEnd;

            // Order notification business processing logic
            console.log('Signature verification successful, order processed:', {
                merchantId,
                mchOrderNo,
                platOrderNo,
                orderStatus,
                payAmount,
                amountCurrency,
                fee,
                feeCurrency,
                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' });
    }
});