Create EDIFACT Invoices from JSON with an EDI API

Turn invoice data from your ERP or platform into an EANCOM INVOIC message

Download Template

Download data sample

  • Template type document txt simple
  • Carbone min. v5.0.0+
  • Features loop aggregator alias math
  • Target retail edi invoice

Generate EDIFACT invoices from your software

Retailers and manufacturers ask their suppliers to invoice by EDI (electronic data interchange), with UN/EDIFACT INVOIC messages. In retail, the version is often EANCOM, the GS1 version of EDIFACT, which identifies companies and products by their barcode numbers. Your ERP or platform sends the invoice to the Carbone API as JSON and gets back the INVOIC message, ready for your EDI provider or AS2 connection. In this example, Fabrikam Cookware invoices four products to the retailer Contoso Hypermarchés in EANCOM INVOIC D96A.

INVOIC message structure

Each line is a segment: a three-letter tag, then data elements (the values) separated by +, then '.

Segments Role
UNA The separators of the file
UNB and UNZ Envelope: sender and receiver GLNs (company barcode numbers), date, reference
UNH and UNT Start and end of the invoice, with its segment count
BGM, DTM, RFF Invoice number, invoice date, order number
NAD Buyer BY and supplier SU: GLN, name, address
CUX Currency
LIN, QTY, MOA, PRI One group per product: GTIN (product barcode number), quantity, amount, price
UNS, MOA, TAX Totals: lines, taxable amount, VAT, amount due

EDIFACT invoice example

Template

UNA:+.? '{o.useHighPrecisionArithmetic=true}{#edi($text) = $text:unaccent:replace('?', '??'):replace('+', '?+'):replace(':', '?:'):replace('''', '?''')}
UNB+UNOC:3+{d.supplier.gln}:14+{d.buyer.gln}:14+{d.interchange.date:formatD('YYMMDD:HHmm')}+{d.interchange.ref}'
UNH+1+INVOIC:D:96A:UN:EAN008'
BGM+380+{d.invoice.number}+9'
DTM+137:{d.invoice.date:formatD('YYYYMMDD')}:102'
RFF+ON:{d.invoice.orderNumber}'
NAD+BY+{d.buyer.gln}::9++{$edi(d.buyer.name)}+{$edi(d.buyer.street)}+{$edi(d.buyer.city)}++{d.buyer.postcode}+{d.buyer.country}'
NAD+SU+{d.supplier.gln}::9++{$edi(d.supplier.name)}+{$edi(d.supplier.street)}+{$edi(d.supplier.city)}++{d.supplier.postcode}+{d.supplier.country}'
CUX+2:{d.invoice.currency}:4'
{d.lines[i]}LIN+{d.lines[i].gtin:cumCount}++{d.lines[i].gtin}:EN'
QTY+47:{d.lines[i].qty}'
MOA+203:{d.lines[i].qty:mul(.price):round(2)}'
PRI+AAA:{d.lines[i].price}'
{d.lines[i+1]}UNS+S'
MOA+77:{d.lines[].qty:mul(.price):aggSum:round(2):mul(1 + d.invoice.vatRate / 100):round(2)}'
MOA+79:{d.lines[].qty:mul(.price):aggSum:round(2)}'
MOA+125:{d.lines[].qty:mul(.price):aggSum:round(2)}'
TAX+7+VAT+++:::{d.invoice.vatRate}+S'
MOA+124:{d.lines[].qty:mul(.price):aggSum:round(2):mul(d.invoice.vatRate / 100):round(2)}'
UNT+{d.lines[].gtin:aggCount:mul(4):add(14)}+1'
UNZ+1+{d.interchange.ref}'

JSON data

{
  "interchange": { "ref": "100482", "date": "2026-11-12T09:45:00+01:00" },
  "invoice": { "number": "FA-2026-0412", "date": "2026-11-12", "orderNumber": "PO-77810", "currency": "EUR", "vatRate": 20 },
  "supplier": { "gln": "3015874000008", "name": "Fabrikam Cookware SAS", "street": "14 rue de la Forge", "city": "Lyon", "postcode": "69007", "country": "FR" },
  "buyer": { "gln": "3029461000005", "name": "Contoso Hypermarchés SA", "street": "2 avenue du Port", "city": "Lille", "postcode": "59000", "country": "FR" },
  "lines": [
    { "gtin": "3015874001012", "qty": 24, "price": 18.4 },
    { "gtin": "3015874001180", "qty": 12, "price": 23.95 },
    { "gtin": "3015874001258", "qty": 36, "price": 11.25 },
    { "gtin": "3015874001326", "qty": 48, "price": 3.85 }
  ]
}

Generated INVOIC message

UNA:+.? '
UNB+UNOC:3+3015874000008:14+3029461000005:14+261112:0945+100482'
UNH+1+INVOIC:D:96A:UN:EAN008'
BGM+380+FA-2026-0412+9'
DTM+137:20261112:102'
RFF+ON:PO-77810'
NAD+BY+3029461000005::9++Contoso Hypermarches SA+2 avenue du Port+Lille++59000+FR'
NAD+SU+3015874000008::9++Fabrikam Cookware SAS+14 rue de la Forge+Lyon++69007+FR'
CUX+2:EUR:4'
LIN+1++3015874001012:EN'
QTY+47:24'
MOA+203:441.6'
PRI+AAA:18.4'
LIN+2++3015874001180:EN'
QTY+47:12'
MOA+203:287.4'
PRI+AAA:23.95'
LIN+3++3015874001258:EN'
QTY+47:36'
MOA+203:405'
PRI+AAA:11.25'
LIN+4++3015874001326:EN'
QTY+47:48'
MOA+203:184.8'
PRI+AAA:3.85'
UNS+S'
MOA+77:1582.56'
MOA+79:1318.8'
MOA+125:1318.8'
TAX+7+VAT+++:::20+S'
MOA+124:263.76'
UNT+30+1'
UNZ+1+100482'

How to create an EDIFACT invoice

1. Write the segments

Write each segment on its own line, with the fixed codes as they are and a tag where a value changes: BGM+380+{d.invoice.number}+9' prints BGM+380+FA-2026-0412+9'. If your trading partner wants a single line, write the template on one line.

2. Release the special characters

+, :, ' and ? are reserved. In names and addresses, the release character ? goes before them: Fabrikam's becomes Fabrikam?'s. The alias on the first line does it, and {$edi(d.buyer.name)} applies it:

{#edi($text) = $text:unaccent:replace('?', '??'):replace('+', '?+'):replace(':', '?:'):replace('''', '?''')}

? is replaced first, so the next replacements are not doubled. In a formatter argument, '''' is one single quote. :unaccent keeps the text in ASCII for the UNOC character set. Learn more about parametrized aliases.

3. Repeat the lines and compute the totals

{d.lines[i]} repeats the LIN, QTY, MOA and PRI segments for each product, as a loop, and :cumCount numbers them. Carbone computes every amount:

  • MOA+203, the line amount: {d.lines[i].qty:mul(.price):round(2)}. 24 items at 18.40 give 441.6.
  • MOA+79 and MOA+125, the sum of the lines: {d.lines[].qty:mul(.price):aggSum:round(2)}.
  • MOA+124, the VAT: the taxable amount times d.invoice.vatRate / 100. 20% of 1318.8 gives 263.76.
  • MOA+77, the amount due: the taxable amount plus the VAT.

{o.useHighPrecisionArithmetic=true} keeps the totals exact to the cent. See aggregators and formulas.

4. Count the segments

UNT gives the number of segments from UNH to UNT: 14 fixed ones, plus 4 per product. {d.lines[].gtin:aggCount:mul(4):add(14)} prints 30 for four products and stays right for any number of lines. When you add a segment to the template, change :add(14), or :mul(4) for a segment inside the loop.

Trusted by 800+ paid customers in 40+ countries

Finance
Healthcare
Insurance
Legal
Public
Retail
Energy
Software
Telecom
Dior
Thales
Younited
Danfoss
CMA CGM
Illumina
KparK
Scalingo
French Ministry of the Armed Forces
BMW
Telus
Bestseller
Flagship Biosciences
Insly
Ninox
Sodexo