Inside the Oman Tax Data Document (TDD): Engineering Walkthrough
Engineering deep-dive into Oman's Tax Data Document (TDD): structure, mapping from PINT OM invoices, Schematron rules, generator design and submission flow.
The TDD in one paragraph
The Tax Data Document (TDD) is Oman's CTC artefact. It is a structured XML document, generated from the underlying PINT OM invoice, that the Oman Tax Authority (OTA) receives in real time alongside the invoice flow on Peppol. It is not the invoice. The invoice itself reaches the buyer through the Peppol four-corner network using the PINT OM customisation. The TDD reaches the OTA through a direct submission channel.
If you are scoping Fawtara, the TDD is the part of the project where most engineering hours land. This post is the deep-dive companion to our Oman Fawtara readiness guide.
CustomizationID and ProfileID
CustomizationID = urn:peppol:taxdata:om-1
ProfileID = urn:peppol:bis:taxdata
These two values disambiguate the TDD from any other PINT or BIS document. They drive the validator selection, the routing, and the OTA-side ingestion.
Structural sketch
A TDD lives under a single root element in the pxs: namespace. The major blocks:
- Document identification —
pxs:ID,pxs:IssueDate,pxs:DocumentTypeCode,pxs:DocumentCurrencyCode,pxs:TaxCurrencyCode. - Source-document reference — link back to the originating PINT OM invoice (its
IDandIssueDate). - Parties — supplier (issuer of the invoice) and customer (buyer), each with endpoint ID, party name, party tax scheme.
- Tax breakdown —
pxs:TaxLineper tax category and rate, with taxable amount and tax amount. - Monetary totals — line extension amount, tax exclusive amount, tax inclusive amount, tax amount.
The TDD does not carry:
- Line-level descriptions or quantities.
- Allowances or charges at line level (allowed only at header where they impact tax totals).
- Payment instructions, terms, or means.
- Notes and attachments not relevant to tax.
The intent is a tight, tax-authority-relevant document — small, fast to validate, and fast to ingest at scale.
The mapping from PINT OM invoice
A working transform reuses these fields directly:
| PINT OM invoice field | TDD field |
|---|---|
cbc:ID |
pxs:DocumentReference/cbc:ID |
cbc:IssueDate |
pxs:IssueDate and pxs:DocumentReference/cbc:IssueDate |
cbc:DocumentCurrencyCode |
pxs:DocumentCurrencyCode |
cbc:TaxCurrencyCode |
pxs:TaxCurrencyCode |
cac:AccountingSupplierParty |
pxs:SupplierParty (subset) |
cac:AccountingCustomerParty |
pxs:CustomerParty (subset) |
cac:TaxTotal/cac:TaxSubtotal |
pxs:TaxLine (one per category/rate combination) |
cac:LegalMonetaryTotal |
pxs:LegalMonetaryTotal (subset) |
Where the invoice carries multiple tax subtotals at different rates, the TDD aggregates them into one pxs:TaxLine per (category, rate) pair. The transform must therefore group and sum, not blindly map.
Why a deterministic, pure transform
Treat the TDD generator as a pure function:
TDD = transform(PINT_OM_Invoice)
No database lookups inside the transform. No date-based calculations not already in the invoice. No external HTTP calls. Why:
- Exhaustive testing. Every published OpenPeppol PINT OM sample becomes a unit test. A failure means a gap in the transform, not a debate about interpretation.
- Idempotency. The same input always yields the same output. If you regenerate, the TDD is bit-identical, which is critical for retries.
- Auditability. A pure transform is reviewable in a single PR.
This is how the GoRoute tdd_generator service is built. It runs in-process behind the validator and emits the TDD in milliseconds.
Validation
The TDD goes through a layered validation just like the source invoice:
- XSD — pxs / cac / cbc namespaces.
- Schematron —
TDD-OM-peppol-om-tdd.xslt, run on Saxon-HE 12.4. - Code-list checks — currency code, country code, tax category code, unit code.
- Cross-document consistency — same
IDreferenced as the source invoice; same supplier and customer parties.
A error blocks the submission to OTA. A warning is recorded for audit. The same discipline applies as in invoice validation errors you can prevent.
Submission flow
PINT OM invoice ──► validate ──► transmit on Peppol ──► persist receipt
│
└─► TDD transform ──► validate ──► submit to OTA ──► persist OTA correlation ID
Two persistence points matter:
- The Peppol receipt (MLR) for the invoice exchange between supplier and buyer.
- The OTA acknowledgement for the TDD submission.
Both are evidence of compliance. Lose either and the audit trail is incomplete.
Common engineering pitfalls
- Hand-written TDD. Some implementers try to author the TDD alongside the invoice in the ERP. Don't. Generate it from the invoice.
- Floating-point sums. Use decimal arithmetic with explicit rounding rules; the Schematron checks totals to the cent.
- Skipping the Schematron
warning. Warnings are not blockers but they are flags for the OTA's downstream analytics. Investigate them. - Tying TDD submission to invoice send synchronously. Decouple them. If OTA is briefly unreachable, the invoice still leaves; the TDD is queued and submitted on retry.
What we ship at GoRoute
GoRoute (POP000991) operates the TDD generator and the OTA submission path in production, with PINT OM compiled at Docker build time and a regression suite of 66 PINT-OM tests running on every release. See the higher-level Oman Fawtara readiness guide for the programmatic context, the PINT OM CustomizationID reference for the document-type table, and the e-invoicing mandates 2026 tracker for the global picture.
Book a demo to see TDD generation live against your sample invoices.
Sources: OpenPeppol PINT framework and PINT OM artefacts; Oman Tax Authority Fawtara public documentation; Saxon-HE 12.4 Schematron processor.
Frequently asked questions
- What is the Oman Tax Data Document?
- The Tax Data Document (TDD) is a purpose-built XML document with CustomizationID urn:peppol:taxdata:om-1, carrying the tax-relevant view of an invoice or credit note. The Oman Tax Authority receives the TDD for continuous transaction control reporting; the underlying invoice itself flows on Peppol between supplier and buyer.
- Is the TDD the same as the invoice?
- No. The TDD is a derived projection focused on the tax-authority view — header identification, parties, taxable amounts and tax line breakdown — without the commercial detail (line descriptions, allowances at line level, payment instructions).
- How is the TDD generated?
- A deterministic transform reads a valid PINT OM invoice and emits the TDD. The transform is pure (no external state) so it is exhaustively unit-testable. GoRoute uses an internal tdd_generator service for this.
- What validates the TDD?
- A purpose-built Schematron, TDD-OM-peppol-om-tdd.xslt, published by OpenPeppol. The Schematron error level is the gate; warnings are logged.
- What happens at submission time?
- The TDD is submitted to the Oman Tax Authority's Fawtara endpoint and acknowledged with a correlation identifier. The acknowledgement, plus the original TDD, are persisted alongside the source invoice.
Building on Peppol?
GoRoute is a certified Peppol Access Point & SMP. Book a demo or read the docs to get started.