Inside the Oman Tax Data Document (TDD): Engineering Walkthrough
The Oman Tax Data Document is the XML report the Tax Authority receives as corner five: what it carries, the 66 rules it must pass, and how it is generated.
Last updated .
What is the Oman Tax Data Document?
The Tax Data Document (TDD) is the XML document that reports a single transaction to the Oman Tax Authority (OTA) under the Fawtara e-invoicing programme. It carries CustomizationID urn:peppol:taxdata:om-1 and ProfileID urn:peppol:taxreporting, it is generated from the underlying PINT OM invoice, and it travels over the Peppol network to the Authority — the fifth corner in Oman's 5-corner model.
It is not a replacement for the invoice, and it is not a stripped-down copy of one either. A TDD holds a short tax-relevant summary and the complete original invoice embedded inside it. That single design decision explains most of the engineering: the summary is what the Authority reads first, and the embedded invoice is what makes the report self-evidencing.
If you are scoping Fawtara, the TDD is where most engineering hours land. This is the deep-dive companion to our Oman Fawtara readiness guide.
CustomizationID and ProfileID
CustomizationID = urn:peppol:taxdata:om-1
ProfileID = urn:peppol:taxreporting
Rule ibr-tdd-01 fixes the first value and ibr-tdd-02 fixes the second. Both are fatal. Together they disambiguate the TDD from every PINT and BIS document, and they drive validator selection, routing and ingestion on the Authority's side.
The full identifier set for Oman — billing, self-billing and the TDD — is tabulated on the PINT OM CustomizationID reference.
What the TDD carries
The document root is pxs:TaxData in the namespace urn:peppol:schema:om-taxdata:1.0. Three groups sit under it.
The header
| Element | What it is | Rule |
|---|---|---|
cbc:CustomizationID |
Always urn:peppol:taxdata:om-1 |
ibr-tdd-01 |
cbc:ProfileID |
Always urn:peppol:taxreporting |
ibr-tdd-02 |
cbc:UUID |
The TDD's own identifier | ibr-tdd-58 |
cbc:IssueDate |
Date only — a timezone here is a failure | ibr-tdd-04 |
cbc:IssueTime |
Valid UBL issue time | ibr-tdd-05 |
pxs:DocumentTypeCode |
S, R or D |
ibr-tdd-06 |
pxs:DocumentScope |
D, IP or INP |
ibr-tdd-07 |
pxs:ReporterRole |
01 or 02 |
ibr-tdd-08 |
There is deliberately no cbc:ID at the root: ibr-tdd-03 fails a TDD that carries one. The identifier is cbc:UUID.
The three code lists are small and worth learning, because picking the wrong value is a silent business error rather than a syntax one:
pxs:DocumentTypeCode—Ssubmit,Rresubmit (revise a TDD already reported),Ddisregard (void one already reported). An olderS/R/W/Flist circulated before version 1.0.0 of the TDD process;WandFare no longer valid and the current Schematron rejects them.pxs:DocumentScope—Ddomestic,IPinternational exchanged via Peppol,INPinternational exchanged outside Peppol. "International" covers both imports and exports; it is not import-only.pxs:ReporterRole—01the seller is reporting,02the buyer is reporting.
The three parties
The root carries three party blocks, and each is an address and nothing else:
| Block | Content | Constraint |
|---|---|---|
pxs:ReportingParty |
cbc:EndpointID with a four-digit schemeID |
ibr-tdd-11 to ibr-tdd-13 |
pxs:ReceivingParty |
cbc:EndpointID with schemeID 0242 |
ibr-tdd-15 to ibr-tdd-17 |
pxs:ReportersRepresentative |
Exactly one cac:PartyIdentification/cbc:ID on scheme 0242 |
ibr-tdd-19 to ibr-tdd-21 |
Rules ibr-tdd-10, -14 and -18 enumerate what may not appear in these blocks, and the list is long: no PartyName, no PostalAddress, no PartyTaxScheme, no PartyLegalEntity, no Contact. Adding a helpful company name to the reporting party is a fatal error. Identifiers and registration names belong further down, on the reported document — and even there cac:PartyName is forbidden, so a trading name has nowhere to go. Use cac:PartyLegalEntity/cbc:RegistrationName.
Scheme 0242 is the Peppol Service Provider identifier scheme, which is why both the receiver and the representative use it: the Authority receives as a service provider, and the reporter is represented by one.
The reported transaction
Exactly one pxs:ReportedTransaction is allowed — ibr-tdd-09 counts them — and it holds two mandatory children plus an optional one:
pxs:ReportedDocument(ibr-tdd-22) — the tax-relevant summary.pxs:SourceDocument(ibr-tdd-23) — the original invoice, whole.pxs:CustomContent, optional, which must use the simplecbc:Valueelement (ibr-tdd-55).
The transaction block itself also records when the original document was received: cbc:IssueDate (ibr-tdd-59) and cbc:IssueTime (ibr-tdd-60).
The reported document, field by field
pxs:ReportedDocument is the summary the Authority reads. It restates a small set of invoice fields:
| PINT OM invoice field | TDD field | Rule |
|---|---|---|
cbc:CustomizationID |
cbc:CustomizationID |
ibr-tdd-24 |
cbc:ProfileID |
cbc:ProfileID |
ibr-tdd-25 |
cbc:ID (invoice number) |
cbc:ID |
ibr-tdd-26 |
| Document UUID | cbc:UUID, a version 5 UUID |
ibr-tdd-27 |
cbc:IssueDate |
cbc:IssueDate |
ibr-tdd-28 |
cbc:InvoiceTypeCode / cbc:CreditNoteTypeCode |
pxs:DocumentTypeCode (380, 381, 383, 389, 261) |
ibr-tdd-29 |
cbc:DocumentCurrencyCode |
cbc:DocumentCurrencyCode |
ibr-tdd-30 |
cac:AccountingSupplierParty |
cac:AccountingSupplierParty — tax scheme identifier, plus a legal-entity registration name where that block is used |
ibr-tdd-32, -42, -62 |
cac:AccountingCustomerParty |
cac:AccountingCustomerParty — VAT identifier, plus a legal-entity registration name where that block is used |
ibr-tdd-33, -50, -64 |
cac:TaxTotal/cbc:TaxAmount |
cac:TaxTotal/cbc:TaxAmount, one per currency |
ibr-tdd-34 to -36 |
cac:LegalMonetaryTotal/cbc:TaxExclusiveAmount |
pxs:MonetaryTotal/cbc:TaxExclusiveAmount |
ibr-tdd-37, -52, -53 |
Four details in that table catch people out.
The document type code moves element. In UBL the code sits on cbc:InvoiceTypeCode or cbc:CreditNoteTypeCode depending on the document root. In the TDD it is always pxs:DocumentTypeCode. Note that the same element name means two different things in two places: at the root of the TDD it is S/R/D, and inside the reported document it is the UNTDID invoice type code.
The reported UUID is not the invoice's own UUID. ibr-tdd-27 requires a version 5 UUID, and a version 5 UUID is computed from a namespace plus a name rather than drawn at random. Oman's Solution Architecture v1.0.1 §10.2.3 defines the name as a fixed join of invoice fields, so the value is reproducible: the Authority recomputes it and compares. Copy the invoice's random cbc:UUID into this slot and the document fails.
There is one tax total per currency, not per rate. ibr-tdd-35 requires exactly one cac:TaxTotal in the document currency, and ibr-tdd-36 exactly one more if an accounting currency is used — which ibr-tdd-31 requires to be a different currency from the document currency. There is no per-category or per-rate breakdown in the reported document, and no pxs:TaxLine element exists. If you are building a category-by-category structure here, stop: the Authority gets the detail from the embedded invoice.
The monetary total is pxs:MonetaryTotal, not LegalMonetaryTotal. Exactly one, carrying cbc:TaxExclusiveAmount in the document currency (ibr-tdd-52, ibr-tdd-53).
One conditional worth encoding properly: ibr-tdd-42 makes the seller's tax identifier mandatory except for an invoice for import of goods, an import-of-service reverse charge, or a profit-margin self invoice. The rule reads the transaction-type bit string on the source invoice to decide, so the exemption is derived, never asserted by the sender.
The source document — the whole invoice travels with it
pxs:SourceDocument/cec:ExtensionContent must contain a complete UBL 2.1 Invoice or CreditNote. ibr-tdd-57 states it directly, and ibr-tdd-23 makes the block itself mandatory.
This is the single most commonly misunderstood part of the TDD. A TDD is not a redacted tax extract that leaves the commercial detail behind. Line descriptions, quantities, allowances, payment terms — all of it is inside the report, because the embedded invoice is the evidence the summary is drawn from. The reported document exists so the Authority can index and match at scale without parsing the invoice first, not so the invoice can be withheld.
Two consequences follow for anyone sizing this work. TDD payloads are roughly invoice-sized plus a small header, so storage and transmission planning should assume a second copy of every invoice. And there is nothing to negotiate about which commercial fields "have to" go to the Authority: under this design they all do.
How the TDD is generated
Derive it from the validated PINT OM invoice. Never author it alongside the invoice in the ERP — two sources of the same truth diverge, and the divergence surfaces as a rejection weeks later.
The transform is deterministic given its inputs, but it is worth being precise about what those inputs are, because "pure function of the invoice" is not quite right. Reading the invoice gives you the identifiers, parties, currencies and amounts. Four things it cannot give you have to be supplied:
- Which endpoint is reporting — the seller's or buyer's Peppol participant identifier, with its scheme.
- Which endpoint receives — the Authority's participant identifier on scheme
0242. - The reporter's representative — the service provider's own identifier, also on scheme
0242. - When the original document was received, as a date and a time.
Everything else is derived. Because the reported document's UUID is a version 5 UUID computed from invoice fields, regenerating a TDD for the same invoice with the same inputs produces the same identifier, which is what makes retries safe.
Keep the transform free of database lookups and outbound calls. Two things follow. Every published PINT OM sample becomes a unit test, so a failure is a gap in the transform rather than a debate about interpretation. And the whole transform stays reviewable in a single pull request.
Validation: 66 rules, all fatal
The TDD goes through the same layered validation as the source invoice:
- XSD — the
pxs,cac,cbcandcecnamespaces. - Schematron —
peppol-om-tdd.sch, compiled topeppol-om-tdd.xsltand run on Saxon-HE 12.4. - Code-list checks — currency code, document type code, document scope, reporter role, participant identifier scheme.
- Cross-document consistency — the reported document's identifiers and parties against the embedded source invoice.
The TDD Schematron carries 66 rules and every one of them is flagged fatal. This is a real difference from the invoice packs, where a rule can fire at warning level and be logged for audit. In the TDD pack there is no warning level: a rule that fires stops the document. Any pipeline that treats TDD Schematron output as advisory is mis-built.
Rule identifiers are worth surfacing in your own error messages. ibr-tdd-17 tells you the receiving party's scheme is wrong; ibr-tdd-27 tells you the UUID is not version 5. Both are one-line fixes once you know which rule fired, and unrecognisable otherwise.
How the TDD reaches the Tax Authority
Over Peppol, through the same send path as any other document.
PINT OM invoice ──► validate ──► transmit on Peppol to the buyer ──► persist receipt
│
└─► TDD transform ──► validate ──► send on Peppol to the OTA ──► persist delivery
The Authority is addressed as an ordinary Peppol participant. ibr-tdd-17 requires the receiving party's endpoint scheme to be 0242 — the Peppol Service Provider identifier scheme — which is the structural statement that corner five is a participant on the network, not a portal you upload to. In GoRoute's implementation the TDD is submitted through the same document-send service as an invoice, carrying metadata that links the report back to the transaction it describes, so its delivery is reconciled against the original invoice.
Two persistence points matter, and both are evidence of compliance:
- The Peppol receipt for the invoice exchange between supplier and buyer.
- The delivery record for the TDD leg to the Authority.
Lose either and the audit trail is incomplete.
When this becomes mandatory in Oman
Tax Authority Decision No. 189/2026 makes electronic tax invoices mandatory from 1 April 2027 for taxable persons whose annual supplies exceed OMR 5,000,000, and from 1 October 2027 for those at or below that threshold. It has been in law since publication in Official Gazette No. 1660 on 9 August 2026, amending the VAT Executive Regulations at Article Three.
Ahead of those dates the Tax Authority has said a voluntary pilot of 100 companies starts from end-August 2026. That is an Authority statement about a pilot, not a legal phase in the decision.
An earlier indicative schedule circulated — February 2027 and August 2027 — from the Authority's FAQ. It was never law and the statutory dates are later, not earlier. Anyone still planning to the old dates has about two extra months, not two fewer. The full reading is in Oman sets its e-invoicing dates, and the global picture is in the e-invoicing mandates 2026 tracker.
Common engineering pitfalls
- Hand-authoring the TDD. Generate it from the validated invoice. A second hand-maintained data model is a second thing to get wrong.
- Omitting the source invoice.
ibr-tdd-23andibr-tdd-57both fail. If your TDD is a few kilobytes, you have built the summary and forgotten the evidence. - Reusing the invoice's random UUID in the reported document. It must be a version 5 UUID derived from the invoice fields, and the Authority recomputes it.
- Decorating the routing parties. A
PartyNameonpxs:ReportingPartyis fatal underibr-tdd-10. Those blocks are addresses. - Treating Schematron output as advisory. Every TDD rule is fatal; there is nothing to downgrade.
- Floating-point sums. Use decimal arithmetic with explicit rounding; the amounts are checked against the embedded invoice.
- Coupling TDD submission synchronously to the invoice send. Decouple them. If the Authority's endpoint is briefly unreachable the invoice should still leave, with the TDD queued and retried.
What GoRoute ships
GoRoute (POP000991) runs the TDD generator and the Peppol send path to the Authority in production. The TDD Schematron is compiled to XSLT at Docker build time and the four PINT OM invoice-family packs ship pre-compiled; all of them run in-process through Saxon-HE 12.4. The Oman regression suite in the API repository stands at 234 tests across 32 files, 16 of them on the TDD generator alone.
GoRoute is accredited by the Oman Tax Authority as an e-invoicing service provider, accredited 29 July 2026 through Union Digital Technologies SPC. For the architecture around this document, read Oman's 5-corner model explained; for the identifiers, the PINT OM CustomizationID reference; for programme context, the Oman Fawtara readiness guide.
Book a demo to see TDD generation run against your own sample invoices.
Sources: OpenPeppol PINT OM v1.0.1 artefacts as shipped in GoRoute's validator, including the peppol-om-tdd Schematron and its published examples; OpenPeppol PINT framework; Oman Tax Authority Fawtara documentation; Tax Authority Decision No. 189/2026, Official Gazette No. 1660, 9 August 2026; Saxon-HE 12.4.
Frequently asked questions
- What is the Oman Tax Data Document?
- The Tax Data Document (TDD) is an XML document with CustomizationID urn:peppol:taxdata:om-1 and ProfileID urn:peppol:taxreporting. It reports one transaction to the Oman Tax Authority under the Fawtara continuous transaction control regime. It carries a summary of the invoice plus the complete original invoice embedded inside it, and it travels over the Peppol network to the Authority as the fifth corner.
- Is the TDD the same as the invoice?
- No, but it contains one. The TDD wraps two things: a ReportedDocument block holding the tax-relevant summary — identifiers, both parties' tax IDs and names, total tax amount and total excluding tax — and a SourceDocument block that must contain the whole original UBL 2.1 Invoice or Credit Note. Rule ibr-tdd-57 fails the document if the source invoice is missing.
- What CustomizationID and ProfileID does the TDD use?
- CustomizationID urn:peppol:taxdata:om-1 and ProfileID urn:peppol:taxreporting, enforced by rules ibr-tdd-01 and ibr-tdd-02. Both are fatal, so a wrong value stops the document rather than warning about it.
- How is the TDD generated?
- It is derived from a valid PINT OM invoice by a transform that reads the invoice and adds the routing and timing values the invoice cannot know: which endpoint is reporting, which endpoint receives, the reporting service provider's own identifier, and the date and time the document was received. GoRoute runs this as an internal tdd_generator service.
- What validates the TDD?
- A dedicated Schematron, peppol-om-tdd.sch, compiled to XSLT and run on Saxon-HE 12.4. It carries 66 rules and every one of them is fatal — the TDD pack has no warning level, so any rule that fires stops the document.
- How does the TDD reach the Oman Tax Authority?
- Over the Peppol network, the same way any other document is sent. The Authority is addressed as an ordinary Peppol participant on scheme 0242, the Peppol Service Provider identifier scheme, which rule ibr-tdd-17 requires for the receiving party. There is no separate portal upload in this flow.
- When does the Oman e-invoicing mandate apply?
- Tax Authority Decision No. 189/2026 sets 1 April 2027 for taxable persons whose annual supplies exceed OMR 5,000,000, and 1 October 2027 for those at or below that threshold. The decision has been in law since its publication in Official Gazette No. 1660 on 9 August 2026.
Building on Peppol?
GoRoute is a certified Peppol Access Point & SMP. Book a demo or read the docs to get started.