Signature verification
How to verify Volt notification signatures using HMAC SHA256 and test your implementation
How Volt notification signatures work
Volt signs every notification to ensure it's authentic and untampered. The signature is generated using a combination of your notification secret, the notification body, and a timestamp—never including personal or sensitive information. Each notification will include a custom HTTP header named X-Volt-Signed, which contains this signature.
Signature process overview
- Volt sends a POST request to your configured notification endpoint.
- Using the notification body and your notification secret, you generate your own version of the expected signature.
- You compare your calculated signature to the value in the
X-Volt-Signedheader to verify that they match.
Verifying the signature
To verify a notification signature, you need three pieces of information—all included in the notification. Follow these steps:
Extract the following from the notification:
User-AgentheaderX-Volt-TimedheaderX-Volt-Signedheader- The body of the notification
From the User-Agent header, extract the notification version. This is the value after the forward slash ( / ).
Example: If User-Agent is Volt/2.0, the version is 2.0.
Concatenate the notification body, the value of X-Volt-Timed, and the version using the pipe character | as a delimiter, in the following format:
body|X-Volt-Timed|version
This will be the string you use for signature verification.
Please ensure you use the body exactly as we send it.
You shouldn't expand escaped characters before calculating the signature.
For example, we’ll send data with accented characters escaped like this: "groupName":"Soci\u00e9t\u00e9 G\u00e9n\u00e9rale". If you convert it back to accented characters so you can read the groupName as "Société Générale" then you'll end up with a signature that doesn't match.
Hash the concatenated string with HMAC SHA256, using your notification secret as the key.
Example code (PHP):
$hash = hash_hmac('sha256', $check_string, $notification_secret);Compare the HMAC signature you just generated to the value in the notification's X-Volt-Signed header. If they match, the notification is valid.
Responding to notifications
Once you've compared your calculated HMAC signature to the one received with the notification, you should return one of two HTTP responses.
- If the signatures match, return an empty HTTP response with a status code of
200 (OK) - If they do not match, return an empty HTTP response with a code of
400 (Bad Request)and do not process the notification
Testing notifications
Use the example values below to verify your signature verification implementation works correctly:
| item | Example value |
|---|---|
| version | 1.0 (from the User-Agent header containing Volt/1.0) |
| X-Volt-Timed | 1631525064 |
| X-Volt-Signed | ed22494369277d25cf8c2293d142e5fddb9cecbea1f54e28ac16db0bee3b8009 |
| body | (empty as in a test notification) |
| notification secret | 9c0c8c97-c224-45ed-a195-23b54b1c67e5 |
Steps to test
Concatenate the body, X-Volt-Timed, and version using the pipe delimiter (|) in that order:
{}|1631525064|1.0Hash the concatenated string using HMAC SHA256 with your notification secret:
$hash = hash_hmac('sha256', $string, $notification_secret);Compare your generated HMAC signature to the value in the X-Volt-Signed header. They should match:
ed22494369277d25cf8c2293d142e5fddb9cecbea1f54e28ac16db0bee3b8009Notifications containing real data
When you receive real notifications, the body element should be supplied as one continuous, unformatted string—with no spaces or line breaks. Use the body exactly as received.
Example notification body:
{"payment":"4a96elcb-8ae0-426c-a95e-d34f18fe32ad","reference":"EXAMPLE123","amount":8888,"status":"PENDING","detailedStatus":"BANK_REDIRECT"}Concatenated verification string:
{"payment":"4a96elcb-8ae0-426c-a95e-d34f18fe32ad","reference":"EXAMPLE123","amount":8888,"status":"PENDING","detailedStatus":"BANK_REDIRECT"}|1631525064|1.0Expected HMAC signature:
9e09fdc90e8121e9d11f560c226271940b6b1f936ffc7a3f2551956c716b1019Responding to tests
Your system should always be able to respond to a test notification and respond with a 200 (OK) status code. In the test notification, we'll send an empty JSON object in the request body, so your check string should look like this:
Test notification structure
{}|X-Volt-Timed|versionTest notification example
{}|12345678|2.0We use test notifications to determine the health of your system. If we stop sending you notifications because of failure, you'll need to send and respond to a test notification before we start sending you other notifications again.
Interactive signature tester
Test your signature verification implementation using the interactive tool below:
The body of the POST message from Volt.
The value of the X-Volt-Timed header.
Extracted from User-Agent (e.g. "Volt/2.0").
This will be used to generate the signature.
How is this guide?
Last updated on