Webhooks and Events
Real-time notifications from Debitura when important events occur in your cases.
Overview
Webhooks enable Debitura to push real-time notifications to your application when events occur, eliminating the need for constant polling.
Benefits:
- Real-time updates
- Reduced API calls
- Lower latency
- Event-driven architecture
- Reliable delivery with retries
How Webhooks Work
Basic Flow
- Event occurs in Debitura (e.g., payment received)
- Webhook triggered for registered endpoints
- HTTP POST sent to your endpoint URL
- Your server processes the webhook payload
- Acknowledgment returned (HTTP 200-299 response)
- Retry if failed (automatic retry logic)
Webhook Anatomy
HTTP Request:
POST /webhooks/debitura HTTP/1.1
Host: your-server.com
Content-Type: application/json
X-Debitura-Signature: sha256=abc123...
X-Debitura-Event: payment.received
X-Debitura-Webhook-Id: whk_xyz789
{
"id": "evt_abc123",
"type": "payment.received",
"created_at": "2024-01-15T10:30:00Z",
"data": {
"case_id": "case_xyz789",
"payment_id": "pmt_abc456",
"amount": 10000,
"currency": "EUR"
}
}
Event Types
Case Events
Case lifecycle:
case.created- New case submittedcase.status_changed- Case status updatedcase.assigned- Case assigned to Collection Partnercase.suspended- Case suspendedcase.resumed- Case resumed from suspensioncase.closed- Case closed
Case updates:
case.updated- Case information modifiedcase.note_added- Note added to casecase.document_uploaded- Document attached
Payment Events
Payment processing:
payment.received- Payment received from debtorpayment.allocated- Payment allocated to invoicespayment.failed- Payment processing failedpayment.refunded- Payment refunded
Payment plans:
payment_plan.created- Installment plan establishedpayment_plan.payment_due- Installment due soonpayment_plan.payment_missed- Installment payment missedpayment_plan.completed- All installments paidpayment_plan.defaulted- Payment plan failed
Payout Events
Creditor payouts:
payout.scheduled- Payout preparedpayout.processing- Transfer initiatedpayout.completed- Funds sent successfullypayout.failed- Transfer failed
Communication Events
Debtor communications:
communication.sent- Message sent to debtorcommunication.received- Response received from debtorcommunication.bounced- Message delivery failed
Partner Events
For Referral Partners:
referral.case_submitted- Case submitted by your customerreferral.commission_earned- Commission generated
For Collection Partners:
assignment.received- New case assignedassignment.updated- Assignment details changedassignment.completed- Case work finished
Webhook Setup
Creating a Webhook
Via Portal:
- Navigate to Settings → Webhooks
- Click "Add Webhook Endpoint"
- Enter endpoint URL
- Select event types to receive
- Save and activate
Via API:
POST /v1/webhooks
{
"url": "https://your-server.com/webhooks/debitura",
"events": ["payment.received", "case.status_changed"],
"description": "Production webhook",
"secret": "whsec_your_secret_key"
}
Webhook Configuration
Required fields:
url- HTTPS endpoint (HTTP not allowed)events- Array of event types to receive
Optional fields:
description- Internal label for webhooksecret- Custom signing secret (auto-generated if omitted)metadata- Custom key-value dataenabled- Active status (default: true)
Security
Signature Verification
Every webhook includes a signature header to verify authenticity.
Header:
X-Debitura-Signature: sha256=abc123def456...
Verification steps:
-
Extract components:
- Timestamp from
X-Debitura-Timestampheader - Signature from
X-Debitura-Signatureheader - Webhook secret (from creation response)
- Timestamp from
-
Construct signed payload:
timestamp + "." + JSON body -
Compute HMAC:
HMAC-SHA256(signed_payload, webhook_secret) -
Compare signatures:
- Must match exactly
- Use constant-time comparison
Example (Node.js):
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret, timestamp) {
// Construct signed payload
const signedPayload = `${timestamp}.${payload}`;
// Compute expected signature
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
// Compare signatures (constant-time)
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(`sha256=${expectedSignature}`)
);
}
Example (Python):
import hmac
import hashlib
def verify_webhook_signature(payload, signature, secret, timestamp):
# Construct signed payload
signed_payload = f"{timestamp}.{payload}"
# Compute expected signature
expected_signature = hmac.new(
secret.encode(),
signed_payload.encode(),
hashlib.sha256
).hexdigest()
# Compare signatures
return hmac.compare_digest(
signature,
f"sha256={expected_signature}"
)
Timestamp Validation
Prevent replay attacks by validating timestamps:
const WEBHOOK_TOLERANCE = 300; // 5 minutes
function isTimestampValid(timestamp) {
const now = Math.floor(Date.now() / 1000);
return Math.abs(now - timestamp) < WEBHOOK_TOLERANCE;
}
Best Practices
- Always verify signatures - Never trust unverified webhooks
- Validate timestamps - Prevent replay attacks
- Use HTTPS - Encrypt webhook data in transit
- Rotate secrets - Periodically update webhook secrets
- Validate payload structure - Check expected fields exist
- Handle duplicates - Use idempotency (event IDs)
Handling Webhooks
Endpoint Requirements
Your webhook endpoint must:
- Accept POST requests
- Use HTTPS (TLS 1.2+)
- Respond within 5 seconds
- Return HTTP 200-299 for success
- Return HTTP 500+ for retryable failures
Response Codes
| Code | Meaning | Debitura Action |
|---|---|---|
| 200-299 | Success | Mark as delivered |
| 400-499 | Client error | Mark as failed (no retry) |
| 500-599 | Server error | Retry with backoff |
| Timeout | No response in 5s | Retry with backoff |
Processing Pattern
Recommended approach:
app.post('/webhooks/debitura', async (req, res) => {
// 1. Verify signature FIRST
const isValid = verifyWebhookSignature(
req.body,
req.headers['x-debitura-signature'],
WEBHOOK_SECRET,
req.headers['x-debitura-timestamp']
);
if (!isValid) {
return res.status(401).json({ error: 'Invalid signature' });
}
// 2. Respond immediately (acknowledge receipt)
res.status(200).json({ received: true });
// 3. Process asynchronously
processWebhookAsync(req.body);
});
async function processWebhookAsync(webhook) {
try {
// Parse event
const { type, data } = webhook;
// Route to appropriate handler
switch (type) {
case 'payment.received':
await handlePaymentReceived(data);
break;
case 'case.status_changed':
await handleStatusChange(data);
break;
default:
console.log(`Unhandled event type: ${type}`);
}
} catch (error) {
console.error('Webhook processing failed:', error);
// Log for manual review
}
}
Retry Logic
Automatic Retries
If your endpoint fails, Debitura automatically retries:
Retry schedule:
- Attempt 1: Immediately
- Attempt 2: 5 seconds later
- Attempt 3: 30 seconds later
- Attempt 4: 2 minutes later
- Attempt 5: 10 minutes later
- Attempt 6: 1 hour later
- Attempt 7: 6 hours later
- Attempt 8: 24 hours later
Maximum attempts: 8
Backoff strategy: Exponential with jitter
Failed Webhooks
After all retries exhausted:
- Webhook marked as failed in portal
- Alert sent to account administrators
- Event data retained for manual replay
Manual replay:
- Available in webhook dashboard
- Reprocesses failed event
- Follows same retry schedule
Testing Webhooks
Webhook Testing Tool
Via Portal:
- Navigate to Webhooks → Test
- Select event type
- Customize payload (optional)
- Send test webhook
- View request/response
Via API:
POST /v1/webhooks/{webhook_id}/test
{
"event_type": "payment.received"
}
Local Development
Use ngrok or similar:
# Expose local server
ngrok http 3000
# Use ngrok URL in webhook configuration
https://abc123.ngrok.io/webhooks/debitura
Sandbox environment:
- Test webhooks in sandbox
- Same event types as production
- No impact on live data
Monitoring Webhooks
Webhook Dashboard
Portal features:
- Delivery success rates
- Failed webhook alerts
- Recent deliveries log
- Retry status
- Response times
Metrics tracked:
- Total webhooks sent
- Success rate (last 24h, 7d, 30d)
- Average response time
- Failed deliveries by endpoint
- Event type distribution
Webhook Logs
Event details:
- Timestamp
- Event type
- Payload
- HTTP status received
- Response body
- Retry attempts
Log retention: 30 days
Export logs:
- CSV export
- API access:
GET /v1/webhooks/{id}/deliveries
Best Practices
Development
- Start with sandbox - Test integration thoroughly
- Verify signatures - Security first
- Handle all event types - Unknown types may be added
- Idempotent processing - Use event IDs to prevent duplicates
- Respond quickly - Acknowledge within seconds
- Process asynchronously - Don't block webhook response
Production
- Monitor delivery rates - Set up alerts for failures
- Log webhook payloads - For debugging and audit
- Implement retry logic - On your side for critical operations
- Scale endpoint - Handle traffic spikes
- Use queue systems - Decouple receipt from processing
- Update webhook URLs - When deploying infrastructure changes
Error Handling
- Return proper status codes - Guide retry behavior
- Log errors thoroughly - Include context for debugging
- Alert on failures - Don't rely on manual checks
- Implement circuit breakers - Prevent cascading failures
- Manual replay capability - For failed critical events
Troubleshooting
Common Issues
Webhook not received:
- Check endpoint is accessible (HTTPS, not firewalled)
- Verify correct URL in configuration
- Check event type is enabled
- Review webhook dashboard for errors
Signature verification fails:
- Ensure using correct webhook secret
- Check timestamp tolerance
- Verify payload not modified
- Use raw body (not parsed JSON)
Timeouts:
- Respond faster (< 5 seconds)
- Process asynchronously
- Optimize endpoint performance
- Check for blocking operations
Duplicate events:
- Implement idempotency using event IDs
- Check for retry processing
- Verify not configured multiple times
Next Steps
- Implement idempotency for reliable webhook processing
- Understand security and audit practices
- Review API reference for webhook management endpoints