Skip to main content
To ensure the security and integrity of every transaction, the CommercePay API requires a digital signature in the cap-signature header for all API requests except Authentication endpoint. This signature allows our server to verify that the request body has not been tampered with and originated from an authorized source.
Field name matching is case-insensitive, so your actual HTTP request body does not strictly need to use camelCase keys. What matters is that the signature calculation below is always performed on a camelCase, recursively-sorted representation of your payload — we still recommend sending your request body in camelCase too, simply to avoid confusion between what you send and what you sign.

Encoding rules for the string you sign

  • Do not escape non-ASCII characters. Sign the raw characters (e.g. 陈大文, Café), not \uXXXX escape sequences. Many JSON libraries escape non-ASCII by default (for example Python’s json.dumps — set ensure_ascii=False; .NET’s System.Text.Json — use an unescaped encoder). The signature is verified against the unescaped form, so an escaped string will be rejected with “Invalid Signature”. Your actual HTTP body may contain either form; only the string you sign matters.
  • Do not escape anything beyond what JSON requires. Only ", \ and control characters are escaped. Characters such as +, <, >, & and ' must appear as-is (some serializers, e.g. System.Text.Json by default, turn a+b@x.com into a+b@x.com).
  • Encode as UTF-8. Convert both the final string and your Secret Key to UTF-8 bytes before computing HMAC-SHA256.
  • Lowercasing applies to every character, including non-ASCII letters (e.g. É becomes é). Use a Unicode-aware lowercase function, not an A–Z-only one.

POST Signature Generation

Follow these 6 steps to generate the cap-signature for your request.
1

Construct JSON (camelCase)

Prepare your request payload as a JSON object. Ensure all property names use camelCase (e.g., currencyCode, referenceCode).Omit any field that is null or was not provided — at every level, including inside nested objects. Do not include it as "key": null; leave it out of the JSON entirely before you move to the next step. (An empty string "" is a value, not null, and must be kept.)
2

Recursive Sorting (Ascending)

Sort all keys in the JSON object in ascending (A-Z) alphabetical order.Important: This must be done recursively. If your payload contains nested objects (like the customer object), their internal keys must also be sorted alphabetically.
3

Form the Signature String

Concatenate the Full Endpoint URL and the Sorted JSON string from Step 2 into one continuous string. Do NOT add any spaces between the URL and the JSON.Format: [FULL_URL][SORTED_JSON_STRING]
4

Normalize to Lowercase

Convert the entire combined string from Step 3 to lowercase. This ensures that minor casing differences in URLs or data do not cause a signature mismatch.
5

Generate HMAC-SHA256 Hash

Sign the lowercased string using the HMAC-SHA256 algorithm. Use your Secret Key as the cryptographic key.
6

Set the Header

Convert the resulting hash into a hexadecimal string. Place this value in the cap-signature header of your HTTP request.

Integration Example

Staging URL: https://staging-payments.commerce.asia/api/services/app/PaymentGateway/RequestPaymentSecret Key: bd90787d8e2340b49757438d66eed86d209e6a36a32d865a8287f90b033b815dRaw Request Payload

Transformation Walkthrough

Example with non-ASCII characters

Same endpoint and Secret Key as above, with customer.name changed to 陈大文 Café.Raw Request Payload
If you escape the non-ASCII characters ("name":"陈大文 café") you will compute 3ae10f257f2f5a85716f875132801794bf61c3c5688905fea51d9d29d7402768 instead, which the server rejects as an invalid signature.

Troubleshooting “Invalid Signature”

If you are receiving a 401 Unauthorized or Signature Mismatch error, check the following:
  • Minification: Ensure your JSON string is “minified” (no extra spaces, tabs, or newlines). The signature for {"a":1} is different from {"a": 1}.
  • Full URL: Ensure you are using the absolute URL (including https://) exactly as it is sent in the request.
  • Nested Keys: Double-check that nested objects like customer or billingAddress are sorted internally.
  • Lowercasing: Ensure the entire concatenated string (URL + JSON) is passed through a lowercase function before hashing.
  • Secret Key: Verify that you are using the correct Secret Key for the environment (Staging vs. Production).
  • Investigate payment signatures via the Signature Validator Tool.