AL development
Ethiopian EIMS E-Invoicing Integration for Business Central: BC Connector, Signing Middleware and Mock Tax Authority
Integrates Dynamics 365 Business Central with Ethiopia’s EIMS e-invoicing system. When a sales invoice is posted, it is queued, mapped to the EIMS schema, digitally signed, and registered with the tax authority. The returned IRN and QR code are written back to the invoice. Built with an AL extension, a Node.js middleware for Azure Functions, and a mock EIMS server for testing.
Watch Solution Demo Video Project Documentation
- ERP side: AL extension for Business Central
- Middleware: Node.js 20+ Azure Functions v4
- Security: RSA-SHA512 digital signatures and X.509 certificate chains
Overview
The solution moves each invoice through a pipeline:
Post: BC posts a sales invoice, and a lightweight subscriber queues it.
Process: a scheduled job picks up queued invoices one at a time and builds a neutral JSON document from the posted data.
Transform: the middleware maps it to the EIMS schema, validates it, signs it and submits it.
Return: EIMS answers with an IRN and a signed QR. The middleware also generates a QR image, and BC stores the result against the invoice.
Users get an invoice log with statuses, a setup page, a QR factbox on the posted invoice, and clear handling of failures such as outages, rejections and duplicates.
Business problem
Ethiopian taxpayers are required to register invoices electronically with the Ministry of Revenue’s EIMS. Doing this well from an ERP is hard for several reasons:
Compliance without disruption: invoices must be registered, but tax-authority downtime must never stop a company from invoicing.
Strict chain integrity: each invoice carries a sequential counter and references the previous invoice’s IRN, so a duplicated or forked sequence causes rejections.
Cryptographic requirements: every request must be digitally signed with the taxpayer’s certificate, and private keys cannot sit in an ERP database.
Strict data rules: formats, lengths, buyer rules for B2B versus B2C, and date styles are demanding, and the specification is still a draft that changes.
Multi-tenant scale: a software provider may serve many taxpayers and wants to avoid redeploying an extension to every tenant for each spec change.
Solution and architecture
Three components, loosely coupled:

Key design decisions:
BC owns the IRN chain. Serverless functions are stateless and may run in parallel, which would fork the sequence. BC advances the counter and last IRN only after EIMS accepts, and a single job processes invoices strictly in order.
Posting is decoupled from submission. The posting event only writes a queue record, with no network calls. EIMS downtime therefore never blocks invoicing, and AL’s restrictions on HTTP inside open transactions are respected.
A clear status model:
Pending is waiting to be sent.
Retry means a transport failure, so the same counter is re-sent safely.
Rejected means a data problem, so the counter is released.
Needs Review means a duplicate or unknown outcome, and it pauses the queue until a person decides.
Mapping lives in the middleware, not in BC. BC sends facts, and tax figures are never recalculated downstream. Since the EIMS specification is a draft, a spec change is one middleware deployment rather than an extension upgrade for each tenant.
Keys never leave the vault. In production, signing is done by Azure Key Vault. Taxpayer credentials and certificate chains are resolved by TIN, so one function app can serve many companies.
The same code runs locally and in the cloud. A shared handler is used by both the Azure Function and a plain Node server, so local testing exercises production logic.
Technical implementation
BC extension. A subscriber on the sales posting event inserts a log record and marks the invoice Pending, without any I/O. A job queue entry runs the processor every minute. The processor first checks that nothing is stuck in Needs Review, then handles pending and retry items in order. It assigns each invoice its place in the chain, saves that assignment, commits, and only then makes the HTTP call. On a successful response it stores the IRN, acknowledgement date and QR, and advances the chain. A payload builder creates the neutral document from posted headers, lines and company and customer data. That includes handling of foreign-currency exchange rates and payment terms. Setup and log pages let administrators configure the connection and inspect or retry entries, and a permission set controls access.
Middleware. A single endpoint receives the invoice document and runs it through a short pipeline:
Mapping: converts the neutral document to the EIMS schema. It formats dates in Ethiopian time, converts tax percentages to tax codes, normalizes rounding, and applies B2B/B2C and credit-note rules.
Pre-flight validation: a JSON Schema check catches obvious errors, such as unit-of-measure length or TIN format, before they cost a call or a counter.
Signing and envelope: the request is signed with RSA-SHA512 and wrapped with the signature and the taxpayer’s certificate chain. In production the signature comes from Key Vault, and a placeholder encryption layer is ready to switch on.
Session handling: login tokens are cached per taxpayer and refreshed before expiry, with one automatic retry if a token is rejected.
Result contract: the middleware translates EIMS outcomes into a small set of HTTP results for BC: 200 registered, 422 rejected, 409 duplicate, 5xx retry later, 403 unknown taxpayer. It also renders the QR as a PNG, and it avoids logging payloads because they contain TINs and personal data.
Mock EIMS and test tooling. A local server imitates the tax authority. It verifies signatures against the supplied certificate, enforces duplicate-document, counter-sequence and previous-IRN rules, and saves invoices, lines and request logs to SQL Server, restoring the chain on restart. A dashboard shows registered invoices with search and CSV export. It also includes a failure-simulation panel (server errors, hangs, lost responses, rejections, duplicates and expired tokens) that exercises each BC status path end to end. Unit tests cover the mapper, validator and signer, and batch scripts handle setup and smoke testing.
Status and next steps. The solution runs end to end against the mock. Production use depends on confirming several open points in the draft EIMS specification: the encryption algorithm, the login request format and the certificate encoding. Planned work includes credit and debit notes, cancellations, withholding values, customer TIN fields, and bulk registration. Moving from function-key authentication to Entra ID is also on the list.