Create EDIFACT Invoices from JSON with an EDI API
Turn invoice data from your ERP or platform into an EANCOM INVOIC message
- 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 give441.6.MOA+79andMOA+125, the sum of the lines:{d.lines[].qty:mul(.price):aggSum:round(2)}.MOA+124, the VAT: the taxable amount timesd.invoice.vatRate / 100. 20% of 1318.8 gives263.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.
Related Examples
Trusted by 800+ paid customers in 40+ countries














