Events

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

EventDescriptionTrigger
invoice.createdA new invoice was successfully createdPOST /api/v1/invoice/de/xrechnung/generate successful
invoice.validation_failedInvoice validation failedE-invoice does not match the schema
invoice.downloadedXML or PDF was downloadedGET /api/v1/invoice/de/xrechnung/generate/{id}/xml or /pdf
conversion.completedFormat conversion completedPOST /v1/convert successful
conversion.failedFormat conversion failedConversion error
peppol.sentE-invoice sent via PeppolPeppol transmission successful
peppol.deliveredDelivery confirmation received from PeppolMDN from recipient
peppol.failedPeppol transmission failedTransmission error

Webhook Payload

All webhooks are sent as HTTP POST with JSON body:

json
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.00
15 },
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-Signature

HMAC-SHA256 signature of the payload

X-Xhub-Event

Event type (e.g. invoice.created)

X-Xhub-Delivery

Unique delivery ID

X-Xhub-Timestamp

Unix timestamp of signature creation

Signature Verification

Always verify the signature to ensure the webhook comes from Invoice-api.xhub:

Node.js / Express

typescript
1import crypto from 'crypto';
2 
3function verifyWebhookSignature(payload, signature, secret) {
4 const expectedSignature = crypto
5 .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 Handler
16app.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

python
1import hmac
2import hashlib
3from flask import Flask, request, abort
4 
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.sha256
13 ).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.data
20 
21 if not verify_signature(payload, signature, WEBHOOK_SECRET):
22 abort(401)
23 
24 event = request.json
25 
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', 200

Retry Policy

If your endpoint does not respond with 2xx, the webhook will be resent:

AttemptDelay
1Immediately
21 minute
35 minutes
430 minutes
52 hours
612 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