Receive real-time notifications when payments are completed. Webhooks allow your application to be notified automatically when payment events occur.
Webhooks are HTTP callbacks that notify your application a payment is successful. Instead of continuously polling our API to check if a payment has been completed, webhooks push this information to your server as soon as it happens.
Create an HTTP endpoint on your server that can receive POST requests. This endpoint will process the webhook data sent by Stablio.
In your Stablio dashboard, navigate to Settings → Webhook Secret and generate a new secret key. This key will be used to verify the authenticity of webhooks.
Store your webhook secret as an environment variable...
If you are configuring a Pay by Link payment then your webhook is added on the Stablio dashboard during the configuration.
If, instead, you are configuring a Web Checkout payment, include your webhook URL in the PaymentWidget call:
const widget = new PaymentWidget({
type: 'defaultPayment',
vendorID: 'your_vendor_id',
amount: 49.99,
currency: 'USD',
userID: 'customer123',
webhook: 'https://your-server.com/webhook'
});
Standard webhooks are sent as HTTP POST requests to the URL you specify. They include a signature header to verify authenticity.
The webhook payload contains information about the payment:
{
"paymentID": "f116faae-bb86-456e-a393-cd6a0628d5fa",
"userID": "customer123",
"amount": 49.99,
"currency": "USD",
"timestamp": "2025-04-24T14:30:45.123Z",
}
Each webhook request includes the following headers:
| Header | Description |
|---|---|
x-signature |
HMAC SHA-256 signature of the request payload |
Content-Type |
Application/json |
To ensure webhooks are genuinely from Stablio, you should verify the signature using your Stablio webhook Secret. Here's an example using Express.js:
const express = require('express');
const crypto = require('crypto');
const app = express();
// Parse JSON bodies
app.use(express.json());
app.post('/webhook', async (req, res) => {
const receivedSignature = req.headers['x-signature'];
const data = req.body;
const payload = {
paymentID: data.paymentID,
userID: data.userID,
amount: data.amount,
currency: data.currency,
timestamp: data.timestamp,
};
const stringPayload = JSON.stringify(payload);
const hmac = crypto.createHmac('sha256', YOUR_STABLIO_WEBHOOK_SECRET);
hmac.update(stringPayload);
const calculatedSignature = hmac.digest('hex');
if (calculatedSignature === receivedSignature) {
console.log('Webhook signature is valid! ✅');
}
else {
console.log('Webhook signature is invalid! ❌');
}
});
Stablio also supports sending webhook notifications directly to Discord channels, allowing you to monitor payments without building a custom webhook endpoint.
Payment notifications will be sent as rich embeds in your Discord channel, containing all relevant payment details.
If you need to process Discord webhook notifications programmatically, you can set up a Discord bot to verify and handle these notifications:
const Discord = require('discord.js');
const crypto = require('crypto');
const client = new Discord.Client();
client.login('YOUR_DISCORD_BOT_TOKEN');
client.on('message', async (msg) => {
if(msg.channel.id == 'YOUR_WEBHOOK_CHANNEL_ID') {
const embed = msg.embeds[0];
const fields = embed.fields;
// Extract all data from the embed
const paymentID = fields.find(f => f.name === "Payment ID")?.value;
const amount = fields.find(f => f.name === "Amount")?.value;
const currency = fields.find(f => f.name === "Currency")?.value;
const userID = fields.find(f => f.name === "User ID")?.value;
const receivedSignature = fields.find(f => f.name === "Signature")?.value;
const timestamp = new Date(embed.timestamp).toISOString();
const secretKey = YOUR_STABLIO_WEBHOOK_SECRET;
const payload = {
paymentID,
userID,
amount,
currency,
timestamp
};
const stringPayload = JSON.stringify(payload);
const hmac = crypto.createHmac('sha256', secretKey);
hmac.update(stringPayload);
const calculatedSignature = hmac.digest('hex');
if (calculatedSignature === receivedSignature) {
console.log('Webhook signature is valid! ✅');
}
else {
console.log('Webhook signature is invalid! ❌');
}
}
})