curl -X POST "https://api.unipay.com/v1/webhooks" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhooks/unipay",
"events": [
"transaction.completed",
"transaction.failed"
],
"secret": "your-webhook-secret-key"
}'
const webhook = await fetch('https://api.unipay.com/v1/webhooks', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: 'https://your-app.com/webhooks/unipay',
events: ['transaction.completed', 'transaction.failed'],
secret: 'your-webhook-secret-key'
})
});
const result = await webhook.json();
import requests
response = requests.post('https://api.unipay.com/v1/webhooks',
headers={
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
'url': 'https://your-app.com/webhooks/unipay',
'events': ['transaction.completed', 'transaction.failed'],
'secret': 'your-webhook-secret-key'
}
)
result = response.json()
{
"webhookId": "wh_1234567890abcdef",
"url": "https://your-app.com/webhooks/unipay",
"events": [
"transaction.completed",
"transaction.failed"
],
"createdAt": "2026-04-22T12:40:00Z"
}
Webhooks
Create Webhook
Register webhook endpoints to receive real-time transaction status updates
POST
/
v1
/
webhooks
curl -X POST "https://api.unipay.com/v1/webhooks" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhooks/unipay",
"events": [
"transaction.completed",
"transaction.failed"
],
"secret": "your-webhook-secret-key"
}'
const webhook = await fetch('https://api.unipay.com/v1/webhooks', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: 'https://your-app.com/webhooks/unipay',
events: ['transaction.completed', 'transaction.failed'],
secret: 'your-webhook-secret-key'
})
});
const result = await webhook.json();
import requests
response = requests.post('https://api.unipay.com/v1/webhooks',
headers={
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
'url': 'https://your-app.com/webhooks/unipay',
'events': ['transaction.completed', 'transaction.failed'],
'secret': 'your-webhook-secret-key'
}
)
result = response.json()
{
"webhookId": "wh_1234567890abcdef",
"url": "https://your-app.com/webhooks/unipay",
"events": [
"transaction.completed",
"transaction.failed"
],
"createdAt": "2026-04-22T12:40:00Z"
}
Register webhook endpoints to receive real-time notifications about transaction status changes. Webhooks are essential for tracking private mode transactions that may take 30-120 seconds to complete.
Verification Example:
After 6 failed attempts, webhook delivery is abandoned.
Request Body
string
required
Your webhook endpoint URL (must be HTTPS)
array
required
Array of event types to subscribe to:
transaction.pendingtransaction.confirmedtransaction.completedtransaction.failed
string
Secret key for webhook signature verification (recommended)
Response
string
Unique webhook identifier
string
Your webhook endpoint URL
array
Subscribed event types
string
Webhook creation timestamp (ISO 8601)
curl -X POST "https://api.unipay.com/v1/webhooks" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhooks/unipay",
"events": [
"transaction.completed",
"transaction.failed"
],
"secret": "your-webhook-secret-key"
}'
const webhook = await fetch('https://api.unipay.com/v1/webhooks', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: 'https://your-app.com/webhooks/unipay',
events: ['transaction.completed', 'transaction.failed'],
secret: 'your-webhook-secret-key'
})
});
const result = await webhook.json();
import requests
response = requests.post('https://api.unipay.com/v1/webhooks',
headers={
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
'url': 'https://your-app.com/webhooks/unipay',
'events': ['transaction.completed', 'transaction.failed'],
'secret': 'your-webhook-secret-key'
}
)
result = response.json()
{
"webhookId": "wh_1234567890abcdef",
"url": "https://your-app.com/webhooks/unipay",
"events": [
"transaction.completed",
"transaction.failed"
],
"createdAt": "2026-04-22T12:40:00Z"
}
Webhook Events
Event Types
transaction.pending
Transaction submitted to network
transaction.confirmed
Transaction confirmed on-chain
transaction.completed
Transaction fully processed (final state)
transaction.failed
Transaction failed or reverted
Event Payload
All webhook events include this payload structure:{
"event": "transaction.completed",
"transactionId": "tx_abcdef1234567890",
"timestamp": "2026-04-22T12:45:00Z",
"data": {
"transactionId": "tx_abcdef1234567890",
"status": "completed",
"mode": "private",
"type": "send",
"signature": "5VERv8NMvQakCcXn7JQVpMhHkPfft9kTrYpo9wqtKn5V...",
"blockTime": 1640995200,
"fee": "0.000005",
"recipients": [
{
"address": "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM",
"amount": "100.0"
}
]
}
}
Webhook Security
Signature Verification
Webhooks include a signature header for verification:X-Unipay-Signature: sha256=a8b7c6d5e4f3g2h1...
const crypto = require('crypto');
function verifyWebhook(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
const receivedSignature = signature.replace('sha256=', '');
return crypto.timingSafeEqual(
Buffer.from(expectedSignature, 'hex'),
Buffer.from(receivedSignature, 'hex')
);
}
// Usage
const isValid = verifyWebhook(
req.body,
req.headers['x-unipay-signature'],
'your-webhook-secret-key'
);
Security Best Practices
1
Use HTTPS
Webhook URLs must use HTTPS for security
2
Verify Signatures
Always verify webhook signatures to prevent spoofing
3
Validate Payload
Check that transaction IDs match your records
4
Idempotency
Handle duplicate webhook deliveries gracefully
Webhook Endpoint Requirements
Response Requirements
Your webhook endpoint must:- Respond with HTTP 200 status code
- Respond within 10 seconds
- Return any response body (ignored)
// Express.js example
app.post('/webhooks/unipay', (req, res) => {
const { event, transactionId, data } = req.body;
// Verify signature
if (!verifyWebhook(req.body, req.headers['x-unipay-signature'], secret)) {
return res.status(401).send('Invalid signature');
}
// Process webhook
console.log(`Transaction ${transactionId} is now ${data.status}`);
// Respond with 200
res.status(200).send('OK');
});
Retry Policy
Failed webhook deliveries are retried with exponential backoff:| Attempt | Delay | Total Time |
|---|---|---|
| 1 | Immediate | 0s |
| 2 | 1 minute | 1m |
| 3 | 5 minutes | 6m |
| 4 | 15 minutes | 21m |
| 5 | 1 hour | 1h 21m |
| 6 | 6 hours | 7h 21m |
Testing Webhooks
Webhook Testing Tool
Use tools like ngrok for local development:# Install ngrok
npm install -g ngrok
# Expose local server
ngrok http 3000
# Use the HTTPS URL for webhook registration
# https://abc123.ngrok.io/webhooks/unipay
Test Events
You can trigger test webhook events:curl -X POST "https://api.unipay.com/v1/webhooks/wh_1234567890abcdef/test" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{"event": "transaction.completed"}'
Managing Webhooks
List Webhooks
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.unipay.com/v1/webhooks
Update Webhook
curl -X PUT "https://api.unipay.com/v1/webhooks/wh_1234567890abcdef" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"events": ["transaction.completed", "transaction.failed", "transaction.pending"]
}'
Delete Webhook
curl -X DELETE "https://api.unipay.com/v1/webhooks/wh_1234567890abcdef" \
-H "Authorization: Bearer YOUR_API_KEY"
Error Responses
string
Error code identifier
string
Human-readable error message
object
Additional error context
Common Errors
| Code | Description |
|---|---|
INVALID_URL | Webhook URL is not valid HTTPS |
INVALID_EVENTS | Unknown event types specified |
URL_UNREACHABLE | Cannot reach webhook URL during validation |
WEBHOOK_LIMIT_EXCEEDED | Too many webhooks registered |
Rate Limits
Webhook registration is subject to rate limits:| Tier | Webhooks | Registrations/Hour |
|---|---|---|
| Free | 3 | 10 |
| Pro | 10 | 50 |
| Enterprise | 50 | 200 |
Next Steps
Transaction Status
Learn about transaction status polling as an alternative
API Introduction
Review authentication and rate limiting details