FIRS e-invoicing platform
A live compliance platform that takes whatever an ERP sends and turns it into a UBL e-invoice that Nigeria's tax authority will issue an IRN for.
Debit · what made it hard
Every ERP has its own dialect, and FIRS accepts exactly one. The invoice must be validated UBL with the right tax identifiers and product codes, or no IRN is issued.
Credit · what shipped
High-throughput Go services on Kubernetes, integrations for six ERP families, and no public ingress to origin. Every integration failure is visible in Grafana.
Context
Nigeria’s e-invoicing mandate means every qualifying invoice has to be validated by the tax authority (FIRS, now NRS) and stamped with an Invoice Reference Number (IRN) before it counts. Businesses don’t produce invoices in that format. They produce whatever ERPNext, Sage, QuickBooks, SAP or Tally gives them.
I lead engineering on the platform that sits in between. It’s live, and I set its technical direction.
What I built
The transformation layer. High-throughput Go (Gin) services that normalise mixed ERP payloads into UBL-compliant e-invoices. They’re built contract-first against OpenAPI/Swagger specs, so every integration knows exactly what it’s promising before any code is written.
Multi-tenant tax validation. It checks corporate CAC and individual TIN identifiers and handles B2B, B2G and B2C invoice kinds. It also maps products to the HS/HSN/ISIC codes the mandate requires. If validation is going to fail, it fails at the platform, not at the tax authority.
The ERP integration surface:
- ERPNext and Frappe hooks
- Sage 200 and Sage Business Cloud
- QuickBooks
- SAP outbound, with OAuth 2.0 and base64 PDF delivery
- Tally Prime
Security at the edge. The Go services sit behind Cloudflare Zero Trust tunnels, with WAF managed rulesets and rate limiting. Origin has no direct public ingress at all.
Observability. I set up cross-namespace Prometheus, Loki and Grafana for scrape targets, log aggregation and alerts on integration failures. In compliance work, a silent failure is just a fine that hasn’t arrived yet.
Leading it
Beyond the code, I own the accreditation path: moving the platform from working through a partner Access Point Provider to direct FIRS accreditation.