Signing requests for key operations
If you are using a Volt Account with Connect, you need to sign each Refund and Payout request using your private key in order for your payment to be straight-through-processed (ie with no further manual interaction required).
If your Connect account is provided by one of our partners (eg Clear Junction or ISX) then you do not need to sign your request and you can stop reading here.
Why do you need to do this?
This is done to add an extra layer of security to actions that impact the outflow of funds from the Volt Account.
How do you do this using the API?
We use JWS (JSON Web Signature) as the signature method for each request to authenticate it using second factor in addition to API credentials.
What happens if you don't sign each API request?
Your request won’t be processed for payment automatically, but will instead appear in a queue for processing in Fuzebox. You will need to login to Fuzebox and authorise the request using a passkey stored on your computer or mobile device. This can be done in bulk or for each individual payment.
Where can you test this?
You can test the signing on sandbox and production. However, we recommend testing it particularly on production before activating it for your shoppers.
Integration steps
First, you’ll need to set up the trusted signing keys. Second, for each request, create a JWT (JSON Web Token) which includes the signature and include that in the request header.
1) Setting up a key for signing
- Create private / public key pair
- Store the private key in a secure manner
- Share public key with Volt and get your assigned public key id
2) Signing the requests
Once you have the private key and the public key id you can proceed with signing the requests.
Create key pair
Technical specifications
- We support public keys in the following formats: PKCS1, PKCS8 and x509.
- The public key length should be between 2048 and 4096 bytes.
How to generate your keys
It is recommended that you will use your own PKI infrastructure preferably based on a hardware security module (HSM) to generate a key pair for this use case as this is industry best practice.
However, as not all companies are able to manage such solutions below recommendations were prepared to help with that manner.
The first option is to use a key creation functionality in Fuzebox. To do this go to Configuration > Customers> Payment Configuration> Signature Keys> Generate a key pair . Your public key will be automatically saved and you will receive a private key and public key id in a popup message. Please bear in mind that Volt is not saving on its side this private key.
You can also generate your private / public key pair using a terminal which supports the openssl command, and by following the details listed above.
If you generated the key pair outside of Fuzebox (e.g. in Terminal)” please upload your public key to Fuzebox under Configuration > Customers> Payment Configuration>Signature Keys> Upload an existing public key.
Once you upload the public key there, you will get a key ID, a UUID which you’ll need to use when generating your signed token on each refund or payout request, so please keep this ID safe.
Example of an ID is 901659f9-c0fd-4d2e-82b8-a55f51f80d73
.
You should never share your private key with Volt, or with any third party. If you believe your private key may be compromised, you should immediately inform Volt, generate new a key pair and send us the new public key.
Create a JWT token for each request
To sign each request, you will need to provide a JWT token in the header of that request. To generate a signed JWT token, you’ll need your private key and the ID of your public key, plus the payload (the JSON body) of the POST request for your Refund or Payout.
Creating your JWT token
You need to create additional two parts for your JWT token, the header and the signature supporting actual payload with data. The header tells us how to process the authentication of payload data and compare results with the signature provided to validate integrity and authenticity of the whole JWT token.
The token header segment
The header should be created first as a JSON object as below, where
alg
– represents the algorithm used to encode/decode the token, in this case it’sRS256
(the Rsa+Sha256 algorithm)typ
– should be “JWT
“kid
– theid
of the public key that we supplied you, which will be in UUID form
{
"alg": "RS256",
"typ": "JWT",
"kid": "ce161c49-4373-4b07-82fa-217998f6b3e8"
}
Encoding the header
Once you’ve created the JSON object as per the example above, you should remove any extra spaces or line breaks, then encode it using the base64UrlEncoded algorithm, as per the example below.
tokenHeader = '{"alg": "RS256","typ":"JWT","kid":"ce161c49-4373-4b07-82fa-217998f6b3e8"}'
encodedHeader = base64UrlEncode(tokenHeader)
… which should then look like the example below.
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImNlMTYxYzQ5LTQzNzMtNGIwNy04MmZhLTIxNzk5OGY2YjNlOCJ9
The signature segment
To create the signature segment, we need to use the algorithm that is specified in the header and the private key. This is where you’ll need a copy of the payload you’re sending in the POST request, because that’s what you’re actually signing here.
In this case we’re using the RSA+SHA256 algorithm and would use the sample code below, utilising the already encoded header plus a base64UrlEncoded version of the JSON payload you will be sending in the refund or payout request. You should not change the payload after generating the signature as this will invalidate the signed token.
Remove whitespace to improve validation
Please remove any line breaks or extra spaces in the request payload before using the base64UrlEncode function, this will ensure that your signature matches the way we’ll validate it. For example, in the case of refunds, you should base64UrlEncode('{"amount":1,"externalReference":"my-external-reference"}')
tokenHeader = '{"alg": "RS256","typ":"JWT","kid":"ce161c49-4373-4b07-82fa-217998f6b3e8"}'
requestPayload = '{"amount":1,"externalReference":"my-external-reference"}'
signature = RSASHA256( base64UrlEncode(tokenHeader) + "." + base64UrlEncode(requestPayload), privateKey )
If all is good you should get a signature which looks like this…
oUjLLtQigBniTiYswfE0JAjMiYXtIlNtVi1Lr1jqBx103vXgVtEdWApUMpG3wze3qVXD_APA2Sk8oLV4DGeBb5pN7yRGeCdxoV3IsikCVs6rn2Q2Jat-bReQMX39F7-Rpn7RznjHUsyWWcNbDKy1wRFcEnDJBVdb_1lKdFBPWaKMkB1Yd8t8X2va6mq7pJXPAMS36Gwc37vULZvdw4D-49r8mcbEGnNXwkcuZ08hMk4UsmM0kxLeNcrVD3wZtuU0N43u1trlPnuX9RDOOh9Gz0fEH1fwxdveAZaMOOWr7IPHBeV8nZXHxt1lpwJ-dpAsSDMvCFhr-MHuOQDDdqsfhQ
Build your JWT token
To build the final JWT token to sign your request, take the encoded header and join it to the signature as follows.
JWT = base64UrlEncode(header) + ".." + signature // Note the ".."
Important note
Please note the double dot ".."
is important when building the JWT token. Validation will fail if you miss one of the dots.
So, using the examples given in this page, your final token should look like the example below:
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImNlMTYxYzQ5LTQzNzMtNGIwNy04MmZhLTIxNzk5OGY2YjNlOCJ9..oUjLLtQigBniTiYswfE0JAjMiYXtIlNtVi1Lr1jqBx103vXgVtEdWApUMpG3wze3qVXD_APA2Sk8oLV4DGeBb5pN7yRGeCdxoV3IsikCVs6rn2Q2Jat-bReQMX39F7-Rpn7RznjHUsyWWcNbDKy1wRFcEnDJBVdb_1lKdFBPWaKMkB1Yd8t8X2va6mq7pJXPAMS36Gwc37vULZvdw4D-49r8mcbEGnNXwkcuZ08hMk4UsmM0kxLeNcrVD3wZtuU0N43u1trlPnuX9RDOOh9Gz0fEH1fwxdveAZaMOOWr7IPHBeV8nZXHxt1lpwJ-dpAsSDMvCFhr-MHuOQDDdqsfhQ
Sign your request
Now you have your request payload and a JWT token which signs that payload, all you need to do is add a JWS header to each request, which contains the JWT token you created.
Header name : X-JWS-Signature
X-JWS-Signature: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImNlMTYxYzQ5LTQzNzMtNGIwNy04MmZhLTIxNzk5OGY2YjNlOCJ9..oUjLLtQigBniTiYswfE0JAjMiYXtIlNtVi1Lr1jqBx103vXgVtEdWApUMpG3wze3qVXD_APA2Sk8oLV4DGeBb5pN7yRGeCdxoV3IsikCVs6rn2Q2Jat-bReQMX39F7-Rpn7RznjHUsyWWcNbDKy1wRFcEnDJBVdb_1lKdFBPWaKMkB1Yd8t8X2va6mq7pJXPAMS36Gwc37vULZvdw4D-49r8mcbEGnNXwkcuZ08hMk4UsmM0kxLeNcrVD3wZtuU0N43u1trlPnuX9RDOOh9Gz0fEH1fwxdveAZaMOOWr7IPHBeV8nZXHxt1lpwJ-dpAsSDMvCFhr-MHuOQDDdqsfhQ
Test it with Postman
We have a test script in our Postman collection. It is part of the “Scripts > Pre-req”.
For testing you need
- Private key for sandbox (not your production private key)
- Public key id (kid) from Volt