Webhooks
Receive payment completion events in real-time through webhooks.
Webhook Setup
Configure webhooks from the Merchant Dashboard.
- Log in to the dashboard.
- Select a project → Navigate to Settings → Webhooks.
- Register your Webhook URL. (HTTPS required)
- Securely store the issued Signing Secret (
whsec_).
The Signing Secret is displayed only once at creation. If lost, you must issue a new one. Always use it server-side only and never expose it externally.
Event Types
| Event | Description |
|---|---|
invoice.confirmed | Payment confirmed (blockchain deposit finalized) |
Webhook Payload
{
"id": "webhook-event-uuid",
"type": "invoice.confirmed",
"createdAt": "2024-01-29T12:00:00Z",
"data": {
"invoiceId": "invoice-uuid",
"clientInvoiceId": "ORDER-12345",
"amount": "100.00000000",
"tokenSymbol": "USDT",
"networkName": "Ethereum",
"txHash": "0xabc123...",
"confirmedAt": "2024-01-29T12:00:00Z"
}
}
| Field | Type | Description |
|---|---|---|
id | string | Webhook event unique ID (UUID) |
type | string | Event type |
createdAt | string | Event creation time (ISO 8601) |
data.invoiceId | string | OOZOO invoice ID |
data.clientInvoiceId | string | null | Merchant-specified order ID |
data.amount | string | Payment amount (token units) |
data.tokenSymbol | string | null | Token symbol (e.g., USDT) |
data.networkName | string | null | Blockchain network name (e.g., Ethereum) |
data.txHash | string | null | Blockchain transaction hash |
data.confirmedAt | string | null | Confirmation time (ISO 8601) |
Signature Verification
The webhook request includes an HMAC-SHA256 signature in the X-Webhook-Signature header. You must verify the request integrity using the Signing Secret.
import * as crypto from 'crypto';
function verifyWebhookSignature(rawBody: string, signature: string, signingSecret: string): boolean {
const expectedSignature = crypto.createHmac('sha256', signingSecret).update(rawBody).digest('hex');
return signature === expectedSignature;
}
// Express example
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-webhook-signature'] as string;
const rawBody = req.body.toString();
if (!verifyWebhookSignature(rawBody, signature, 'whsec_xxxxxxxx')) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(rawBody);
if (event.type === 'invoice.confirmed') {
// Handle payment confirmation
console.log('Payment confirmed:', event.data.invoiceId);
}
res.status(200).send('OK');
});
Processing webhook events without signature verification may expose you to forged requests. Always verify the X-Webhook-Signature header before processing events.
Retry Policy
Failed webhook deliveries are automatically retried with exponential backoff. The base delay is 1 minute, doubling with each attempt up to 5 total attempts.
| Attempt | Wait Time |
|---|---|
| 1st | Immediate |
| 2nd | After 1 min |
| 3rd | After 2 min |
| 4th | After 4 min |
| 5th | After 8 min |
After 5 failed attempts, the event is recorded as a delivery failure. You can view delivery history from the Merchant Dashboard.
Response Requirements
| Item | Description |
|---|---|
| Status Code | A 2xx response is treated as successful. Any other status code is considered a failure. |
| Timeout | Must respond within 10 seconds. Exceeding this is treated as a failure. |
| Idempotency | The same event may be sent multiple times. Handle events idempotently based on the id field. |
| Content-Type | The request body is in application/json format. |