Design
XML templates
Write an XML file with Carbone tags, and generate e-invoices, payment files and product feeds from JSON data.
COMMUNITY FEATURE
Available for:
Carbone Cloud
Carbone On-premise
Embedded Carbone JS
v2.0+
Any XML file can be a template. Write Carbone tags in element text and attribute values, send your JSON data to the API, and get back an XML file with the structure of the template, ready for a bank, a tax platform or a marketplace.
Basic
Write a tag where a value goes, in the text of an element or in an attribute value. In {d.recipient.name}, d is the root of the data and recipient.name is the path to the value. Carbone replaces only the tags: the XML declaration, the namespaces and their prefixes, the comments and the indentation stay as written.
{
"reference": "SHP-2026-10482",
"shipDate": "2026-11-12",
"service": "EXPRESS",
"shipper": {
"name": "Acme Corporation",
"city": "Chicago",
"country": "US"
},
"recipient": {
"name": "Vandelay & Sons Industries",
"street": "18 Mill Lane",
"postalCode": "02108",
"city": "Boston",
"country": "US",
"email": "receiving@vandelay.example"
},
"package": {
"weight": 4.2,
"contents": "Cordless drills with batteries <100 Wh"
},
"instructions": "Use the loading dock & call 10 min before"
}<?xml version="1.0" encoding="UTF-8"?>
<ShipmentRequest xmlns="urn:acme:shipping:2.0" version="2.0">
<Reference>{d.reference}</Reference>
<ShipDate>{d.shipDate}</ShipDate>
<Service code="{d.service}"/>
<Shipper>
<Name>{d.shipper.name}</Name>
<City>{d.shipper.city}</City>
<Country>{d.shipper.country}</Country>
</Shipper>
<Recipient>
<Name>{d.recipient.name}</Name>
<Street>{d.recipient.street}</Street>
<City postalCode="{d.recipient.postalCode}">{d.recipient.city}</City>
<Country>{d.recipient.country}</Country>
<Email>{d.recipient.email}</Email>
</Recipient>
<Package weight="{d.package.weight}" unit="kg">
<Contents>{d.package.contents}</Contents>
</Package>
<Instructions>{d.instructions}</Instructions>
</ShipmentRequest><?xml version="1.0" encoding="UTF-8"?>
<ShipmentRequest xmlns="urn:acme:shipping:2.0" version="2.0">
<Reference>SHP-2026-10482</Reference>
<ShipDate>2026-11-12</ShipDate>
<Service code="EXPRESS"/>
<Shipper>
<Name>Acme Corporation</Name>
<City>Chicago</City>
<Country>US</Country>
</Shipper>
<Recipient>
<Name>Vandelay & Sons Industries</Name>
<Street>18 Mill Lane</Street>
<City postalCode="02108">Boston</City>
<Country>US</Country>
<Email>receiving@vandelay.example</Email>
</Recipient>
<Package weight="4.2" unit="kg">
<Contents>Cordless drills with batteries <100 Wh</Contents>
</Package>
<Instructions>Use the loading dock & call 10 min before</Instructions>
</ShipmentRequest>- Carbone escapes
&,<and>in the values, like the recipient name and the contents. For free text in an attribute, see attributes. - A missing or empty value prints an empty element, like
<Note></Note>. To remove the element instead, use a condition. - Tags in XML comments are replaced too.
Learn more about tags.
Loops
A loop repeats an element for each item of an array. The template needs two elements:
- The element to repeat, with
[i]in its tags:{d.pages[i].url}. - The next element, with
[i+1]in one tag:{d.pages[i+1].url}. It marks the end of the loop and is removed from the report.
Carbone repeats the element with its children and attributes. Add a condition to the [i+1] tag to filter the items: noindex=false leaves the cart page out of this sitemap.
{
"pages": [
{ "url": "https://www.acme.example/", "updatedAt": "2026-11-10T08:15:00Z", "changefreq": "daily", "priority": 1, "noindex": false },
{ "url": "https://www.acme.example/products/cordless-drill", "updatedAt": "2026-11-04T14:30:00Z", "changefreq": "weekly", "priority": 0.8, "noindex": false },
{ "url": "https://www.acme.example/products?category=tools&sort=new", "updatedAt": "2026-11-09T06:00:00Z", "changefreq": "daily", "priority": 0.6, "noindex": false },
{ "url": "https://www.acme.example/cart", "updatedAt": "2026-11-10T09:00:00Z", "changefreq": "always", "priority": 0.1, "noindex": true },
{ "url": "https://www.acme.example/support/warranty", "updatedAt": "2026-09-22T10:00:00Z", "changefreq": "monthly", "priority": 0.5, "noindex": false }
]
}<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>{d.pages[i].url}</loc>
<lastmod>{d.pages[i].updatedAt:formatD('YYYY-MM-DD')}</lastmod>
<changefreq>{d.pages[i].changefreq}</changefreq>
<priority>{d.pages[i].priority}</priority>
</url>
<url>
<loc>{d.pages[i+1, noindex=false].url}</loc>
</url>
</urlset><?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://www.acme.example/</loc>
<lastmod>2026-11-10</lastmod>
<changefreq>daily</changefreq>
<priority>1</priority>
</url>
<url>
<loc>https://www.acme.example/products/cordless-drill</loc>
<lastmod>2026-11-04</lastmod>
<changefreq>weekly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://www.acme.example/products?category=tools&sort=new</loc>
<lastmod>2026-11-09</lastmod>
<changefreq>daily</changefreq>
<priority>0.6</priority>
</url>
<url>
<loc>https://www.acme.example/support/warranty</loc>
<lastmod>2026-09-22</lastmod>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
</urlset>Learn more about loops, filtering and sorting.
Nested loops
A loop can contain another loop. In this SEPA credit transfer file (pain.001.001.09), {d.batches[i].id} repeats the payment block PmtInf for each execution date, and {d.batches[i].payments[i].name} repeats the transaction CdtTrfTxInf for each payment of the block. The PmtInf element with [i+1] closes the outer loop.
Aggregators fill the control sums: :aggCount counts the transactions and :aggSum adds their amounts, for the whole file in the group header, and for each block inside the loop.
{
"messageId": "ACME-SCT-20261110-01",
"createdAt": "2026-11-10T08:30:00Z",
"debtor": {
"name": "Acme Corporation",
"iban": "FR7630006000011234567890189"
},
"batches": [
{
"id": "BATCH-20261112",
"executionDate": "2026-11-12",
"payments": [
{ "invoice": "INV-88412", "amount": 1249.99, "name": "Globex GmbH", "iban": "DE89370400440532013000" },
{ "invoice": "INV-88419", "amount": 860.25, "name": "Initech B.V.", "iban": "NL91ABNA0417164300" }
]
},
{
"id": "BATCH-20261115",
"executionDate": "2026-11-15",
"payments": [
{ "invoice": "INV-88433", "amount": 3420.17, "name": "Umbrella Logistica S.L.", "iban": "ES9121000418450200051332" }
]
}
]
}<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.09">
<CstmrCdtTrfInitn>
<GrpHdr>
<MsgId>{d.messageId}</MsgId>
<CreDtTm>{d.createdAt:formatD('YYYY-MM-DDTHH:mm:ssZ')}</CreDtTm>
<NbOfTxs>{d.batches[].payments[].amount:aggCount}</NbOfTxs>
<CtrlSum>{d.batches[].payments[].amount:aggSum:round(2)}</CtrlSum>
<InitgPty><Nm>{d.debtor.name}</Nm></InitgPty>
</GrpHdr>
<PmtInf>
<PmtInfId>{d.batches[i].id}</PmtInfId>
<PmtMtd>TRF</PmtMtd>
<NbOfTxs>{d.batches[i].payments[].amount:aggCount}</NbOfTxs>
<CtrlSum>{d.batches[i].payments[].amount:aggSum:round(2)}</CtrlSum>
<PmtTpInf><SvcLvl><Cd>SEPA</Cd></SvcLvl></PmtTpInf>
<ReqdExctnDt><Dt>{d.batches[i].executionDate}</Dt></ReqdExctnDt>
<Dbtr><Nm>{d.debtor.name}</Nm></Dbtr>
<DbtrAcct><Id><IBAN>{d.debtor.iban}</IBAN></Id></DbtrAcct>
<DbtrAgt><FinInstnId><Othr><Id>NOTPROVIDED</Id></Othr></FinInstnId></DbtrAgt>
<CdtTrfTxInf>
<PmtId><EndToEndId>{d.batches[i].payments[i].invoice}</EndToEndId></PmtId>
<Amt><InstdAmt Ccy="EUR">{d.batches[i].payments[i].amount}</InstdAmt></Amt>
<Cdtr><Nm>{d.batches[i].payments[i].name}</Nm></Cdtr>
<CdtrAcct><Id><IBAN>{d.batches[i].payments[i].iban}</IBAN></Id></CdtrAcct>
</CdtTrfTxInf>
<CdtTrfTxInf>
<PmtId><EndToEndId>{d.batches[i].payments[i+1].invoice}</EndToEndId></PmtId>
</CdtTrfTxInf>
</PmtInf>
<PmtInf>
<PmtInfId>{d.batches[i+1].id}</PmtInfId>
</PmtInf>
</CstmrCdtTrfInitn>
</Document><?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.09">
<CstmrCdtTrfInitn>
<GrpHdr>
<MsgId>ACME-SCT-20261110-01</MsgId>
<CreDtTm>2026-11-10T09:30:00+01:00</CreDtTm>
<NbOfTxs>3</NbOfTxs>
<CtrlSum>5530.41</CtrlSum>
<InitgPty><Nm>Acme Corporation</Nm></InitgPty>
</GrpHdr>
<PmtInf>
<PmtInfId>BATCH-20261112</PmtInfId>
<PmtMtd>TRF</PmtMtd>
<NbOfTxs>2</NbOfTxs>
<CtrlSum>2110.24</CtrlSum>
<PmtTpInf><SvcLvl><Cd>SEPA</Cd></SvcLvl></PmtTpInf>
<ReqdExctnDt><Dt>2026-11-12</Dt></ReqdExctnDt>
<Dbtr><Nm>Acme Corporation</Nm></Dbtr>
<DbtrAcct><Id><IBAN>FR7630006000011234567890189</IBAN></Id></DbtrAcct>
<DbtrAgt><FinInstnId><Othr><Id>NOTPROVIDED</Id></Othr></FinInstnId></DbtrAgt>
<CdtTrfTxInf>
<PmtId><EndToEndId>INV-88412</EndToEndId></PmtId>
<Amt><InstdAmt Ccy="EUR">1249.99</InstdAmt></Amt>
<Cdtr><Nm>Globex GmbH</Nm></Cdtr>
<CdtrAcct><Id><IBAN>DE89370400440532013000</IBAN></Id></CdtrAcct>
</CdtTrfTxInf>
<CdtTrfTxInf>
<PmtId><EndToEndId>INV-88419</EndToEndId></PmtId>
<Amt><InstdAmt Ccy="EUR">860.25</InstdAmt></Amt>
<Cdtr><Nm>Initech B.V.</Nm></Cdtr>
<CdtrAcct><Id><IBAN>NL91ABNA0417164300</IBAN></Id></CdtrAcct>
</CdtTrfTxInf>
</PmtInf>
<PmtInf>
<PmtInfId>BATCH-20261115</PmtInfId>
<PmtMtd>TRF</PmtMtd>
<NbOfTxs>1</NbOfTxs>
<CtrlSum>3420.17</CtrlSum>
<PmtTpInf><SvcLvl><Cd>SEPA</Cd></SvcLvl></PmtTpInf>
<ReqdExctnDt><Dt>2026-11-15</Dt></ReqdExctnDt>
<Dbtr><Nm>Acme Corporation</Nm></Dbtr>
<DbtrAcct><Id><IBAN>FR7630006000011234567890189</IBAN></Id></DbtrAcct>
<DbtrAgt><FinInstnId><Othr><Id>NOTPROVIDED</Id></Othr></FinInstnId></DbtrAgt>
<CdtTrfTxInf>
<PmtId><EndToEndId>INV-88433</EndToEndId></PmtId>
<Amt><InstdAmt Ccy="EUR">3420.17</InstdAmt></Amt>
<Cdtr><Nm>Umbrella Logistica S.L.</Nm></Cdtr>
<CdtrAcct><Id><IBAN>ES9121000418450200051332</IBAN></Id></CdtrAcct>
</CdtTrfTxInf>
</PmtInf>
</CstmrCdtTrfInitn>
</Document>Learn more about aggregators.
Numbers and dates
XML schemas expect machine formats, not the formats of a language. Use these formatters:
| Value | Tag | Result |
|---|---|---|
Date (xs:date) |
{d.date:formatD('YYYY-MM-DD')} |
2026-11-12 |
Date and time (xs:dateTime) |
{d.createdAt:formatD('YYYY-MM-DDTHH:mm:ssZ')} |
2026-11-10T09:30:00+01:00 |
| Factur-X date (format 102) | {d.issueDate:formatD('YYYYMMDD')} |
20261110 |
Decimal (xs:decimal) |
{d.total:round(2)} |
3152.64 |
- Dates with a time are converted to the
timezoneof the report,Europe/Parisby default. Dates without a time are not converted. :round(2)writes a dot whatever thelangof the report, without trailing zeros: 49.9. When the receiver expects exactly two decimals, add{o.lang=en-us}to the template (it sets the language of the whole report) and write{d.price:formatN(2):replace(',', '')}: 49.90.:formatNand:formatCalone add thousands separators and follow the language, like 1 234,50 in French.
See the date and number formatters, and in-template options.
Conditions
Schemas often reject empty elements. Remove an optional element when its value is missing, or print one value or another:
- Conditional blocks remove the elements between
:showBeginand:showEndwhen the condition is false. In this Google Merchant Center feed,{d.products[i].salePrice:ifNEM:showBegin}keepsg:sale_pricefor the products on sale only, and each product gets eitherg:gtinorg:identifier_exists. - Inline conditions print one value or another:
{d.products[i].stock:ifGT(0):show('in_stock'):elseShow('out_of_stock')}.
{
"store": {
"name": "Acme Outdoor",
"url": "https://shop.acme.example",
"description": "Camping and hiking gear"
},
"products": [
{
"sku": "TNT-2P-GRN",
"title": "Ridge 2-Person Tent & Footprint",
"url": "https://shop.acme.example/p/ridge-tent?color=green&size=2p",
"image": "https://shop.acme.example/img/ridge-tent-green.jpg",
"stock": 34,
"price": 249.99,
"salePrice": 199.99,
"brand": "Acme Outdoor",
"gtin": "00012345678905"
},
{
"sku": "LMP-HD-350",
"title": "Trail Headlamp 350 lm",
"url": "https://shop.acme.example/p/trail-headlamp",
"image": "https://shop.acme.example/img/trail-headlamp.jpg",
"stock": 0,
"price": 39.95,
"salePrice": null,
"brand": "Acme Outdoor",
"gtin": ""
}
]
}<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:g="http://base.google.com/ns/1.0">
<channel>
<title>{d.store.name}</title>
<link>{d.store.url}</link>
<description>{d.store.description}</description>
<item>
<g:id>{d.products[i].sku}</g:id>
<title>{d.products[i].title}</title>
<link>{d.products[i].url}</link>
<g:image_link>{d.products[i].image}</g:image_link>
<g:availability>{d.products[i].stock:ifGT(0):show('in_stock'):elseShow('out_of_stock')}</g:availability>
<g:price>{d.products[i].price} USD</g:price>{d.products[i].salePrice:ifNEM:showBegin}
<g:sale_price>{d.products[i].salePrice} USD</g:sale_price>{d.products[i].salePrice:showEnd}
<g:brand>{d.products[i].brand}</g:brand>{d.products[i].gtin:ifNEM:showBegin}
<g:gtin>{d.products[i].gtin}</g:gtin>{d.products[i].gtin:showEnd}{d.products[i].gtin:ifEM:showBegin}
<g:identifier_exists>no</g:identifier_exists>{d.products[i].gtin:showEnd}
<g:condition>new</g:condition>
</item>
<item>
<g:id>{d.products[i+1].sku}</g:id>
</item>
</channel>
</rss><?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:g="http://base.google.com/ns/1.0">
<channel>
<title>Acme Outdoor</title>
<link>https://shop.acme.example</link>
<description>Camping and hiking gear</description>
<item>
<g:id>TNT-2P-GRN</g:id>
<title>Ridge 2-Person Tent & Footprint</title>
<link>https://shop.acme.example/p/ridge-tent?color=green&size=2p</link>
<g:image_link>https://shop.acme.example/img/ridge-tent-green.jpg</g:image_link>
<g:availability>in_stock</g:availability>
<g:price>249.99 USD</g:price>
<g:sale_price>199.99 USD</g:sale_price>
<g:brand>Acme Outdoor</g:brand>
<g:gtin>00012345678905</g:gtin>
<g:condition>new</g:condition>
</item>
<item>
<g:id>LMP-HD-350</g:id>
<title>Trail Headlamp 350 lm</title>
<link>https://shop.acme.example/p/trail-headlamp</link>
<g:image_link>https://shop.acme.example/img/trail-headlamp.jpg</g:image_link>
<g:availability>out_of_stock</g:availability>
<g:price>39.95 USD</g:price>
<g:brand>Acme Outdoor</g:brand>
<g:identifier_exists>no</g:identifier_exists>
<g:condition>new</g:condition>
</item>
</channel>
</rss>Write the begin tag at the end of the line above the block, and the end tag at the end of the last line of the block: the removed block leaves no empty line. :hideBegin and :hideEnd work the same way.
To remove an attribute, write the block inside the start tag: <Contact{d.email:ifNEM:showBegin} email="{d.email}"{d.email:showEnd}>. The template is no longer well-formed XML, but the report is. Learn more about conditional blocks and inline conditions.
Totals
Math formatters and aggregators compute the amounts from the data. This Factur-X invoice uses the MINIMUM profile, which has no invoice lines: {d.lines[].qty:mul(.price):aggSum} computes the net total from the lines of the JSON data, and :set stores it in c.net. The tax and the totals below read c.net.
{
"number": "FA-2026-0417",
"issueDate": "2026-11-10",
"currency": "EUR",
"vatRate": 20,
"prepaid": 500,
"seller": {
"name": "Acme Corporation SAS",
"siren": "999999998",
"country": "FR",
"vatId": "FR11999999998"
},
"buyer": {
"name": "Globex SARL"
},
"lines": [
{ "name": "Cordless drill 18 V", "qty": 12, "price": 129.99 },
{ "name": "Battery pack 5 Ah", "qty": 24, "price": 64.49 },
{ "name": "Delivery", "qty": 1, "price": 45 }
]
}<?xml version="1.0" encoding="UTF-8"?>
<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
<rsm:ExchangedDocumentContext>
<ram:GuidelineSpecifiedDocumentContextParameter>
<ram:ID>urn:factur-x.eu:1p0:minimum</ram:ID>
</ram:GuidelineSpecifiedDocumentContextParameter>
</rsm:ExchangedDocumentContext>
<rsm:ExchangedDocument>
<ram:ID>{d.number}</ram:ID>
<ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime>
<udt:DateTimeString format="102">{d.issueDate:formatD('YYYYMMDD')}</udt:DateTimeString>
</ram:IssueDateTime>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction>
<ram:ApplicableHeaderTradeAgreement>
<ram:SellerTradeParty>
<ram:Name>{d.seller.name}</ram:Name>
<ram:SpecifiedLegalOrganization><ram:ID schemeID="0002">{d.seller.siren}</ram:ID></ram:SpecifiedLegalOrganization>
<ram:PostalTradeAddress><ram:CountryID>{d.seller.country}</ram:CountryID></ram:PostalTradeAddress>
<ram:SpecifiedTaxRegistration><ram:ID schemeID="VA">{d.seller.vatId}</ram:ID></ram:SpecifiedTaxRegistration>
</ram:SellerTradeParty>
<ram:BuyerTradeParty>
<ram:Name>{d.buyer.name}</ram:Name>
</ram:BuyerTradeParty>
</ram:ApplicableHeaderTradeAgreement>
<ram:ApplicableHeaderTradeDelivery/>
<ram:ApplicableHeaderTradeSettlement>{d.lines[].qty:mul(.price):aggSum:round(2):set(c.net)}
<ram:InvoiceCurrencyCode>{d.currency}</ram:InvoiceCurrencyCode>{c.net:mul(d.vatRate):div(100):round(2):set(c.vat)}
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:TaxBasisTotalAmount>{c.net}</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount currencyID="{d.currency}">{c.vat}</ram:TaxTotalAmount>
<ram:GrandTotalAmount>{c.net:add(c.vat):round(2)}</ram:GrandTotalAmount>
<ram:DuePayableAmount>{c.net:add(c.vat):sub(d.prepaid):round(2)}</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
</ram:ApplicableHeaderTradeSettlement>
</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice><?xml version="1.0" encoding="UTF-8"?>
<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
<rsm:ExchangedDocumentContext>
<ram:GuidelineSpecifiedDocumentContextParameter>
<ram:ID>urn:factur-x.eu:1p0:minimum</ram:ID>
</ram:GuidelineSpecifiedDocumentContextParameter>
</rsm:ExchangedDocumentContext>
<rsm:ExchangedDocument>
<ram:ID>FA-2026-0417</ram:ID>
<ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime>
<udt:DateTimeString format="102">20261110</udt:DateTimeString>
</ram:IssueDateTime>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction>
<ram:ApplicableHeaderTradeAgreement>
<ram:SellerTradeParty>
<ram:Name>Acme Corporation SAS</ram:Name>
<ram:SpecifiedLegalOrganization><ram:ID schemeID="0002">999999998</ram:ID></ram:SpecifiedLegalOrganization>
<ram:PostalTradeAddress><ram:CountryID>FR</ram:CountryID></ram:PostalTradeAddress>
<ram:SpecifiedTaxRegistration><ram:ID schemeID="VA">FR11999999998</ram:ID></ram:SpecifiedTaxRegistration>
</ram:SellerTradeParty>
<ram:BuyerTradeParty>
<ram:Name>Globex SARL</ram:Name>
</ram:BuyerTradeParty>
</ram:ApplicableHeaderTradeAgreement>
<ram:ApplicableHeaderTradeDelivery/>
<ram:ApplicableHeaderTradeSettlement>
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:TaxBasisTotalAmount>3152.64</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount currencyID="EUR">630.53</ram:TaxTotalAmount>
<ram:GrandTotalAmount>3783.17</ram:GrandTotalAmount>
<ram:DuePayableAmount>3283.17</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
</ram:ApplicableHeaderTradeSettlement>
</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>A :set tag prints nothing. Write it at the end of a line, above the tags that read its value. Learn more about math formatters and :set.
The BASIC, EN 16931 and EXTENDED profiles add the invoice lines: repeat ram:IncludedSupplyChainTradeLineItem with a loop. To embed the XML in the PDF invoice, use :attachFile, as in the Factur-X invoice example.
Best practices
- Attributes: keep free text in elements, and codes or identifiers in attributes, like
currencyID="EUR". When an attribute holds free text, encode its double quotes:{d.name:preserveCharRef:replace('"', '"')}. Learn more - Encoding: save the template in UTF-8 and keep
encoding="UTF-8"in the declaration. For a receiver that requires another encoding, send character references in the data, likecafé, and add:preserveCharRefto the tag. - Optional elements: most schemas reject an empty date or amount. Remove these elements with a conditional block when the value is missing.
- Validation: before going live, check a few reports with the schema or the validator of the receiver.
Automate an XML file
To generate an XML file from an XML template with the Carbone API:
- Prepare two files: an XML template with Carbone tags, like
{d.name}, and the JSON data to populate it. You can use the files of the Nested loops example. - Generate the XML in one of three ways:
- Use an official Carbone integration, like N8N, Make, Zapier, Airtable or Bubble.
- Use a Carbone SDK: Node.js, Go, Python, Java, JavaScript or PHP.
- Send a
POST /render/templateHTTP request to the Carbone API, like this curl command:
curl --location --request POST 'https://api.carbone.io/render/template?download=true' \
--header 'carbone-version: 5' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer API_TOKEN' \
--data-raw "{
\"data\": $(cat nested-data.json),
\"template\": \"$(base64 -i nested-template.xml)\",
\"timezone\": \"Europe/Paris\"
}" \
--output report.xml
💡 Linux users: replacebase64 -i nested-template.xmlwithbase64 -w 0 nested-template.xml
Key parameters
| Parameter | Description |
|---|---|
template |
Your XML template, encoded as a Base64 string. |
data |
JSON data used to populate the template. |
timezone |
Time zone of the dates and times printed by :formatD, like "UTC". "Europe/Paris" by default. See time zones. |
lang |
Optional: language of the translations and of :formatN and :formatC. |
convertTo |
Omit it: an XML template generates an XML file. |
?download=true |
Query parameter to download the document as a stream. |
Authorization |
Header required for the Carbone Cloud API. Get your API key here. |
For more details, refer to the Carbone API Documentation.