These are the Pay1st best practices for generating signatures for gateway Integrations
Overview
For all non authentication requests, a signature needs to be generated for the intended payload. We do this so that we can validate that API requests have not been tampered with.
Signature Description
The signature is a hex encoded HMAC-SHA256 and is generated and sent using the X-SIGNATURE HTTP request header.
The signature can be generated using the following steps:
- Prepare the Payload - The payload string is made up of two parts:
- Timestamp - Generate a timestamp in ISO-8601 format.
- Request JSON - Use the exact JSON that is sent to the server
- Create the Payload String - Concatenate the timestamp with the request JSON
- Generate HMAC-SHA256
- Use the payload string as the HMAC key.
- Use the Signing Key (which is obtained from Configuring API Credentials) as the data to sign the payload.
Ensure that the HMAC result is in lowercase (some languages return this by default).
TimestampThe same timestamp of this request will also be expected to be sent in the
X-Timestamp
HTTP Header alongside theX-Signature
when submitting API requests to the Pay1st Gateway.
Test Cases
The following table can be used as test cases to check for the correctness of the signature
Expected Signature | Timestamp | Signing Key | JSON Payload |
---|---|---|---|
85aa0862aa052f737d3cf4d38f92091ea7c015e782d207ea18cc5641d3e47755 | 2025-03-17T08:10:52.544247646Z | hCyO_Flnu6aid-bhFYTYOowkxXRzoZkgzO32rB6Ik8Y | {"countryCode":"NG","currencyCode":"NGN","amount":100,"partnerReference":"4a662291-2840-4bcd-aae9-553ab24601ed","callbackSuccessUrl":"<https://callback.success","callbackFailureUrl":"https://callback.failure","callbackPendingUrl":"https://callback.pending","callbackCancelUrl":"https://callback.cancel","webhookUrl":"https://webhook.success","products":[{"title":"10> Credits","sku":"12345","price":100,"quantity":1,"currencyCode":"NGN"}],"metadata":[{"key":"customerId","value":"1"}]} |
Code Samples
The following code samples can be used as a reference (or the signature description can be code generated using an LLM)
KEY="YXBpdXNlcjphcGlwYXNzd29yZA=="
PAYLOAD="{\"countryCode\":\"NG\",\"currencyCode\":\"NGN\",\"amount\":100,\"partnerReference\":\"{{pay1stPartnerReference}}\",\"callbackSuccessUrl\":\"https://callback.success\",\"callbackFailureUrl\":\"https://callback.failure\",\"callbackPendingUrl\":\"https://callback.pending\",\"callbackCancelUrl\":\"https://callback.cancel\",\"webhookUrl\":\"https://webhook.success\",\"products\":[{\"title\":\"10Credits\",\"sku\":\"12345\",\"price\":100,\"quantity\":1,\"currencyCode\":\"NGN\"}],\"metadata\":[{\"key\":\"customerId\",\"value\":\"1\"}]}";
echo -en "$PAYLOAD" \
| openssl sha256 -hmac "$KEY" \
| awk '{print $2}'
<?php
$payload = "{\"countryCode\":\"NG\",\"currencyCode\":\"NGN\",\"amount\":100,\"partnerReference\":\"{{pay1stPartnerReference}}\",\"callbackSuccessUrl\":\"https://callback.success\",\"callbackFailureUrl\":\"https://callback.failure\",\"callbackPendingUrl\":\"https://callback.pending\",\"callbackCancelUrl\":\"https://callback.cancel\",\"webhookUrl\":\"https://webhook.success\",\"products\":[{\"title\":\"10Credits\",\"sku\":\"12345\",\"price\":100,\"quantity\":1,\"currencyCode\":\"NGN\"}],\"metadata\":[{\"key\":\"customerId\",\"value\":\"1\"}]}";;
$key = "YXBpdXNlcjphcGlwYXNzd29yZA==";
echo hash_hmac('sha256', trim($payload), $key);
import java.nio.charset.Charset;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Hex;
public class Signature {
public static void main(String[] args) throws Exception {
String payload = "{\"countryCode\":\"NG\",\"currencyCode\":\"NGN\",\"amount\":100,\"partnerReference\":\"{{pay1stPartnerReference}}\",\"callbackSuccessUrl\":\"https://callback.success\",\"callbackFailureUrl\":\"https://callback.failure\",\"callbackPendingUrl\":\"https://callback.pending\",\"callbackCancelUrl\":\"https://callback.cancel\",\"webhookUrl\":\"https://webhook.success\",\"products\":[{\"title\":\"10Credits\",\"sku\":\"12345\",\"price\":100,\"quantity\":1,\"currencyCode\":\"NGN\"}],\"metadata\":[{\"key\":\"customerId\",\"value\":\"1\"}]}";
String key = "YXBpdXNlcjphcGlwYXNzd29yZA==";
Mac hmac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(Charset.defaultCharset()), "HmacSHA256");
hmac.init(secretKeySpec);
String signature = new String(Hex.encodeHex(hmac.doFinal(String.format(payload).trim().getBytes(Charset.defaultCharset()))));
System.out.println(signature);
}
using System;
using System.Text;
using System.Security.Cryptography;
class Signature
{
public static void Main (string[] args)
{
string payload = "{\"countryCode\":\"NG\",\"currencyCode\":\"NGN\",\"amount\":100,\"partnerReference\":\"{{pay1stPartnerReference}}\",\"callbackSuccessUrl\":\"https://callback.success\",\"callbackFailureUrl\":\"https://callback.failure\",\"callbackPendingUrl\":\"https://callback.pending\",\"callbackCancelUrl\":\"https://callback.cancel\",\"webhookUrl\":\"https://webhook.success\",\"products\":[{\"title\":\"10Credits\",\"sku\":\"12345\",\"price\":100,\"quantity\":1,\"currencyCode\":\"NGN\"}],\"metadata\":[{\"key\":\"customerId\",\"value\":\"1\"}]}";
string key = "YXBpdXNlcjphcGlwYXNzd29yZA==";
HMACSHA256 hmac = new HMACSHA256 (Encoding.Default.GetBytes (key));
byte[] hash = hmac.ComputeHash (Encoding.Default.GetBytes(payload).Trim()));
string signature = String.Concat(Array.ConvertAll(hash, x => x.ToString("X2")));
Console.Write (signature);
}
}
import hmac
import hashlib
key = 'YXBpdXNlcjphcGlwYXNzd29yZA=='
payload = "{\"countryCode\":\"NG\",\"currencyCode\":\"NGN\",\"amount\":100,\"partnerReference\":\"{{pay1stPartnerReference}}\",\"callbackSuccessUrl\":\"https://callback.success\",\"callbackFailureUrl\":\"https://callback.failure\",\"callbackPendingUrl\":\"https://callback.pending\",\"callbackCancelUrl\":\"https://callback.cancel\",\"webhookUrl\":\"https://webhook.success\",\"products\":[{\"title\":\"10Credits\",\"sku\":\"12345\",\"price\":100,\"quantity\":1,\"currencyCode\":\"NGN\"}],\"metadata\":[{\"key\":\"customerId\",\"value\":\"1\"}]}"
print hmac.new(key, (payload).strip(), hashlib.sha256).hexdigest()