Webhooks
Receive real-time notifications about events in your account. Webhooks are triggered for every relevant action.
Real-time Events
Instant notification on invoice creation, validation, and more
Signed
HMAC-SHA256 signatures to verify authenticity
Automatic Retries
On failure, webhooks are automatically resent
Available Events
| Event | Description | Trigger |
|---|---|---|
invoice.created | A new invoice was successfully created | POST /api/v1/invoice/de/xrechnung/generate successful |
invoice.validation_failed | Invoice validation failed | E-invoice does not match the schema |
invoice.downloaded | XML or PDF was downloaded | GET /api/v1/invoice/de/xrechnung/generate/{id}/xml or /pdf |
conversion.completed | Format conversion completed | POST /v1/convert successful |
conversion.failed | Format conversion failed | Conversion error |
peppol.sent | E-invoice sent via Peppol | Peppol transmission successful |
peppol.delivered | Delivery confirmation received from Peppol | MDN from recipient |
peppol.failed | Peppol transmission failed | Transmission error |
Webhook Payload
All webhooks are sent as HTTP POST with JSON body:
1{2 "id": "evt_abc123xyz",3 "type": "invoice.created",4 "created": "2025-01-15T10:30:00Z",5 "data": {6 "object": {7 "id": "inv_xyz789",8 "status": "valid",9 "format": "XRechnung 3.0.2",10 "invoiceNumber": "RE-2025-001",11 "totals": {12 "net": 1500.00,13 "vat": 285.00,14 "gross": 1785.0015 },16 "download": {17 "xml": "https://service.invoice-api.xhub.io/api/v1/invoice/de/xrechnung/generate/inv_xyz789/xml",18 "pdf": "https://service.invoice-api.xhub.io/api/v1/invoice/de/xrechnung/generate/inv_xyz789/pdf"19 }20 }21 }22}HTTP Headers
X-Xhub-SignatureHMAC-SHA256 signature of the payload
X-Xhub-EventEvent type (e.g. invoice.created)
X-Xhub-DeliveryUnique delivery ID
X-Xhub-TimestampUnix timestamp of signature creation
Signature Verification
Always verify the signature to ensure the webhook comes from Invoice-api.xhub:
Node.js / Express
1import crypto from 'crypto';2 3function verifyWebhookSignature(payload, signature, secret) {4 const expectedSignature = crypto5 .createHmac('sha256', secret)6 .update(payload)7 .digest('hex');8 9 const trusted = Buffer.from(`sha256=${expectedSignature}`, 'ascii');10 const untrusted = Buffer.from(signature, 'ascii');11 12 return crypto.timingSafeEqual(trusted, untrusted);13}14 15// Express.js Handler16app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {17 const signature = req.headers['x-xhub-signature'];18 const payload = req.body;19 20 if (!verifyWebhookSignature(payload, signature, process.env.WEBHOOK_SECRET)) {21 return res.status(401).send('Invalid signature');22 }23 24 const event = JSON.parse(payload);25 26 switch (event.type) {27 case 'invoice.created':28 console.log('Invoice created:', event.data.object.id);29 break;30 case 'invoice.validation_failed':31 console.log('Validation failed:', event.data.object.errors);32 break;33 }34 35 res.status(200).send('OK');36});Python / Flask
1import hmac2import hashlib3from flask import Flask, request, abort4 5app = Flask(__name__)6WEBHOOK_SECRET = 'your_webhook_secret'7 8def verify_signature(payload, signature, secret):9 expected = hmac.new(10 secret.encode(),11 payload,12 hashlib.sha25613 ).hexdigest()14 return hmac.compare_digest(f'sha256={expected}', signature)15 16@app.route('/webhook', methods=['POST'])17def webhook():18 signature = request.headers.get('X-Xhub-Signature')19 payload = request.data20 21 if not verify_signature(payload, signature, WEBHOOK_SECRET):22 abort(401)23 24 event = request.json25 26 if event['type'] == 'invoice.created':27 print(f"Invoice created: {event['data']['object']['id']}")28 elif event['type'] == 'invoice.validation_failed':29 print(f"Validation failed: {event['data']['object']['errors']}")30 31 return 'OK', 200Retry Policy
If your endpoint does not respond with 2xx, the webhook will be resent:
| Attempt | Delay |
|---|---|
| 1 | Immediately |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 6 | 12 hours |
After 6 failed attempts, the webhook is marked as failed. You will be notified by email.
Best Practices
Respond Quickly
Respond within 5 seconds with 200 OK. Process the webhook asynchronously in the background.
Verify Signature
Always verify the HMAC signature. Reject requests without a valid signature.
Ensure Idempotency
Store the delivery ID and process each webhook only once (duplicates may occur during retries).
Use HTTPS
Your webhook endpoint must support HTTPS. HTTP endpoints are not accepted.
Set Up Webhook
Webhooks are configured in the dashboard. There you can:
- • Set endpoint URL
- • Select events to be sent
- • View and rotate webhook secret
- • View delivery logs and failed webhooks