Skip to main content

Signature Callback Validation

Signature validation is used to authenticate requests sent to the merchant callback url.

Public Key

In validating the callback signature, the merchant requires winpay's public key in the process. Production will be sent via email with a certain format.

Signature Formula

The signature on the callback validation takes data in the request header sent by winpay.


stringToSign = HTTPMethod +":"+ EndpointUrl +":"+ Lowercase(HexEncode(SHA-256(minify(RequestBody)))) + ":" + TimeStamp
signature = base64_decode(SHA256withRSA(private_key, stringToSign))

Source Code Signature Validation

Virtual Account

$path = '/sandbox_prod/url_listener.php/v1.0/transfer-va/payment';
$timestamp = '2024-01-11T08:57:55+07:00'; //ambil dari header X-Timestamp
$signature = 'Zng8tJgtK2lPd8CP89KyO1OGEKXn1tFfXevTGIn5IhHYDpobp7+4uvuczP5HwldghO5mzkh03v6wnggoZev8M2RyKegbrRaIr66KbAgr6sfKfH9MfkXFcEKpF/am8QMr4oExKPdYTdGEr6pq6m1CzUjFQsyu9z6JuMGrjXrxFXU='; //ambil dari header X-Signature
$httpMethod = 'POST';
$partnerId = '170041'; //ambil dari header X-Partner-Id
$body = [
"partnerServiceId"=> " 9042",
"customerNo"=> "00000009",
"virtualAccountNo"=> " 904200000009",
"virtualAccountName"=> "WINPAY - fiandi",
"trxId"=> "INV-000000023220",
"paymentRequestId"=> "45539",
"paidAmount"=> [
"value"=> "10000.00",
"currency"=> "IDR"
],
"trxDateTime"=> "2024-01-11T08:57:55+07:00",
"additionalInfo"=> [
"contractId"=> "si1cd5671d-2ffe-4cca-aff0-b8ee9bc1c041",
"channel"=> "BSI"
]
];

$payload = json_encode($body, JSON_UNESCAPED_SLASHES);

$stringToSignArr = [
$httpMethod,
$path,
strtolower(bin2hex(hash('sha256', $payload, true))),
$timestamp
];

$stringToSign = implode(':', $stringToSignArr);

try {
$publicKey = openssl_get_publickey($publicKey);
$verify = openssl_verify($stringToSign, base64_decode($signature), $publicKey, OPENSSL_ALGO_SHA256);

if($verify !== 1){
$response = [
'message' => 'Cannot verify signature'
];

print_r($response);
} else {
$response = [
'responseCode' => '2002500',
'responseMessage' => 'Successful'
];

print_r($response);
}


} catch(Exception $e) {
$response = [
'message' => 'Invalid signature {'.$e->getMessage().'}'
];

print_r($response);
}

E-Wallet

$path = '/v1/test';
$timestamp = '2024-01-11T17:01:35+07:00'; //ambil dari header X-Timestamp
$signature = 'SbplyMG0x4igUO8ZqkgUDqNXIzZ6eryz1eNWFfUT499/ulgCLKDJifPtdQH/WBWg5BnKTn+AaKK6inll7h7gJbojC/85TH1QNFnzz8fR4ds+BmFhQaYhys1G5upm4h9x/2hFIznFsEYlc+Ggljs5kXi9wezsltlEkAf5w6snCf4='; //ambil dari header X-Signature
$httpMethod = 'POST';
$partnerId = '170041'; //ambil dari header X-Partner-Id
$body = [
"originalPartnerReferenceNo"=> "0000000000591y",
"originalReferenceNo"=> "45588",
"merchantId"=> 170041,
"amount"=> [
"value"=> "1000",
"currency"=> "IDR"
],
"latestTransactionStatus"=> "00",
"additionalInfo"=> [
"channel"=> "OVO",
"contractId"=> "ovb7b5599b-cce7-4f0f-8c34-fa283185945b"
]
];

$payload = json_encode($body, JSON_UNESCAPED_SLASHES);

$stringToSignArr = [
$httpMethod,
$path,
strtolower(bin2hex(hash('sha256', $payload, true))),
$timestamp
];

$stringToSign = implode(':', $stringToSignArr);

try {
$publicKey = openssl_get_publickey($publicKey);
$verify = openssl_verify($stringToSign, base64_decode($signature), $publicKey, OPENSSL_ALGO_SHA256);

if($verify !== 1){
$response = [
'message' => 'Cannot verify signature'
];

print_r($response);
} else {
$response = [
'responseCode' => '2005600',
'responseMessage' => 'Successful'
];

print_r($response);
}


} catch(Exception $e) {
$response = [
'message' => 'Invalid signature {'.$e->getMessage().'}'
];

print_r($response);
}

QRIS

$path = '/sandbox_prod/url_listener.php/v1.0/qr/qr-mpm-notify';
$timestamp = '2024-01-11T16:36:57+07:00'; //ambil dari header X-Timestamp
$signature = 'Zeqi6FIJ1Po8JU2tc0yqfqEbiHNfBYkvesbKIcPIEomsBpqriWrD5cqMH2Tb8Ys8U5CSqBhSliM8KnQ0YIyk444mCEe4M4eKnGVYA3YVfE3Bg1IOviugqzCeNPKxU8kxARdaXVlCo7s+tA9roHt+fE5ZTRYeGkAEC3ChM8277aI='; //ambil dari header X-Signature
$httpMethod = 'POST';
$partnerId = '170041'; //ambil dari header X-Partner-Id
$body = [
"originalReferenceNo"=> "45584",
"originalPartnerReferenceNo"=> "abctoxfzxc",
"latestTransactionStatus"=> "00",
"amount"=> [
"value"=> "45000",
"currency"=> "IDR"
],
"additionalInfo"=> [
"channel"=> "QRIS",
"contractId"=> "qr748ad360-9755-40af-a201-e44b45c4568f",
"brandName"=> "DANA",
"rrn"=> "027364710019",
"buyerRef"=> "WINPAY",
"terminalId"=> null
]
];

$payload = json_encode($body, JSON_UNESCAPED_SLASHES);

$stringToSignArr = [
$httpMethod,
$path,
strtolower(bin2hex(hash('sha256', $payload, true))),
$timestamp
];

$stringToSign = implode(':', $stringToSignArr);

try {
$publicKey = openssl_get_publickey($publicKey);
$verify = openssl_verify($stringToSign, base64_decode($signature), $publicKey, OPENSSL_ALGO_SHA256);

if($verify !== 1){
$response = [
'message' => 'Cannot verify signature'
];

print_r($response);
} else {
$response = [
'responseCode' => '2005200',
'responseMessage' => 'Successful'
];

print_r($response);
}


} catch(Exception $e) {
$response = [
'message' => 'Invalid signature {'.$e->getMessage().'}'
];

print_r($response);
}