Push-style integration is the right pattern. Subscribe once, receive every state change forever. 32 event types at launch covering invoicing, payments, payroll, and tax. HMAC-SHA256 signatures. Exponential-backoff retries. 30-day replay window.
Polling the API to check for state changes is wasteful: 99% of requests return "no change," and the 1% that matter arrive minutes late. Webhooks invert the model — HIBR pushes events to your endpoint within 5 seconds of the underlying state change.
For UAE-specific workflows, webhooks matter especially for:
Every webhook delivery is an HTTPS POST with a stable JSON payload structure:
# Standard event envelope POST https://your-endpoint.com/hibr-webhook HTTP/1.1 Content-Type: application/json Hibr-Event: invoice.paid Hibr-Event-Id: evt_01HFQB... Hibr-Signature: t=1729000080,v1=5257a86... Hibr-Webhook-Endpoint: wh_01HFQA... { "id": "evt_01HFQB...", "object": "event", "type": "invoice.paid", "created": "2026-10-15T09:32:14Z", "api_version": "2026-10-01", "livemode": true, "data": { "object": { / Full invoice resource at the moment of the event "id": "inv_01HFQB...", "object": "invoice", "status": "paid", ... }, "previous_attributes": { / Only changed fields, for diff calculation "status": "open" } } }
Key fields:
id — unique event ID (idempotency key on your side)type — event type from the catalog (§7)data.object — the resource at the moment of the eventdata.previous_attributes — only fields that changed (useful for diff-based logic)livemode — true for production, false for sandboxHIBR expects your endpoint to respond with HTTP 2xx within 10 seconds. Slower than 10 seconds counts as a failed delivery and triggers retry. Anything other than 2xx counts as a failed delivery.
Every webhook is signed with HMAC-SHA256 using a secret shared at subscription time. Verify the signature before processing the payload — otherwise an attacker who knows your endpoint URL could send forged events.
Hibr-Signature: t=1729000080,v1=5257a86a9eb1d77a4d3c7e2f9b8a6c5e4d3b2a1f0e9d8c7b6a5f4e3d2c1b0a9f8
t — Unix timestamp of when HIBR computed the signaturev1 — HMAC-SHA256 hex digest of {timestamp}.{raw_body} using your endpoint secrett and v1 from the Hibr-Signature header.t is more than 5 minutes old (replay protection).HMAC-SHA256(secret, "{t}.{raw_request_body}").v1. Reject if mismatch.# Node.js example const crypto = require('crypto'); function verifyWebhook(rawBody, signature, secret) { const parts = Object.fromEntries(signature.split(',').map(p => p.split('='))); const t = parts.t, v1 = parts.v1; / Replay protection — 5-minute window if (Math.abs(Date.now()/1000 - parseInt(t)) > 300) return false; const expected = crypto .createHmac('sha256', secret) .update(`${t}.${rawBody}`) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(expected), Buffer.from(v1) ); }
If your endpoint fails to respond with 2xx within 10 seconds, HIBR retries with exponential backoff. Up to 8 attempts spanning 72 hours.
After attempt 8, the event is marked permanently failed. Permanent failures are retrievable via the replay endpoint (§5) for 30 days.
Endpoints that fail 100 consecutive deliveries are automatically disabled, with an email notification to the developer contact. Re-enable from the dashboard.
Every event delivered (or attempted) is retrievable for 30 days. Useful for:
| GET /v1/events | List events (filterable by type, created.gte, delivery_status) |
| GET /v1/events/{event_id} | Retrieve a single event with full payload |
| POST /v1/events/{event_id}/redeliver | Trigger immediate redelivery to all subscribed endpoints |
| POST /v1/events/{event_id}/redeliver?endpoint=wh_xxx | Redeliver to a specific endpoint |
Webhook endpoints are first-class resources. Manage them via API or in the dashboard.
| POST /v1/webhook-endpoints | Create an endpoint |
| GET /v1/webhook-endpoints | List endpoints |
| GET /v1/webhook-endpoints/{id} | Retrieve one |
| PATCH /v1/webhook-endpoints/{id} | Update (URL, event subscriptions, enabled state) |
| DELETE /v1/webhook-endpoints/{id} | Delete |
| POST /v1/webhook-endpoints/{id}/rotate-secret | Rotate the signing secret without changing the URL |
{
"id": "wh_01HFQA...",
"object": "webhook_endpoint",
"url": "https://your-server.com/hibr",
"description": "Production payment processor",
"enabled_events": ["invoice.paid", "payment.succeeded"],
"status": "enabled",
"created": "2026-10-15T09:32:14Z",
"secret": "whsec_..." / only on creation + rotate
}
32 event types at launch, grouped by resource. Subscribe to specific events or use wildcards (e.g., invoice.*).
| invoice.created | New invoice created (draft state) |
| invoice.updated | Invoice modified before posting |
| invoice.posted | Invoice posted to the ledger (immutable from here) |
| invoice.sent | Invoice emailed to the customer |
| invoice.viewed | Customer opened the invoice PDF via portal link |
| invoice.paid | Invoice fully paid |
| invoice.overdue | Invoice past due date |
| invoice.voided | Invoice voided (with reversing entries posted) |
| bill.created | New bill (purchase invoice) recorded |
| bill.approved | Bill passes approval workflow |
| bill.paid | Bill marked paid |
| credit_note.created | Credit note issued (sales or purchase) |
| payment.succeeded | Payment received and matched to invoice(s) |
| payment.failed | Payment attempt failed (Stripe, gateway, bank refusal) |
| payment.refunded | Full or partial refund processed |
| bank_feed.transaction.created | New transaction received from bank feed |
| bank_feed.reconciliation.matched | Bank transaction matched to an invoice or bill |
| vat_return.draft.ready | VAT 201 draft generated, ready for review |
| vat_return.submitted | VAT 201 submitted to FTA |
| vat_return.accepted | FTA accepted the submission |
| vat_return.rejected | FTA rejected — includes error reason from FTA |
| ct_return.draft.ready | CT-201 draft generated |
| ct_return.submitted | CT-201 submitted to FTA |
| e_invoice.sent | PINT-AE e-invoice delivered via PEPPOL |
| e_invoice.acknowledged | Recipient's accounting system acknowledged receipt |
| e_invoice.failed | Delivery failed — includes failure reason |
| payroll_run.created | New payroll cycle initiated |
| payroll_run.approved | Payroll approved + ready for WPS |
| wps_file.generated | SIF file generated |
| wps_file.submitted | SIF submitted to WPS agent bank |
| wps_file.accepted | Bank confirmed processing |
| wps_file.rejected | Bank rejected the file — includes row-level errors |
| employee.offboarded | Employee terminated, gratuity calculation triggered |
id — store the ID of each processed event and reject duplicates. Retries can deliver the same event twice.https://api.hibr.ai/security/egress-ips (post-launch). Restrict your endpoint to only accept connections from this list at the firewall.created timestamp on the event payload for ordering logic, not arrival time.
Sandbox at sandbox-api.hibr.ai opens in August 2026. You'll be able to create webhook endpoints, generate test events, and verify your signature-verification logic before production launch.