Troubleshooting Signed REST Requests
Given the binary nature of signature verification (it passes or it doesn't), troubleshooting problems with signatures can be difficult. There is a broad range of input data and only a single boolean output. If a signed REST request fails then the problems causing this may include the following:
- Signed request string does not match the request sent by your back end
- Expiry time not within a valid range
- Incorrect signing algorithm
- Invalid request body
- Incorrect private or public key
If you are having problems with signed REST requests we recommend starting with a basic request and building it one field at a time until it mirrors requests that your system will be sending. The zsh scripts below can be used for this. It sends a basic signed hosted verified payout request.
#!/bin/zsh
#
# Script to test request signatures for verified hosted payout REST requests.
#
# The script can be called as follows:
#
# zsh ./get_hosted_payout_link.zsh
#
# The configurable variables below should be set before using script.
###### Configurable variables.
# Put your private API key here.
#
YOUR_MERCHANT_PRIVATE_API_KEY="5f219015-de07-10f1-529a-ba018baeff01"
# Put your RSA private key file path here.
#
YOUR_RSA_PRIVATE_KEY_FILE="./private_key.pem"
# Update this to reflect requests you will be sending.
#
REQUEST_BODY='{
"amount": 1.05,
"currency": "GBP",
"paymentGiro": "FPS",
"reference": "ref123",
"customerIdentifier": "[email protected]",
"customerIpAddress": "1.2.3.4",
"customerDeviceOs": "Android"
}'
###### End Configurable variables.
ENDPOINT='https://testapi.yaspa.com/v2/payouts/hosted-payout/generate-link'
currentTime=$(date +%s)
signatureExpireTime=$((currentTime + 600))
signaturePlainText="$signatureExpireTime|POST|$ENDPOINT|$REQUEST_BODY"
encodedSignature=$(echo -n $signaturePlainText | openssl dgst -sha256 -sign $YOUR_RSA_PRIVATE_KEY_FILE | base64)
curl -X POST $ENDPOINT \
-H "AuthorizationCitizen: $YOUR_MERCHANT_PRIVATE_API_KEY" \
-H "Expires-at: $signatureExpireTime" \
-H "Signature: $encodedSignature" \
-H "Content-Type: application/json" \
-d $REQUEST_BODY#!/bin/zsh
#
# Script to test request signatures for verified hosted payout REST requests.
#
# The script can be called as follows:
#
# zsh ./get_hosted_payout_link.zsh
#
# The configurable variables below should be set before using script.
###### Configurable variables.
# Put your private API key here.
#
YOUR_MERCHANT_PRIVATE_API_KEY="5f219015-de07-10f1-529a-ba018baeff01"
# Put your RSA private key file path here.
#
YOUR_RSA_PRIVATE_KEY_FILE="./private_key.pem"
# Update this to reflect requests you will be sending.
#
REQUEST_BODY='{
"amount": 1.05,
"currency": "EUR",
"paymentGiro": "SEPA",
"reference": "ref123",
"customerIdentifier": "[email protected]",
"customerIpAddress": "1.2.3.4",
"customerDeviceOs": "Android"
}'
###### End Configurable variables.
ENDPOINT='https://testapi.yaspa.com/v2/payouts/hosted-payout/generate-link'
currentTime=$(date +%s)
signatureExpireTime=$((currentTime + 600))
signaturePlainText="$signatureExpireTime|POST|$ENDPOINT|$REQUEST_BODY"
encodedSignature=$(echo -n $signaturePlainText | openssl dgst -sha256 -sign $YOUR_RSA_PRIVATE_KEY_FILE | base64)
curl -X POST $ENDPOINT \
-H "AuthorizationCitizen: $YOUR_MERCHANT_PRIVATE_API_KEY" \
-H "Expires-at: $signatureExpireTime" \
-H "Signature: $encodedSignature" \
-H "Content-Type: application/json" \
-d $REQUEST_BODYThe following steps should be followed for troubleshooting with the script:
- Ensure you have cURL and OpenSSL installed.
- These can be installed with the following commands on a Mac:
brew install opensslbrew install curl
- These can be installed with the following commands on a Mac:
- Copy the shell script for GBP or EUR payouts as appropriate and save it to:
get_hosted_payout_link.zsh. Then configure the script:- Set the variables:
YOUR_MERCHANT_PRIVATE_API_KEYandYOUR_RSA_PRIVATE_KEY_FILE
- Set the variables:
- Run the script using the command:
zsh ./get_hosted_payout_link.zsh- If the script does not run then because it cannot find OpenSSL or similar then you can paste the whole script then you may paste the script and error message into a LLM such as Claude or ChatGPT. Be careful about installing packages – the script should not need anything other than cURL and OpenSSL. Also, do not include any production keys.
- If a 401 response is returned then there is likely a problem with either the private or public RSA key. Check that the private RSA key corresponds to the public RSA key registered. Also check that it is a 2048 bit key.
- If a 403 response is returned then there is likely a problem with your merchant private API key. Check that this correct.
- Add fields in the
REQUEST_BODYvariable to match the fields you intend to set in payout requests. The fields should be added one at a time and then tested.- If a 400 response is returned then it is likely that a required field has been removed. Check the documentation for required fields for the REST call.
- Once the request sent by the script reflects one that will be sent by your system then try a signed request from it.
- If a 400 response is returned then check if a required field is missing from the call from your system.
- If a 403 response is returned then your system is likely using an incorrect merchant private API key. Check that this correct.
- If a 401 response is returned then check the following:
- Check if your system is including special chars in the request it's sending.
- Check that the order of fields sent in the request matches that in the requestBody part of the signed string.
- Check that your system is using the same private RSA key as the script.
- Check that the expires-at header is set to a UNIX timestamp between now and 10 minutes from now. It should also match the value in the expiryTime part of the signed string.
- Check that your system is using the correct signing algorithm:
SHA256withRSA. In this algorithm a SHA 256 hash is taken of the string and the hash is then signed.
It should be possible to complete steps 1 to 4 without customer support. These steps should rule out the most obvious problems. If you receive a 401 response at step 5 we can help by checking logs at our end, which may be useful for the following issues:
- Checking the request that your system is sending to see if special chars are being added or if fields are being re-ordered
- Checking if the
expires-atheader is within the allowed range. - Checking for problems with key length or signing algorithm.
Updated 4 days ago
