All endpoints require signature validation for the request to be accepted for processing. We use HMAC SHA-512 based signatures to valiate requests. Add Request-Signature and Request-Timestamp as required header parameters.

Signing Key

Get your API secret that will be used for signing requests on the dashboard. How to get your API credentials

Please note that your API secret should be stored securely. It should be used only for generating Request-Signature header, do not add the API secret directly to any API request to avoid exposure. Paycashless will never request you to share your API key or API secret.

Signing a request

StepActionDescription
1SortIf the request has a body, sort it alphabetically.
2HashIf the request has a body, turn the sorted body into a string and hash it with HMAC SHA-512 algorithm using your API secret as the signing key (output should be hex-encoded).
3ConcatenateConcatenate the request path, hashed body (if present), and timestamp. There are no spaces or other characters between these values. The order of the fields must follow the order stipulated here.
4SignTake the string from the Concatenate step and generate a HMAC SHA-512 signature using your API secret as the signing key.
5EncodeTake the output of the Sign step and hex-encode it.

The fields used to generate the signature are as follows. If the conditions below are not met, your signature will not validate.

FieldDescription
Request PathLowercased URL path without the base url and search parameters (e.g. /v1/virtual_account/va_84jdvcy3gyt5bfsczdaooy4/transactions).
Hashed BodyShould be omitted if request does not have a body (e.g. GET requests). The alphabetically sorted, stringified and HMAC SHA-512 hashed http request body.
TimestampThe number of seconds since the Unix Epoch in UTC, and must be within five minutes of the API service’s time when the request arrives. The same value MUST also be passed in the Request-Timestamp header.

API Signature example

You can use the example values below to test and validate your signing code logic;

FieldValue
Request Path/v1/payouts
Sorted Body{"amount":{"currency":"NGN","value":10000},"bankId":"bank_538ed2056326432ba8e6853b613997bb","callbackUrl":"https://webhook.site/99a59e8a-bd0b-485d-8249-fccb5eb62e27","destinationAccountNumber":"9845648577","metadata":{"category":"transfer"},"narration":"zapped","reference":"trx_fWQ7b31pbs5mmT3k3qfb46"}
Hashed Body61ce72561daddb581abbd83c731dc5421b062157f707b1f683086bccbe85d8b14b7a4df6a1cdb7c14230a631d8ad7d82536f28c2e67717e6cf6673d8b6df3a23
Timestamp1749163599
Signing Keylive_sk_bqf5evl708c5arkfv16g37glc4isxsup.pc
Signature95013b0b1e41f36b2de57cd6ef08ecc4d0f8ff846c98e1470f3ef8bce90012133a7c867b7d21e4c27cc68c1bde0bb3fc63e960c892ac82c8ef74b9f793854d7d

Below is a node.js code sample used in signing the values above;

import crypto from 'crypto';
import { sortObjectAlphabetically } from "./sort.js";

function sha512Sign(message, secret) {
  return crypto.createHmac('sha512', secret).update(message).digest('hex');
}

// Get the timestamp (in seconds) and pass it to the header as 'Request-Timestamp'
const timestamp = Math.floor(Date.now() / 1000);
const requestPath = "/v1/payouts";
const API_SECRET = "YOUR_API_SECRET"; // replace these with your actual API secret value

// Get the request body 
let body = {
  "amount":{
    "currency":"NGN",
    "value":10000
  },
  "bankId":"bank_538ed2056326432ba8e6853b613997bb",
  "callbackUrl":"https://webhook.site/99a59e8a-bd0b-485d-8249-fccb5eb62e27",
  "destinationAccountNumber":"9845648577",
  "metadata":{
    "category":"transfer"
  },
  "narration":"zapped",
  "reference":"trx_fWQ7b31pbs5mmT3k3qfb46"
};

// Sort the body alphabetically
body = sortObjectAlphabetically(body);

// Create the body hash to be passed as payload
const bodyHash = sha512Sign(JSON.stringify(body), API_SECRET);

// Concatenate the string to sign
const stringToSign = `${requestPath}${bodyHash}${timestamp}`;

// Generate the Request-Signature value for the header
const signature = sha512Sign(stringToSign, API_SECRET);

console.log(`signature: ${signature}`);