SNAP BI signatures can feel confusing because they combine several ideas at once:

  • HTTP method;
  • URL path;
  • request body hash;
  • timestamp;
  • RSA private and public keys;
  • a signature header.

When all of those appear together, it is easy to get lost. The SNAP BI Asymmetric Signature tool is useful because it shows the signing input and lets you sign or verify it step by step.

This post explains the idea in plain language first, then walks through the testing flow.

The simple idea

A signature is a way to prove two things:

  1. the request was created by someone holding the private key;
  2. the important request data was not changed after signing.

In SNAP BI asymmetric signing, the client signs a prepared text using an RSA private key. The receiver verifies the signature using the matching public key.

Simple mental model:

private key = used to sign
public key  = used to verify

Do not share the private key. The public key is the one you give to the other side for verification.

What “asymmetric” means

“Asymmetric” means signing and verifying use different keys.

With HMAC, both sides share the same secret. With asymmetric signing, the signer keeps the private key, and the verifier uses the public key.

That is useful for API integrations because the verifier does not need to know the private key. If the public key verifies the signature, the request must have been signed by the matching private key.

What SHA256withRSA means

SHA256withRSA sounds complicated, but it can be read in two parts:

  1. hash the signing text with SHA-256;
  2. sign that hash with an RSA private key.

The signature is usually sent as Base64 text so it can fit safely inside an HTTP header.

You do not need to manually do every cryptographic step. The important part is that both sides must build the exact same signing text before signing or verifying.

Step 1: collect the request parts

Before signing, write down the request details.

Example:

HTTP method: POST
Path: /snap/v1.0/transfer-va/payment
Timestamp: 2026-09-27T10:00:00+07:00

Then prepare the request body:

{
  "partnerReferenceNo": "INV-1001",
  "amount": {
    "value": "10000.00",
    "currency": "IDR"
  }
}

Be careful with the path. Usually the signing input expects the path and query, not the full domain. For example:

/snap/v1.0/transfer-va/payment

not:

https://api.example.com/snap/v1.0/transfer-va/payment

Always follow the exact integration spec you are implementing.

Step 2: understand the body hash

Many SNAP BI signature flows include a hash of the request body.

The purpose is simple:

If the body changes, the body hash changes. If the hash changes, the signature no longer matches.

This protects the body from being silently modified.

A common problem is hashing a different body than the one actually sent.

For example, these two JSON bodies mean the same thing to a JSON parser, but they are different text:

{"amount":10000}
{
  "amount": 10000
}

Depending on the required canonicalization rules, whitespace and formatting may matter before hashing. The safest habit is to sign exactly the body string you will send.

Step 3: build the string to sign

The string to sign is the exact text that will be signed by the private key.

It usually combines values such as:

  • HTTP method;
  • endpoint path;
  • body hash;
  • timestamp.

The exact format must match the SNAP BI requirement for the endpoint and signature type you are using.

This is where the SNAP BI Asymmetric Signature tool helps: it shows the signing input so you can see what is actually being signed.

If signing fails between systems, compare the string to sign on both sides first. Most bugs are not caused by RSA itself. They are caused by different signing text.

Step 4: paste the private key for signing

To create a signature, you need the RSA private key.

It may look like this:

-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----

or sometimes:

-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----

Use a test key while learning. Do not paste production private keys into tools you do not control. The tool on this site runs in the browser, but the safe professional habit is still to test with non-production keys whenever possible.

Step 5: generate the signature

After the request parts and private key are filled in, generate the signature.

The result is usually Base64 text. It is meant to be sent in the required signature header, according to the API spec.

At this point, save these for debugging:

  • HTTP method;
  • path;
  • timestamp;
  • body exactly as sent;
  • body hash;
  • string to sign;
  • generated signature.

If the other system says the signature is invalid, those values are what you compare.

Step 6: verify with the public key

Verification uses the public key that matches the private key.

A public key may look like this:

-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----

Paste the public key, the same request parts, and the signature into the verification side of the tool.

If verification passes, it means:

  • the signature matches the signing input;
  • the public key matches the private key used for signing;
  • the signing text has not changed.

If verification fails, do not immediately blame the key. Check the signing text first.

Step 7: compare timestamps carefully

Timestamps are a common source of mistakes.

Check:

  • timezone offset, such as +07:00;
  • date format;
  • seconds vs milliseconds;
  • whether the timestamp in the header is exactly the timestamp used for signing;
  • whether the receiver has a time tolerance window.

If the timestamp sent in the header differs from the timestamp used in the string to sign, verification can fail.

Step 8: compare paths carefully

Another common source of mistakes is the endpoint path.

These are different strings:

/snap/v1.0/transfer-va/payment
/snap/v1.0/transfer-va/payment/

The trailing slash matters if it is included in the signing input.

Query strings can also matter:

/snap/v1.0/report?from=2026-09-01&to=2026-09-27

If the spec says to include the query string, include it exactly. If it says not to, do not include it.

Step 9: compare request bodies carefully

If the body is part of the signature, compare the exact body string.

Common body-related mistakes:

  • signing minified JSON but sending pretty JSON;
  • signing pretty JSON but sending minified JSON;
  • changing key order after signing;
  • adding or removing whitespace;
  • sending a different value type, such as number vs string;
  • hashing an empty body when the request actually has a body.

For debugging, log a safe hash of the body instead of logging sensitive full payloads in production.

Step 10: use test keys before production keys

A safe workflow is:

  1. generate or use test RSA keys;
  2. sign a simple test request;
  3. verify it locally with the public key;
  4. send it to the sandbox environment;
  5. compare the string to sign if sandbox rejects it;
  6. only then move to production keys.

This prevents learning mistakes from touching production credentials.

My SNAP BI signature checklist

When a SNAP BI signature fails, I check:

  1. Is the HTTP method exactly the same?
  2. Is the path exactly the same, including query string if required?
  3. Is the body exactly the same as the body that was signed?
  4. Is the body hash computed from the correct text?
  5. Is the timestamp format correct?
  6. Is the timestamp in the header the same as the timestamp in the signing input?
  7. Was the signature created with the correct private key?
  8. Is verification using the matching public key?
  9. Is the signature Base64 copied without spaces or line breaks?
  10. Are sandbox and production keys mixed up?

The professional way to debug this is not to guess. Compare the exact string to sign on both sides. If that string is identical and the right keys are used, verification should work.

The SNAP BI Asymmetric Signature tool is useful because it makes the hidden part visible: the text you are actually signing.

Comments

Comments are welcome — please read the comment policy first. Powered by giscus and GitHub Discussions.