Security
Overview
All requests between Baokim and CashPlus are digitally signed using RSA with SHA1 hash:
| Direction | Signer | Key for signing | Verifier | Key for verification |
|---|---|---|---|---|
| CashPlus → Baokim (API call) | CashPlus | CashPlus's private key | Baokim | CashPlus's public key registered with Baokim |
| Baokim → CashPlus (webhook) | Baokim | Baokim's private key | CashPlus | Baokim's public key provided |
- Signature in
Signatureheader, Base64 encoded. Never put signature in body. - Data being signed is raw request body, exact bytes sent. No reformatting, no whitespace changes, no field reordering after signing.
- Only SHA1 supported. Signatures created with other algorithms rejected with code 120.
- Test and production environments have different keys. Contact Baokim to exchange public keys for each environment.
CashPlus Calls Baokim API
Applies to all APIs in this documentation:
POST /collection/{env}/users
POST /collection/{env}/v1
POST /transaction/v2/share-amount
POST /transaction/v2/spend
POST /transaction/v2/spend-result
POST /ats/transaction
POST /ats/transaction-payment-share
POST /ats/merchant
POST /ats/user
Step 1. Create request body JSON — this is the exact string to send:
{"RequestId":"ABC123","RequestTime":"2025-01-15 10:30:00","PartnerCode":"CASHPLUS","Data":[]}
Step 2. Sign the body string using CashPlus's private key, RSA-SHA1 algorithm, then Base64 encode:
$body = json_encode($data);
openssl_sign($body, $signature, $privateKey, OPENSSL_ALGO_SHA1);
$signatureBase64 = base64_encode($signature);
Step 3. Send the exact body string with Signature header:
curl -X POST '{BASE_URL}/collection/live/v1' \
-H 'Content-Type: application/json' \
-H 'Signature: <signatureBase64>' \
-d '{"RequestId":"ABC123","RequestTime":"2025-01-15 10:30:00","PartnerCode":"CASHPLUS","Data":[]}'
Invalid signature or missing Signature header → Baokim returns code 120.
CashPlus Receives Webhook from Baokim
Applies to Collection webhook and Disbursement result webhook.
Baokim sends:
- Header
Content-Type: application/json - Header
Signature: <Base64 of RSA-SHA1 signature on raw body>
CashPlus verifies on raw body received (not parsed then re-encoded):
$rawBody = file_get_contents('php://input');
$signature = base64_decode($_SERVER['HTTP_SIGNATURE'] ?? '');
$isValid = openssl_verify($rawBody, $signature, $baokimPublicKey, OPENSSL_ALGO_SHA1);
if ($isValid !== 1) {
// Invalid signature: do not process, return non-200 ResponseCode
}
$data = json_decode($rawBody, true);
Response format and retry policy: see each webhook's documentation page.
Node.js Example
const crypto = require('crypto');
// CashPlus signs request to Baokim
function signBody(body, privateKeyPem) {
const signer = crypto.createSign('RSA-SHA1');
signer.update(body, 'utf8');
return signer.sign(privateKeyPem, 'base64');
}
// CashPlus verifies webhook from Baokim
function verifyWebhook(rawBody, signatureBase64, baokimPublicKeyPem) {
const verifier = crypto.createVerify('RSA-SHA1');
verifier.update(rawBody, 'utf8');
return verifier.verify(baokimPublicKeyPem, signatureBase64, 'base64');
}
const body = JSON.stringify({
RequestId: 'ABC123',
RequestTime: '2025-01-15 10:30:00',
PartnerCode: 'CASHPLUS',
Data: []
});
fetch('{BASE_URL}/collection/live/v1', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Signature': signBody(body, privateKeyPem) },
body // send exact string that was signed
});