Skip to content
dg.dev
← all projects

2026 · updated 26 Sept 2026

myData-Client-Lib

Catch AADE's rejections on your own machine, before the request ever leaves it.

The problem

myDATA's SendInvoices endpoint enforces a long list of business rules (gross, net and tax arithmetic, line-to-summary totals, forbidden fields, VAT exemption codes) but only checks them after the request reaches AADE. A batch of 100 invoices can come back as 200 OK carrying 97 acceptances and 3 rejections, so a naive integration either treats every 200 as success or hand-parses the error list.

On top of that, the wire format is XML generated from XSDs that change with each spec revision, and none of it is exposed as a clean, typed surface.

How it works

  1. Your application
  2. InvoiceValidator
  3. Mapping layer
  4. Generated XSD models
  5. MyDataClient
  6. AADE myDATA API

Three layers, one direction. Generated/ comes from the official XSDs and never leaves the library as a public type; Mapping/ translates it into the hand-written models; Http/ only ever talks to those models. A schema regeneration changes Generated/, Mapping/ absorbs it, and the public API doesn't move.

The hard parts

  1. 01

    Partial success inside a 200

    Business errors come back as data, per invoice, matched to the caller's input. Only transport failures (401, network errors, timeouts) throw. Treating a mixed 200 as an exception would make every caller unpack the same body twice.

  2. 02

    Reproducing AADE's rules

    The validator reproduces error codes 203, 207–210, 217, 219, 220, 261, 265 and 306, so a bad batch fails in milliseconds on your machine instead of round-tripping to the sandbox to find out.

  3. 03

    A boundary XmlSerializer won't enforce

    XmlSerializer refuses to serialise internal types, even with InternalsVisibleTo, so the generated types have to be public. The boundary is enforced another way: every mapping class is internal, and no HTTP method accepts or returns a generated type.

  4. 04

    Greek encodings and two kinds of paging

    UID computation needs ISO-8859-7, which .NET doesn't register by default, and document retrieval pages through two independent mechanisms: a mark watermark and a separate continuation token.

Decisions and trade-offs

UID computation stays opt-in

The documented SHA-1 algorithm is implemented but never called automatically, since its exact field format hasn't been checked against a real AADE-computed value. AADE assigns the UID itself when it's left out.

Four tiers of tests

Unit tests with no I/O, golden-file snapshots of the mapped XML, contract tests replaying captured sandbox responses through WireMock.Net, and live sandbox calls that skip rather than fail when credentials are missing.

Credentials never live in files

Sandbox keys come from environment variables or user-secrets, never from appsettings.json or a tracked .http file.

What it doesn't do yet

  • Schema coupling is the known cost: each AADE schema revision means regenerating and re-verifying the models.
  • UID computation stays opt-in until it's checked against a real AADE value.