Skip to main content

Authentication

The Legacy API uses two different authentication schemes depending on the endpoint group.

Order Endpoints — SHA-512 Signature

Order endpoints (/api/order/*) are authenticated via a SHA-512 hash included in the request body.

Formula

signature = lowercase_hex( SHA512( clientId + "|" + orderId + "|" + totalAmount + "|" + clientSecret ) )
  • clientId — your legacy_client_id
  • orderId — the merchant order ID from the request body
  • totalAmount — the full IDR integer from the request body (not minor units)
  • clientSecret — your legacy_client_secret
  • Fields are joined with pipe | characters (no spaces)

Code Samples

PHP
function signOrder(string $clientId, string $orderId, int $totalAmount, string $clientSecret): string
{
$parts = implode('|', [$clientId, $orderId, (string)$totalAmount, $clientSecret]);
return hash('sha512', $parts);
}

// Usage:
$signature = signOrder('TEST_CLIENT_001', 'INV-2026-00123', 100000, 'TEST_SECRET_001');
Node.js
const crypto = require('crypto');

function signOrder(clientId, orderId, totalAmount, clientSecret) {
const parts = [clientId, orderId, String(totalAmount), clientSecret].join('|');
return crypto.createHash('sha512').update(parts).digest('hex');
}

// Usage:
const signature = signOrder('TEST_CLIENT_001', 'INV-2026-00123', 100000, 'TEST_SECRET_001');
cURL (compute then send)
SIGNATURE=$(echo -n "TEST_CLIENT_001|INV-2026-00123|100000|TEST_SECRET_001" | sha512sum | awk '{print $1}')
caution

totalAmount must be exactly the integer value you send in the request body. A mismatch (e.g., different whitespace or rounding) will cause an Invalid Signature error.


Disbursement Endpoints — RSA-SHA256 X-SIGNATURE

Disbursement endpoints (/api/disbursement/*) require an X-SIGNATURE header signed with your RSA private key.

How It Works

  1. Minify your JSON request body (compact, no extra whitespace)
  2. Compute bodyHash = lowercase_hex( SHA256( minified_body ) )
  3. Build the string to sign: stringToSign = clientId + "|" + clientSecret + "|" + bodyHash
  4. Sign it: rawSig = RSA_SHA256_sign( stringToSign, yourPrivateKey )
  5. Encode: X-SIGNATURE: base64( rawSig )

The server verifies using your public key which you upload to the platform dashboard.

Generating Your RSA Key Pair

Generate RSA-2048 key pair
# Generate private key (keep this secret, never share)
openssl genrsa -out private.pem 2048

# Extract public key (upload this to the Admin Dashboard)
openssl rsa -in private.pem -pubout -out public.pem

Upload the contents of public.pem to the Admin Dashboard → Merchants → Your Merchant → Legacy Credentials.

Code Samples

PHP
function signDisbursement(array $body, string $clientId, string $clientSecret, string $privateKeyPem): string
{
$minifiedBody = json_encode($body, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$bodyHash = hash('sha256', $minifiedBody);
$stringToSign = implode('|', [$clientId, $clientSecret, $bodyHash]);

$privateKey = openssl_pkey_get_private($privateKeyPem);
openssl_sign($stringToSign, $rawSig, $privateKey, OPENSSL_ALGO_SHA256);
return base64_encode($rawSig);
}

// Usage:
$xSignature = signDisbursement(
['clientId' => 'TEST_CLIENT_001', 'orderId' => 'DISB-001', ...],
'TEST_CLIENT_001',
'TEST_SECRET_001',
file_get_contents('private.pem')
);

// Send as header: X-SIGNATURE: <value>
Node.js
const crypto = require('crypto');
const fs = require('fs');

function signDisbursement(body, clientId, clientSecret, privateKeyPem) {
const minifiedBody = JSON.stringify(body);
const bodyHash = crypto.createHash('sha256').update(minifiedBody).digest('hex');
const stringToSign = [clientId, clientSecret, bodyHash].join('|');

return crypto.sign('sha256', Buffer.from(stringToSign), privateKeyPem).toString('base64');
}

// Usage:
const privateKey = fs.readFileSync('private.pem', 'utf8');
const xSignature = signDisbursement(requestBody, clientId, clientSecret, privateKey);

// Add to request: 'X-SIGNATURE': xSignature
Important: Body Consistency

The JSON body you hash must be byte-for-byte identical to the body you send in the HTTP request. Build the body object once, stringify it once, use that same string for both hashing and the request body.

Common Errors

MessageCause
Invalid Client IDclientId not found or merchant inactive
Invalid X-SIGNATURESignature verification failed (wrong key or mismatched body)
Public Key is not setNo RSA public key uploaded for this merchant