Webhooks
Introduction
Webhooks are automated https JSON requests sent to any desired web endpoint. These are sent each time a payment's status changes. These are useful for keeping your system up to date with the Sticitt's Pay API, should you wish to do so.
Every webhook request must be responded to using a HTTP 200 OK. If a different response is received, the webhook will retry every 15 seconds until a 200 OK is received.
Your application should catch any errors and still respond 200 OK unless you want the webhook to retry i.e. temporarily down.
Signature
Webhook payloads are signed using a shared key.
All signatures must be verified before considered reliable.
Webhook posts have a Pay-Signature http-header. A Base64 encoded HMAC265 signature should be calculated over the body using your client_secret. The calculated signature should then be compared to the Pay-Signature header.
If the signatures do not match, do not treat the webhook as reliable.
Calculating signatures
using System.Security.Cryptography;
using System.Text;
public class Program
{
private static string CalculateSignature(string message, string clientSecretKey)
{
//Retrieve key from client secret.
var encoding = new UTF8Encoding();
var key = encoding.GetBytes(clientSecretKey);
var payload = encoding.GetBytes(message);
//Sign request
var pen = new HMACSHA256(key);
var signature = pen.ComputeHash(payload);
//Encode signature as base64
var base64Signature = Convert.ToBase64String(signature);
return base64Signature;
}
public static void Main(string[] args)
{
var message = "YOUR_MESSAGE_TO_BE_SIGNED";
var clientSecretKey= "YOUR_CLIENT_SECRET_KEY";
Console.WriteLine("Calculated Signature: " + CalculateSignature(message, clientSecretKey));
}
}
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class SignatureCalculator {
private static String calculateSignature(String message, String clientSecretKey) throws Exception {
// Retrieve key from client secret.
byte[] key = clientSecretKey.getBytes(StandardCharsets.UTF_8);
byte[] payload = message.getBytes(StandardCharsets.UTF_8);
// Sign request
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacSHA256");
Mac hmacSha256 = Mac.getInstance("HmacSHA256");
hmacSha256.init(secretKeySpec);
byte[] signature = hmacSha256.doFinal(payload);
// Encode signature as base64
String base64Signature = Base64.getEncoder().encodeToString(signature);
return base64Signature;
}
public static void main(String[] args) {
try {
String message = "YourMessageToBeSigned";
String clientSecretKey = "YOUR_CLIENT_SECRET_KEY";
String calculatedSignature = calculateSignature(message, clientSecretKey);
System.out.println("Calculated Signature: " + calculatedSignature);
} catch (Exception e) {
e.printStackTrace();
}
}
}
<?php
function calculateSignature($message, $clientSecretKey) {
// Retrieve key from client secret.
$key = utf8_encode($clientSecretKey);
$payload = utf8_encode($message);
// Sign request
$signature = hash_hmac('sha256', $payload, $key, true);
// Encode signature as base64
$base64Signature = base64_encode($signature);
return $base64Signature;
}
// Example of usage
try {
$message = "YourMessageToBeSigned";
$clientSecretKey = "YOUR_CLIENT_SECRET_KEY";
$calculatedSignature = calculateSignature($message, $clientSecretKey);
echo "Calculated Signature: " . $calculatedSignature;
} catch (Exception $e) {
echo $e->getMessage();
}
?>
const crypto = require('crypto');
function calculateSignature(message, clientSecretKey) {
// Retrieve key from client secret.
const key = Buffer.from(clientSecretKey, 'utf-8');
const payload = Buffer.from(message, 'utf-8');
// Sign request
const signature = crypto.createHmac('sha256', key).update(payload).digest();
// Encode signature as base64
const base64Signature = signature.toString('base64');
return base64Signature;
}
const message = "YourMessageToBeSigned";
const clientSecretKey = "YOUR_CLIENT_SECRET_KEY";
const calculatedSignature = calculateSignature(message, clientSecretKey);
console.log("Calculated Signature:", calculatedSignature);
import hmac
import hashlib
import base64
def calculate_signature(message, client_secret_key):
# Retrieve key from client secret.
key = bytes(client_secret_key, 'utf-8')
payload = bytes(message, 'utf-8')
# Sign request
signature = hmac.new(key, payload, hashlib.sha256).digest()
# Encode signature as base64
base64_signature = base64.b64encode(signature).decode('utf-8')
return base64_signature
message = "YourMessageToBeSigned"
client_secret_key = "YOUR_CLIENT_SECRET_KEY"
calculated_signature = calculate_signature(message, client_secret_key)
print("Calculated Signature:", calculated_signature)
Payment Webhook
These are sent via a http POST
to the url that you provide to us, with the following json
request body.
{
"webhookID": "00f0f000-fff0-0f00-00f0-000f000f0000",
"clientID": "sticitt-host",
"body": {
"paymentID": "00f0ffff-0000-0000-00ff-ff0fff00ff00",
"amount": 100000,
"createdAt": "2024-07-01T00:00:00.000000+00:00",
"authorizedAt": null,
"expiredAt": "2024-07-06T00:00:00.0000000Z",
"expires": "2024-07-05T00:00:00.00000+00:00",
"canceledAt": null,
"paidAt": null,
"reversedAt": null,
"clientID": "sticitt-host",
"merchantID": "ff0f0f0f-0000-0000-00f0-0f0f0f000f00",
"merchantName": "sticitt training",
"merchantAccountReference": "SXXXPXXX",
"status": 0,
"reference": "Sticitt 0000000ff0000000000000",
"description": "STICITT - School Fees",
"walletHolderName": null,
"debtor": "STICITT",
"project": "School Fees",
"debtorReference": null,
"cardPaymentFee": 0
},
"type": "PaymentStatusUpdate"
}
Field | Description |
---|
clientID | API ID assigned to you |
body | Payment object |
type | 'PaymentStatusUpdate' |
Last modified: 20 February 2025