Appearance
Webhook Integration
Webhooks notify your application when events occur in OVN Pay.
Webhook Events
| Event | Description |
|---|---|
payout.created | A payout was created |
payout.succeeded | A payout completed successfully |
payout.failed | A payout failed |
payout.cancelled | A payout was cancelled |
batch.released | A batch was released for processing |
batch.completed | A batch finished processing |
Setup Webhook URL
Configure your webhook URL via API:
http
POST /api/v1/webhooksBody:
json
{
"url": "https://your-app.com/webhooks/ovn",
"events": ["payout.succeeded", "payout.failed"]
}Verify Webhook Signatures
All webhook payloads are signed with a signature header:
X-Webhook-Signature: t=1234567890,v1=abc123...Verification (TypeScript)
typescript
import { createHmac } from 'crypto';
export function verifyWebhookSignature(
payload: string,
signature: string,
secret: string
): boolean {
const [t, v1] = signature.split(',');
const expectedSignature = createHmac('sha256', secret)
.update(`${t}.${payload}`)
.digest('hex');
return `v1=${expectedSignature}` === v1;
}Verification (Node.js Express)
javascript
import crypto from 'crypto';
app.post('/webhooks/ovn', (req, res) => {
const signature = req.headers['x-webhook-signature'];
const payload = JSON.stringify(req.body);
const hmac = crypto.createHmac('sha256', process.env.WEBHOOK_SECRET)
.update(payload)
.digest('hex');
const expected = `v1=${hmac}`;
if (signature !== expected) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process webhook
const event = req.body;
console.log('Event type:', event.type);
res.json({ success: true });
});Verification (Go)
go
import (
"crypto/hmac"
"encoding/hex"
"strings"
)
func verifyWebhookSignature(payload, signature, secret string) bool {
parts := strings.Split(signature, ",")
t := parts[0]
v1 := parts[1]
h := hmac.NewSHA256.New()
h.Write([]byte(t + "." + payload))
expected := "v1=" + hex.EncodeToString(h.Sum(nil))
return v1 == expected
}Best Practices
- Use HTTPS - Always use HTTPS for webhook URLs
- Verify Signatures - Always verify webhook signatures
- Handle Idempotency - Webhooks may be sent multiple times
- Respond Quickly - Respond within 5 seconds with 200 OK
- Retry Logic - Implement exponential backoff for failed deliveries
- Log Everything - Log all webhook events for debugging
Event Payload Structure
All webhook events follow this structure:
json
{
"id": "evt_abc123",
"type": "payout.succeeded",
"data": {
"payoutId": "payout_123",
"driverId": "drv_abc123",
"amount": 50000,
"status": "succeeded",
"completedAt": "2025-01-15T10:30:00Z"
},
"timestamp": "2025-01-15T10:30:00Z"
}