🔔Webhook
How does it work?
Webhook is a kind of feedback method for payment information.
When withdrawal request status changes, a POST request is sent to the callback url specified when creating the request.
Webhook Request format
{
"id": "9c3288f5-3aef-464d-a3fd-57c170163eab",
"network": "BTC",
"currency": "BTC",
"address": "bc1qa7pumxw8rf7srg74adtks0ramsfv6c3vjvefrm",
"amount": 0.05,
"status": "pending",
"order_id": "1",
"additional_data": {
"user_id": 255,
"client_category": "Big"
},
"created_at": 1717434398,
"updated_at": 1717434398
}id*
Invoice id. Can be used to check it's status
amount*
Invoice amount in fiat currency
currency*
network*
address*
Crypto wallet address where coins should be sent to
status*
additional_data*
Any data provided during Withdrawal creation request. It will be null if you didn't specify it during invoice creation request.
created_at*
Unix time for invoice creation date
expires_at*
Unix time for invoice expiration date
* - mandatory parameter
Webhook verification
Every Webhook Request has two headers:
X-Silus-Sign— this header contains the sign itself which should be validated by your backend.X-Silus-Timestamp— this is the header which contains time when the event was sent. It will be used for sign generation.
How to make sure sign in request is valid?
To be sure that sign in the request is valid you have to encode the entire webhook payload to JSON, then append X-Silus-Timestamp value at the end of the result string. The entire result should be converted to sha256 using HMAC with a secret key (the one you use to authenticate requests to Silus Withdrawals API).
The result string should be equal to the one in X-Silus-Sign header to be sure you are safe to perform any operations.
There is a difference when encoding an array of data in PHP and other languages. PHP does escape slashes and some other languages don’t. Therefore, you may encounter a sign mismatch.
You have to escape slashes with backslash to make it work properly.
Sign generation example using PHP
<?php
$secretKey = 'iaB9JSOSrBsNTSPGZAnhNRkMO1MNsq2Qep70cyOiuZfQ0GYNurpCjU5LD5jVDiky';
$payload = file_get_contents('php://input');
$payload = json_decode($payload, true);
$time = $_SERVER['HTTP_X_SILUS_TIMESTAMP'];
$requestSign = $_SERVER['HTTP_X_SILUS_SIGN'];
$signData = json_encode($payload, JSON_UNESCAPED_UNICODE) . $time;
$expectedSign = hash_hmac('sha256', $signData, $secretKey);
echo hash_equals($requestSign, $expectedSign) ? 'Yay! Request is valid!' : 'Nah :( Didn\'t work';Sign generation example using NodeJS
const crypto = require('crypto');
const http = require('http');
const secretKey = 'iaB9JSOSrBsNTSPGZAnhNRkMO1MNsq2Qep70cyOiuZfQ0GYNurpCjU5LD5jVDiky';
const server = http.createServer((req, res) => {
let payload = '';
req.on('data', chunk => {
payload += chunk;
});
req.on('end', () => {
const time = req.headers['x-silus-timestamp'];
const requestSign = req.headers['x-silus-sign'];
const signData = payload + time;
const expectedSign = crypto.createHmac('sha256', secretKey).update(signData).digest('hex');
if (crypto.timingSafeEqual(Buffer.from(requestSign), Buffer.from(expectedSign))) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Yay! Request is valid!');
} else {
res.writeHead(400, { 'Content-Type': 'text/plain' });
res.end('Nah :( Didn\'t work');
}
});
});
server.listen(3000, () => {
console.log('Server is listening on port 3000');
});
Last updated