Messaging and Routing Protocols
The middleware uses an event-driven pipeline to process invoices. Every invoice event triggers a configurable sequence of actions. This page explains how events, actions, and webhook delivery work.
Invoice Events
The platform exposes the following event IDs. Use these IDs when configuring Event Routing rules.
Lifecycle — Outbound (platform → FIRS)
| Event ID | Description |
|---|---|
invoice.created | Invoice created in the system from an ERP webhook |
invoice.validated | Invoice passed schema and business rule validation |
invoice.signed | Invoice digitally signed with tenant FIRS credentials |
invoice.transmitted | Invoice transmitted to FIRS |
invoice.delivered | Invoice successfully delivered and acknowledged by FIRS — IRN issued |
Lifecycle — Inbound (FIRS/external → platform)
| Event ID | Description |
|---|---|
invoice.received | Inbound invoice received from an external system |
invoice.acknowledged | Inbound invoice acknowledged |
Lifecycle — Both directions
| Event ID | Description |
|---|---|
invoice.failed | Invoice processing failed at any stage |
invoice.rejected | Invoice rejected by FIRS or the receiving party |
invoice.canceled | Invoice canceled |
invoice.paid | Payment confirmed for the invoice |
ERP — Inbound (ERP → platform via webhook)
These are the event IDs your ERP sends in the X-Event-Type header when posting to the platform's inbound webhook URL.
| Event ID | Description |
|---|---|
erp.invoice.submitted | Invoice submitted from the ERP into the platform |
erp.invoice.updated | An existing invoice was updated in the ERP |
erp.invoice.voided | Invoice voided in the ERP |
erp.invoice.canceled | Invoice canceled in the ERP |
erp.payment.received | Payment recorded for an invoice in the ERP |
erp.creditnote.issued | Credit note issued from the ERP |
erp.debitnote.issued | Debit note issued from the ERP |
System
| Event ID | Description |
|---|---|
test.event | Test event used to verify webhook connectivity |
Workflow Actions
Workflow actions are the processing steps assigned to events in the Event Routing configuration.
Outbound actions (platform → FIRS)
| Action ID | Endpoint | Description |
|---|---|---|
transform | POST /api/v1/workflow/transform | Transform the ERP invoice payload into FIRS UBL format |
validate | POST /api/v1/workflow/validate | Validate the transformed invoice against FIRS schema and business rules |
sign | POST /api/v1/workflow/sign | Digitally sign the validated invoice using tenant FIRS credentials |
generate_irn | POST /api/v1/workflow/irn/generate | Generate an Invoice Reference Number (IRN) |
transmit | POST /api/v1/workflow/transmit | Transmit the signed invoice to the FIRS API |
complete_outbound | POST /api/v1/workflow/outbound | Execute the full outbound pipeline in one call: Transform → Validate → Sign → Transmit |
process_credit_note | POST /api/v1/workflow/credit-note | Process a credit note by fetching the original invoice and adapting it |
sync_erp | POST /api/v1/workflow/erp-sync | Push the processed invoice back to the tenant ERP using the configured sync endpoint and body template |
Inbound actions
| Action ID | Endpoint | Description |
|---|---|---|
complete_inbound | POST /api/v1/workflow/inbound | Execute the full inbound pipeline: receive, validate, and acknowledge an inbound invoice |
Reporting actions
| Action ID | Endpoint | Description |
|---|---|---|
report_vat | POST /api/v1/workflow/vat-report | Submit a VAT report for the invoice or reporting period to FIRS |
confirm_invoice_status | GET /api/v1/workflow/status/:irn | Query FIRS to confirm the current status of a transmitted invoice |
update_payment_status | PATCH /api/v1/workflow/invoices/outbound/:irn/payment-status | Submit a VAT post-payment report to FIRS after payment is recorded on a delivered invoice |
Event Routing Configuration
Event routing maps the event type from the incoming ERP webhook header to one or more workflow actions. You configure this per tenant from the Event Routing section under Webhooks in the admin settings, or via the admin API.
Get routing config
GET /v1/admin/tenants/{tenantId}/event-routing/
x-admin-key: YOUR_ADMIN_KEY
Set full routing config
PUT /v1/admin/tenants/{tenantId}/event-routing/
x-admin-key: YOUR_ADMIN_KEY
Content-Type: application/json
{
"routes": [
{
"event": "erp.invoice.submitted",
"actions": ["complete_outbound"],
"enabled": true,
"description": "Full outbound pipeline when ERP submits a new invoice"
},
{
"event": "erp.invoice.updated",
"actions": ["complete_outbound"],
"enabled": true,
"description": "Resubmit updated invoice through the full pipeline"
},
{
"event": "erp.payment.received",
"actions": ["update_payment_status"],
"enabled": true,
"description": "Submit FIRS VAT post-payment report when ERP records payment"
},
{
"event": "erp.creditnote.issued",
"actions": ["process_credit_note"],
"enabled": true,
"description": "Process credit note against the original IRN"
},
{
"event": "erp.debitnote.issued",
"actions": ["process_credit_note"],
"enabled": true,
"description": "Process debit note against the original IRN"
},
{
"event": "invoice.delivered",
"actions": ["sync_erp"],
"enabled": true,
"description": "Push completed invoice with IRN back to ERP after FIRS delivery"
}
]
}
Add a single route
POST /v1/admin/tenants/{tenantId}/event-routing/routes
x-admin-key: YOUR_ADMIN_KEY
Content-Type: application/json
{
"event": "erp.invoice.submitted",
"actions": ["complete_outbound"],
"enabled": true,
"description": "Full outbound pipeline on ERP invoice submission"
}
Clear all routes
DELETE /v1/admin/tenants/{tenantId}/event-routing/
x-admin-key: YOUR_ADMIN_KEY
Inbound Webhook — Receiving Invoices from Your ERP
Invoices enter the platform via an inbound webhook. The platform generates a unique webhook URL and webhook secret for each tenant. You copy these from the Webhooks settings page and register them in your ERP's outbound webhook configuration.
When your ERP fires an invoice event, it sends a POST request to the platform's webhook URL with:
- The event type in the request headers
- The invoice payload in the request body
The platform authenticates the request using the webhook secret, reads the event type from the headers, and executes the matching workflow actions from the Event Routing configuration. The invoiceIdKey is used to extract and store the unique invoice identifier from the payload.
Inbound webhook request format
POST https://platform.heirs.com/webhooks/{tenantId}
X-Event-Type: invoice.created
X-Webhook-Secret: whsec_...
Content-Type: application/json
{
"invoiceNumber": "INV-2026-001",
...
}
Outbound Webhook — Status Callbacks to Your ERP
After pipeline events fire (e.g. invoice.acknowledged), the platform can send status callbacks back to your ERP via a registered outbound webhook URL.
Registering an outbound webhook
PATCH /v1/tenants/{tenantId}
x-admin-key: YOUR_ADMIN_KEY
Content-Type: application/json
{
"webhookUrl": "https://yourapp.com/webhooks/heirs",
"webhookEnabled": true
}
Outbound webhook payload structure
{
"event": "invoice.acknowledged",
"tenantId": "ten_01j9ab2c3d4e5f6g",
"timestamp": "2026-06-17T10:30:00Z",
"data": {
"invoiceId": "INV-2026-001",
"irn": "IRN-2026-ACME-001",
"status": "acknowledged"
}
}
Delivery guarantees
| Property | Detail |
|---|---|
| Protocol | HTTPS POST only |
| Response timeout | 30 seconds — return 2xx within 30s |
| Retry policy | Up to maxRetries (1–10) attempts, configurable |
| Test webhook | POST /v1/tenants/{tenantId}/webhook/test |
:::caution Respond quickly
Return a 2xx HTTP status immediately on receipt. If your processing takes longer, acknowledge first and handle in a background job. Failed deliveries are retried per your tenant's maxRetries setting.
:::
ERP Sync
ERP Sync is the return-path configuration — it defines how the platform sends the finished invoice back to your ERP once FIRS has delivered and acknowledged it. It is implemented as the sync_erp workflow action (POST /api/v1/workflow/erp-sync), which pushes the completed invoice record (including the IRN and QR code stamp) to your ERP using a configured sync endpoint and Handlebars body template.
ERP Sync covers the outbound direction only (platform → ERP) and is a separate configuration menu from Event Routing. The typical trigger is mapping invoice.delivered → sync_erp in your Event Routing config.
Reference: Fetching Events and Actions at Runtime
Fetch the full event catalogue:
GET /v1/admin/config/reference/events
x-admin-key: YOUR_ADMIN_KEY
Filter by category or direction:
?category=lifecycle # lifecycle | payment | system | erp
?direction=inbound # inbound | outbound | both
Fetch all workflow actions:
GET /v1/admin/config/reference/workflow-actions
x-admin-key: YOUR_ADMIN_KEY
Filter by category:
?category=outbound # outbound | inbound | reporting