Skip to main content

Search OfficeIMO

Enter a topic, API type, or PowerShell command.

A branded invoice with embedded CII

Generate a customer-facing invoice and its machine-readable CII representation from one typed model, while keeping branding and presentation settings separate from the business data.

Start with
Typed invoice parties, line items, tax, payment, branding, and approval details
Generate
Two-page PDF with embedded CII XML
Page 1 of a generated Evotec-branded PDF invoice
Page 1 · Generated by the example below

How it works

  1. Build the invoice model

    Populate typed seller, buyer, line, tax, payment, reference, and note records, then calculate the declared totals from those values.

  2. Apply the presentation

    Choose one or more built-in label cultures, select the modern theme, add the governed logo, and add visible prepared-by and approved-by details to the captured layout.

  3. Write both representations

    Create one snapshot, write its exact CII XML, and render the PDF with that XML embedded as the alternative invoice representation.

The rest of the document

A branded invoice with embedded CII: Page 2
Page 2

The C# source

This is the complete example file used to generate the download. The walkthrough runner creates the output directory and produces the additional previews.

using OfficeIMO.Invoicing;
using OfficeIMO.Invoicing.Pdf;
using OfficeIMO.Pdf;

namespace OfficeIMO.Examples.Showcase.Workflows;

/// <summary>Creates a polished PDF invoice and embeds its CII representation from the typed invoice model.</summary>
internal static class BrandedInvoice {
    internal static void Create(string folder) {
        Invoice invoice = CreateInvoice();
        var contract = new InvoiceXmlOptions(
            InvoiceSpecificationRelease.FacturX_1_09_2_Zugferd_2_5_2,
            InvoiceSyntax.Cii,
            InvoiceProfile.En16931);
        var layout = InvoicePdfLayoutOptions.ForCultures("en-GB");
        layout.Theme = InvoicePdfTheme.Modern(PdfColor.FromRgb(63, 92, 255));
        layout.LogoBytes = File.ReadAllBytes(Path.Combine(
            AppContext.BaseDirectory,
            "Assets",
            "Brand",
            "Evotec",
            "evotec-logo-horizontal-gradient-2400.png"));
        layout.LogoAlternativeText = "Evotec";
        layout.Approvals.Add(new InvoicePdfApproval("Prepared by", "Marta Nowak", "Finance", invoice.IssueDate));
        layout.Approvals.Add(new InvoicePdfApproval("Approved by", "Daniel Reed", "Delivery lead", invoice.IssueDate));

        PdfInvoiceDocument snapshot = PdfInvoiceDocument.Create(invoice, contract, layout);
        string fonts = Path.Combine(AppContext.BaseDirectory, "Assets", "Fonts");
        var pdfOptions = new PdfOptions {
            DefaultFontSize = 9.5D,
            TaggedStructureMode = PdfTaggedStructureMode.CatalogMarkers
        }.UseFontFamily(new PdfEmbeddedFontFamily(
            "Carlito",
            File.ReadAllBytes(Path.Combine(fonts, "Carlito-Regular.ttf")),
            File.ReadAllBytes(Path.Combine(fonts, "Carlito-Bold.ttf"))));

        File.WriteAllBytes(Path.Combine(folder, "example.xml"), snapshot.ToXmlBytes());
        File.WriteAllBytes(Path.Combine(folder, "example.pdf"), snapshot.ToPdfBytes(pdfOptions));
    }

    private static Invoice CreateInvoice() {
        var invoice = new Invoice {
            Number = "EVO-DEMO-2026-0917",
            IssueDate = new DateTime(2026, 9, 17),
            DueDate = new DateTime(2026, 10, 1),
            Currency = "EUR",
            BuyerReference = "NW-DOC-2048",
            PurchaseOrderReference = "PO-2048-09",
            PaymentTerms = "Payment due within 14 days. Use the invoice number as the transfer reference.",
            Seller = new InvoiceParty {
                Name = "Evotec Services sp. z o.o.",
                ElectronicAddress = new InvoiceIdentifier("[email protected]", "EM"),
                Address = new InvoiceAddress {
                    Line1 = "Demonstration address",
                    City = "Warsaw",
                    PostCode = "00-001",
                    CountryCode = "PL"
                },
                Contact = new InvoiceContact { Name = "Finance team", Email = "[email protected]" }
            },
            Buyer = new InvoiceParty {
                Name = "Northwind Field Operations",
                ElectronicAddress = new InvoiceIdentifier("[email protected]", "EM"),
                Address = new InvoiceAddress {
                    Line1 = "12 Harbour Street",
                    City = "Copenhagen",
                    PostCode = "1050",
                    CountryCode = "DK"
                },
                Contact = new InvoiceContact { Name = "Accounts payable", Email = "[email protected]" }
            }
        };
        invoice.Seller.TaxRegistrations.Add(new InvoiceTaxRegistration("PL0000000000", InvoiceTaxRegistration.VatScheme));
        invoice.Payments.Add(new InvoicePayment {
            MeansCode = "58",
            MeansText = "SEPA credit transfer",
            Reference = invoice.Number,
            Account = new InvoiceBankAccount { Identifier = "PL10105000997603123456789123", Name = "Evotec Services" }
        });
        AddLine(invoice, "1", "Document workflow discovery", "Architecture workshop and conversion inventory", 6m, 145m);
        AddLine(invoice, "2", "Invoice automation implementation", "Typed model, PDF layout and embedded CII delivery", 18m, 145m);
        AddLine(invoice, "3", "Validation evidence", "Artifact inspection, semantic readback and release notes", 7.5m, 145m);
        AddLine(invoice, "4", "Team enablement", "Developer handover and API walkthrough", 4m, 145m);
        invoice.Notes.Add(new InvoiceNote("Demonstration document. Seller identifiers, address and bank account are intentionally non-operational sample data."));
        InvoiceCalculator.UpdateDeclaredAmounts(invoice);
        return invoice;
    }

    private static void AddLine(Invoice invoice, string id, string name, string description, decimal quantity, decimal unitPrice) =>
        invoice.Lines.Add(new InvoiceLine {
            Id = id,
            Name = name,
            Description = description,
            Quantity = quantity,
            UnitCode = "HUR",
            UnitPrice = unitPrice,
            Tax = new InvoiceTaxCategory { Code = "S", Rate = 23m }
        });
}
Open the C# source file

Run it from the source checkout

Clone the OfficeIMO repository and run this command from its root with the .NET 10 SDK. The first run restores the example project's dependencies.

dotnet run --project OfficeIMO.Examples -f net10.0 -- --showcase-workflows --showcase-example pdf-branded-invoice

The files are written to OfficeIMO.Examples/bin/Debug/net10.0/Documents/Workflows/pdf-branded-invoice/. To use the example in your application, start with the PDF guide and its package setup.

Downloads and scope

What the preview shows

The example generates the PDF and XML from one captured invoice. The runner reopens the PDF, checks its visible text, and renders both page previews with Poppler.

What to keep in mind

Seller identifiers, bank details, and the buyer are non-operational sample data. Approval blocks are visible content, not cryptographic signatures. The showcase does not claim Factur-X or PDF/A conformance without external validation of the exact artifact.

PDF API reference · Artifact hashes and provenance

Continue with another example

Example source

Download source