Skip to main content

Webhooks

Receive payment completion events in real-time through webhooks.

Webhook Setup

Configure webhooks from the Merchant Dashboard.

  1. Log in to the dashboard.
  2. Select a project → Navigate to SettingsWebhooks.
  3. Register your Webhook URL. (HTTPS required)
  4. Securely store the issued Signing Secret (whsec_).
Signing Secret Storage

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

EventDescription
invoice.confirmedPayment 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"
}
}
FieldTypeDescription
idstringWebhook event unique ID (UUID)
typestringEvent type
createdAtstringEvent creation time (ISO 8601)
data.invoiceIdstringOOZOO invoice ID
data.clientInvoiceIdstring | nullMerchant-specified order ID
data.amountstringPayment amount (token units)
data.tokenSymbolstring | nullToken symbol (e.g., USDT)
data.networkNamestring | nullBlockchain network name (e.g., Ethereum)
data.txHashstring | nullBlockchain transaction hash
data.confirmedAtstring | nullConfirmation 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');
});
Signature Verification Required

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.

AttemptWait Time
1stImmediate
2ndAfter 1 min
3rdAfter 2 min
4thAfter 4 min
5thAfter 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

ItemDescription
Status CodeA 2xx response is treated as successful. Any other status code is considered a failure.
TimeoutMust respond within 10 seconds. Exceeding this is treated as a failure.
IdempotencyThe same event may be sent multiple times. Handle events idempotently based on the id field.
Content-TypeThe request body is in application/json format.