Skip to main content
Once CommercePay has verified a successful response from the payment provider and the customer has completed payment on the provider’s page, CommercePay sends an asynchronous, host-to-host callback notification to the merchant server. This notification is sent to the callbackUrl supplied in the originating request — for example on Direct Integration, Hosted Session Checkout, or Request Payout.
callbackUrl is optional on these endpoints. If it is omitted, CommercePay will not send a callback for that transaction — merchants who don’t provide it must poll the Query Payment endpoint instead.

Callback Payload

The payload CommercePay posts to your callbackUrl differs slightly depending on whether the transaction originated from a session-based flow (e.g. Hosted Session Checkout).
The exact set of fields returned may vary slightly by channel and provider.

Payload Fields

int64
The transaction payment value. This field exclusively accepts integer units where the final decimals are represented as whole values (e.g., an amount value of 1000 translates to 10.00 in the system backend).
integer
The CommercePay payment channel used for this transaction. Corresponds to the id from Get Channel List — see the Channel List for common values.
string
Currency code with a 3-letter ISO 4217 standard code (e.g., MYR).
string
The merchant-side unique order reference or invoice tracking sequence code originally supplied on the request.
integer
The resulting payment status code. See the Payment Status Code Table below.
string
Unique CommercePay Transaction Number mapped internally for auditing.
string
The upstream payment provider’s own transaction reference for this payment, when made available by the provider.
string
Session flow only. The unique session identifier, present when the transaction originated from a session-based checkout such as Hosted Session Checkout.

Payment Status Code Table

Verifying the Callback Signature

Every callback is signed with the same cap-signature scheme used to sign your own requests — see Generate Signature for the full mechanics. To confirm a callback genuinely came from CommercePay and was not tampered with, recompute the signature yourself and compare it to the cap-signature header sent with the callback request.
1

Construct JSON (camelCase)

Take the callback payload exactly as received, with all property names in camelCase.
2

Recursive Sorting (Ascending)

Sort all keys in the JSON object in ascending (A-Z) alphabetical order.
3

Form the Signature String

Concatenate your own callbackUrl (the exact URL you supplied on the original request) and the Sorted JSON string from Step 2, with no separator.Format: [YOUR_CALLBACK_URL][SORTED_JSON_STRING]
4

Normalize to Lowercase

Convert the entire combined string from Step 3 to lowercase.
5

Generate HMAC-SHA256 Hash

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

Compare to the cap-signature Header

Convert the resulting hash into a hexadecimal string and compare it to the cap-signature header sent with the callback. If they match, the callback is authentic.

Verification Example

Merchant Callback URL: https://www.merchantcallbackurl.com Received Payload

Transformation Walkthrough

Troubleshooting a Signature Mismatch

  • Use your own callbackUrl: Step 3 uses the exact callbackUrl value you originally sent CommercePay, not the request path the callback arrives on.
  • Minification: Ensure the JSON string is minified (no extra spaces, tabs, or newlines) before hashing.
  • Lowercasing: The entire concatenated string (URL + JSON) must be lowercased, including all keys and values — not just the values.
  • Secret Key: Verify you are using the correct Secret Key for the environment (Staging vs. Production) the callback was sent from.
  • Session vs. non-session payloads: Include paymentSessionNumber in the sorted JSON only when it is present in the received payload.