Skip to main content
SXN Labs
Open Source

einvoicing: EU e-invoicing for Ruby

Open source Ruby gem to generate Factur-X (PDF/A-3), CII D16B and UBL 2.1 invoices. Targets the French September 2026 B2B e-invoicing mandate and EN 16931.

EN 16931 Factur-X PDF/A-3 CII D16B UBL 2.1 Ruby ≥ 3.2
What is it?

What is einvoicing?

🏛️ The 2026 French mandate

From September 2026, all French B2B invoices must be transmitted electronically through a certified platform (PPF or PDP). Paper and non-structured PDFs will no longer be valid.

💎 A Ruby gem

einvoicing lets any Ruby or Rails application generate fully compliant invoices, without relying on third-party SaaS tools or manual processes.

📄 Factur-X PDF/A-3

Factur-X embeds a structured XML (CII D16B) inside a standard PDF. A human reads the PDF, a machine reads the XML. Both in one file. Validated by Mustang (PDF:valid XML:valid).

✅ Validated & tested

307 specs, 0 failures. PDF/A-3 conformance confirmed by Mustang CLI. Official XSD schemas bundled. GitHub CI runs Mustang on every push. Our in-house batch of 15 hostile invoices (multi-rate, reverse charge, 500 lines, DOM rates, foreign currency) clears the XSD, container and EN 16931 arithmetic checks.

What's done

Current features

🏗️

Invoice data model

Invoice, Party, LineItem and Tax, with BigDecimal amounts, credit notes and payment means (IBAN, BIC)

📋

CII D16B XML generator

EN 16931-compliant Cross Industry Invoice XML, Factur-X EN16931 profile

📋

UBL 2.1 XML generator

Peppol BIS Billing 3.0 compliant, BuyerReference, PaymentMeans, TaxCurrencyCode

📎

Factur-X PDF/A-3 embedding

Embeds CII XML into any PDF. Bundled sRGB ICC profile for PDF/A-3 OutputIntent conformance

🔍

French B2B validators

SIREN/SIRET Luhn checksum, VAT numbers for all 27 member states, IBAN ISO 13616, BIC format, French mainland, DOM and Corsican rates (2.1%, 8.5%, 1.75%, 1.05%, 13%, 0.9%)

🧾

EN 16931 VAT categories

S, Z, E, AE, K, G, O with exemption reason (BT-120) and VATEX code (BT-121): reverse charge, intra-Community, export, French art. 293 B franchise

Document-level allowances and charges

BG-20 / BG-21 with reason, reason code, base amount and percentage. Each category's taxable base and VAT adjust accordingly (BR-CO-10 to BR-CO-13)

🏦

Prepaid amount and retention

TotalPrepaidAmount (BT-113) reduces the amount due without touching the taxable base or the VAT (BR-CO-16)

↩️

Credit notes (avoir)

TypeCode 381, machine-readable BG-3 reference to the original invoice (BT-25/BT-26), required original_invoice_number validation

💱

VAT accounting currency

TaxCurrencyCode (BT-6) and the VAT total restated in the accounting currency (BT-111) in both CII and UBL (BR-53)

🏛️

Chorus Pro profile

:chorus_pro profile for CII generation, with SIRET schemeID instead of the ISO 6523 code for party identification

💳

Payment means

IBAN, BIC, payment type code (SEPA credit transfer, etc.) in both CII and UBL

🌍

i18n error messages

Structured symbol error codes { field:, error:, message: } with English and French translations

🛤️

Rails Invoiceable concern

Drop-in ActiveRecord concern, configurable validator, to_einvoice mapping

🔌

Chorus Pro / PPF client

OAuth2 (client_credentials), deposit_flux for Factur-X PDF upload, invoice status polling

🤖

GitHub CI with Mustang validation

Every push runs rspec + generates a sample invoice + validates it with Mustang CLI

🔍

SIRET lookup via French government API

Einvoicing::FR::SiretLookup.find(siren) and enrich!(party), no auth, stdlib only

Peppol BIS 3.0 Schematron validation

Einvoicing::Validators::Peppol.validate_ubl(xml): Saxon-HE + official Peppol XSLT, 0 errors on valid invoices

🧩

Top-level convenience API

Einvoicing.xml, .validate, .embed, .process: one-liner interface for the full pipeline

Quick start

Quick start

# Gemfile

gem "einvoicing"

# Build an invoice

invoice = Einvoicing::Invoice.new(

invoice_number: "FAC-2026-001",

issue_date: Date.today,

currency: "EUR",

seller: Einvoicing::Party.new(...),

buyer: Einvoicing::Party.new(...),

lines: [Einvoicing::LineItem.new(...)]

)


# Validate, generate XML, embed into PDF

errors = Einvoicing::Validators::FR.validate(invoice)

xml = Einvoicing::Formats::CII.generate(invoice)

pdf_out = Einvoicing::Formats::FacturX.embed(pdf_in, xml)

Used in production, not just tested

It generates compliant Factur-X PDF/A-3 invoices at our clients, on every transaction.

Want to integrate this in your app?

Need help integrating Factur-X generation into your Ruby on Rails application? Get in touch.

Contact us

Need to ship Factur-X in your Rails system?

We've already done the work for 5 clients. Let's discuss your case in 30 minutes.

Book a meeting

Check a Factur-X PDF for free, in your browser