Eunormia.Sdk
1.0.1
dotnet add package Eunormia.Sdk --version 1.0.1
NuGet\Install-Package Eunormia.Sdk -Version 1.0.1
<PackageReference Include="Eunormia.Sdk" Version="1.0.1" />
<PackageVersion Include="Eunormia.Sdk" Version="1.0.1" />
<PackageReference Include="Eunormia.Sdk" />
paket add Eunormia.Sdk --version 1.0.1
#r "nuget: Eunormia.Sdk, 1.0.1"
#:package Eunormia.Sdk@1.0.1
#addin nuget:?package=Eunormia.Sdk&version=1.0.1
#tool nuget:?package=Eunormia.Sdk&version=1.0.1
Eunormia.Sdk
Offline conversion to ZUGFeRD / Factur-X (PDF/A-3, EN 16931) for .NET — with the full double gate: veraPDF (PDF/A-3B) and EN-16931 Schematron. Only output that passes both gates is ever returned.
The package bundles the validated Java engine together with a trimmed JRE —
no infrastructure at the consumer (no installed Java, no Docker, no server).
dotnet add package, done.
Why
No existing .NET package does this: the common libraries (ZUGFeRD-csharp, FacturX-csharp/Securibox, Dangl.XRechnung …) create/read XML and embed it into an already-conforming PDF/A. Eunormia takes an arbitrary input PDF and enforces conformance (font embedding → base-14 substitution → rasterization as escalation) and returns only after passing the veraPDF and EN-16931 gate. veraPDF has no .NET port — real PDF/A-3B validation in .NET exists only by wrapping the Java engine; that is exactly what this package encapsulates.
Quick start
using Eunormia.Sdk;
var converter = new EunormiaConverter(new EunormiaOptions
{
LicenseKey = "…", // from the eunormia dashboard; without it -> watermark
Profile = ZugferdProfile.EN16931,
Language = "en"
});
EunormiaResult r = await converter.ConvertAsync(invoiceJson, pdfBytes);
File.WriteAllBytes(r.FileName, r.Pdf);
Console.WriteLine($"veraPDF={r.VeraPdfPassed} EN16931={r.En16931Passed} " +
$"watermarked={r.Watermarked} license={r.LicenseStatus}");
- Without a valid license the result carries a watermark (conversion + gates still run in full).
- Business/technical errors surface as
EunormiaException(status, stage, localizedDetails). - Without
pdfBytesa default template is rendered. For CII-XML passthrough:ConvertXmlAsync(ciiXml, pdfBytes).
Typed model (optional)
Instead of a JSON string you can pass the strongly-typed Invoice model — same
schema, with IntelliSense and compile-time safety:
var invoice = new Invoice
{
Number = "RE-2026-0042",
IssueDate = "2026-07-21",
Seller = new Party { Name = "Muster GmbH", Street = "Musterstraße 1",
Zip = "4020", City = "Linz", Country = "AT", VatId = "ATU12345678" },
Buyer = new Party { Name = "Beispiel GmbH", Street = "Beispielweg 2",
Zip = "80331", City = "München", Country = "DE" },
Items = new() { new LineItem { Name = "Consulting", Quantity = 16m,
Unit = "HUR", UnitPrice = 120m, VatPercent = 20m } }
};
EunormiaResult r = await converter.ConvertAsync(invoice, pdfBytes);
The JSON-string overload stays available as an escape hatch (e.g. to bring your
own model or set fields outside the schema). On the receiving side,
ReadResult.GetInvoice() returns the same typed model.
Receiving: validate & read
// Check an incoming e-invoice against the double gate (veraPDF + EN 16931):
ValidationResult v = await new EunormiaValidator().ValidateAsync(incomingPdf);
if (!v.Valid) foreach (var f in v.En16931.Failures) Console.WriteLine(f);
// Read the header data:
ReadResult r = await new EunormiaReader().ReadAsync(incomingPdf);
Console.WriteLine($"{r.Header?.Number} {r.Header?.Currency} {r.Standard}");
string embeddedCiiXml = r.Xml;
This covers both directions: creating invoices (guaranteed conformant) and receiving them (validate + deserialize) — all offline.
License & watermark
The SDK is fully functional without a license — generated invoices then carry only a sample watermark. A license key removes it. Verification runs completely offline (no phone-home, no telemetry).
How to get a key:
- Create an account at eunormia.com.
- Dashboard → "Offline license" → Generate license → copy the key.
- Set it in the SDK — either as
EunormiaOptions.LicenseKeyor via the environment variableEUNORMIA_LICENSE.
For pilot/trial access and commercial terms: eunormia.com.
Use is subject to the bundled license (LICENSE.txt).
Target platforms
- Frameworks:
net8.0andnetstandard2.0(the latter covers .NET Framework 4.6.1+ incl. 4.8). - RIDs: currently
win-x64only. On other platforms (Linux/macOS) the SDK throws a clearEunormiaException— further RIDs (linux-x64,osx-arm64) follow additively, built per platform. - Package size: ~116 MB (win-x64) — dominated by the engine core (Mustang, PDFBox, veraPDF, FOP/Batik, Saxon, ICU4J) + trimmed JRE, not by the SDK code.
Architecture (in brief)
EunormiaConverter starts the bundled JRE (runtimes/<rid>/native/jre) as a
child process and invokes eunormia-core.jar (entry point
at.eunormia.cli.OfflineCli); communication is JSON over stdin/stdout. The
runtime is unpacked from a packed runtime.zip into runtimes/<rid>/native/
during the consumer's build (see build/Eunormia.Sdk.targets).
Building / packing yourself
Prerequisites: the portable Java toolchain under service/tools/ (see
service/README), a .NET SDK (≥ 8), and 7-Zip (included in the toolchain).
# Build the runtime (slim core.jar + trimmed JRE) and pack the NuGet:
cd dotnet
./pack-nuget.sh win-x64 # -> dotnet/nupkg-out/Eunormia.Sdk.<ver>.nupkg
# Sample against the local runtime:
dotnet run --project sample -- \
../service/dist/win-x64 ../service/harness/harness-invoice.json \
../service/testdata/embedded-ttf.pdf
Feature set
Create (ZUGFeRD/Factur-X, double gate veraPDF + EN 16931) · Receive
(validate + deserialize) · optional official add-on checks KoSIT
(XRechnung/DE) and FR-CTC (France) · daemon mode (UseDaemon) against
cold-start latency · signed conformance certificate (EmitCertificate) ·
Ed25519 offline license (watermark gate). Both TFMs (net8.0,
netstandard2.0).
Platforms: currently win-x64 only; further RIDs (Linux/macOS) to follow.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.Text.Json (>= 8.0.5)
-
net8.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.1 | 125 | 7/21/2026 |