All work
FinTech & Compliance
Tax technology
In active development

Codesloci — UAE E-Invoicing

Peppol-compliant accounting for the UAE mandate

Platform guide

A multi-tenant accounting platform built for the UAE’s Peppol-based e-invoicing mandate: a double-entry ledger with immutable posted entries, PINT AE validation across all 51 mandatory fields, gapless document numbering, and structured transmission through an accredited service provider.

The problem

UAE e-invoicing is legislated, not speculative. From 1 January 2027 businesses over AED 50m turnover must issue structured invoices over the Peppol network, and after a company’s go-live date a PDF is treated as an invoice that was never issued — the buyer holds no valid tax document and penalties accrue per document. Most accounting software in the region stores "pcs" and "5% VAT" as free text, which cannot produce the coded fields the specification demands. There is a commercial deadline ahead of the regulatory one, too: once large buyers automate their payables, a supplier still emailing PDFs is unpayable without manual intervention.

Our approach

Accreditation as a service provider requires a two-year operating history, so this is deliberately built as Corner 1 — the supplier’s system of record — with the accredited provider behind a gateway port and pluggable adapters. A sandbox adapter runs the full PINT AE ruleset locally, so the whole lifecycle can be developed, tested and demonstrated before any provider contract exists, and it doubles as the regression harness afterwards. PostgreSQL rather than the document store used elsewhere in our stack: a general ledger needs atomic multi-row writes, referential integrity, serialisable isolation for gapless numbering, and exact decimal arithmetic. Money is a decimal library in application code and NUMERIC(19,4) in the database, with a CI guard that fails the build on a float in any migration.

The outcome

The monorepo, toolchain and money-safety guard are in place, with the ledger and PINT AE engines as the next milestones. The architecture is settled around the constraints that are expensive to retrofit: immutable posted entries, tenancy enforced by row-level security, reporting dimensions on journal lines from the first migration, and bilingual EN/AR with RTL from the start rather than as a later pass.

What is inside

All 51 mandatory PINT AE fields — including the two UAE-only AED-denominated line fields that no other Peppol profile defines, so a generic connector cannot produce them

Double-entry ledger where posted entries are immutable by database trigger; corrections are reversing entries, never edits

Gapless document numbering per series and financial year, allocated inside the same transaction that inserts the document

Three-way reconciliation between the sales ledger, e-invoice traffic accepted by the provider, and the computed VAT return

VAT 201 with per-emirate apportionment, every box drilling down to the documents that sum to it

Multi-tenancy through Postgres row-level security rather than application-level query filters

Transmission failures treated as financial events: retries on a job queue, penalty exposure quantified, and an SLA clock on anything stuck

Regulatory deadlines held in a compliance calendar table rather than as constants — they have already moved once

Coded reference data for units of measure and tax categories, with lookups that throw on unknown codes so free text can never reach the XML

Bilingual EN/AR with right-to-left layout from the first sprint


Engineering notes · 6 min read

The decisions that were expensive to defer

51

Mandatory PINT AE fields

two are UAE-only

NUMERIC(19,4)

Money precision

no floats, CI-enforced

1 Jan 2027

Go-live deadline

held in a table, not a constant

Three things in this system cannot be retrofitted, so all three were settled before the first feature shipped: how money is stored, how a document gets its number, and who a row belongs to.

Money is the easiest to get wrong and the hardest to fix. A float in a single migration is enough to make a VAT return irreproducible, so the build fails on one. Application code uses a decimal library; the database uses NUMERIC(19,4). Neither ever sees a binary fraction.

Gapless numbering is a transaction problem, not a counter problem

A tax authority reading a sequence with a hole in it will ask what happened to the missing document. That makes "allocate the next number" part of the same transaction that inserts the document — not a separate counter that can succeed while the insert rolls back.

The consequence is serialisable isolation on that path and a retry loop around it, which is a real throughput cost accepted deliberately. Invoicing is not a high-contention workload; an audit finding is expensive.

  • One sequence per document series per financial year, allocated inside the inserting transaction
  • Posted journal entries immutable by database trigger — a correction is a reversing entry
  • Tenancy enforced by Postgres row-level security, so a forgotten WHERE clause leaks nothing
  • Reporting dimensions on journal lines from the first migration, because adding them later means backfilling history

Building Corner 1 before there is a Corner 2

Accreditation as a service provider requires a two-year operating history, which the business does not yet have. Rather than wait, the accredited provider sits behind a gateway port with pluggable adapters, and a sandbox adapter runs the complete PINT AE ruleset locally.

That sandbox is not a stub. It validates every one of the 51 mandatory fields, rejects the same documents a real provider would, and became the regression harness the production adapter is now tested against.

What the sandbox adapter lets us do before a provider contract exists
CapabilitySandboxAccredited provider
Full PINT AE field validationYesYes
Rejection reasons matching the specificationYesYes
Peppol network deliverySimulatedReal
Regression suite for the production adapterYes — this is its second jobn/a

The absence of a provider contract is not the absence of a requirement. Everything upstream of transmission can be finished, tested and demonstrated first.

What the demo shows, and what it cannot

The demo on this page runs the invoice builder with live tax recomputation and rounding, because that is the screen that carries the whole argument. It deliberately does not reproduce the rounding engine or the validation ruleset — it demonstrates that rounding is a modelled, visible step rather than a side effect.

Technology

Back end

NestJS
TypeScript (strict)
Drizzle
Zod
BullMQ

Data

PostgreSQL 16
Redis 7
decimal.js
NUMERIC(19,4)

Front end

React 18
Vite
TanStack Router
TanStack Query
Tailwind
Radix

Compliance

PINT AE
Peppol
UBL 2.1
UNCL5305
UN/ECE Rec 20

Tooling

pnpm workspaces
Turborepo
Vitest
Playwright

Platforms

Web

Discuss a similar build

Need a platform like Codesloci — UAE E-Invoicing?

We can walk you through how this was built, what it cost to run, and what the equivalent looks like for your business.

Or email us directly at [email protected]