Appearance
Mappings
For merchants
Where: Settings → Extensions → Export mappings
A mapping describes the document the receiving system gets. It is an allow-list: only fields you map are sent — nothing else from the order leaks out.
Editing a mapping
| Card | What you do there |
|---|---|
| General information | Name, description and Target format — JSON or XML. |
| Mapping definition | The mapping itself, written as JSON. Generate from order fills it with a starter mapping built from the test order selected in Test mapping — see below. Saving requires valid JSON; the definition itself is checked when you publish. |
| Test mapping | Choose a real order and click Test mapping. You see the rendered document and any field errors. Nothing is sent anywhere. |
| Import / Export | Copy a mapping out as JSON or YAML, or paste one in — handy for moving mappings between staging and production. |
Save stores the definition as an unpublished draft: it is kept after a page reload, but exports do not use it.
Publish validates the current definition, turns it into a new, numbered, read-only version (v1, v2…) and makes it the mapping's active version. Targets always use the active published version; a mapping that has never been published shows Not published (Draft in the list) and cannot be exported with. Edit freely, save, test, then publish again.
Generate a mapping from an order
Instead of writing a definition from scratch, choose an order in Test mapping and click Generate from order in the Mapping definition card. After you confirm, the definition is replaced with a starter mapping of every field, association and custom field that order contains: plain path entries, and an each for every list (sampled from its first entry). Then delete what the receiving system does not need, add functions, and Test mapping. Only what the selected order contains is generated — an order without, say, a promotion produces no promotion fields.
Writing a definition
The definition mirrors the document you want. Each field says where its value comes from:
| You write | Result |
|---|---|
{"path": "order.orderNumber"} | The value at that path in the order. A missing value gives null, not an error. |
{"expr": "money(order.amountTotal)"} | The result of an expression — maths, conditions, functions. |
"SHOPWARE" or {"literal": "SHOPWARE"} | A fixed value. Numbers and true/false work too. |
{ "name": …, "email": … } | A nested object. |
{"each": "order.lineItems", "as": "item", "where": "…", "map": {…}} | A list: one entry per line item (or any other list), optionally filtered. |
Everything in the order is available under order. — order number, dates, amounts, currency, customer, billing and shipping addresses with country, line items, deliveries with shipping method, transactions with payment method, tags, sales channel, state and more. Use Test mapping to see what an order contains.
A complete example
json
{
"orderNumber": { "path": "order.orderNumber" },
"orderDate": { "expr": "format_date(order.orderDateTime, 'Y-m-d')" },
"source": "SHOPWARE",
"customer": {
"name": { "expr": "concat(order.orderCustomer.firstName, ' ', order.orderCustomer.lastName)" },
"email": { "path": "order.orderCustomer.email" },
"country": { "expr": "country_iso(order.billingAddress.country.iso)" }
},
"lines": {
"each": "order.lineItems",
"as": "item",
"where": "item.type == 'product'",
"map": {
"sku": { "path": "item.payload.productNumber" },
"qty": { "path": "item.quantity" },
"net": { "expr": "money(item.totalPrice)" },
"vat": { "expr": "tax_rate(item.price.calculatedTaxes[0].taxRate)" }
}
},
"total": { "expr": "money(order.amountTotal)" }
}Rendered against an order:
json
{
"orderNumber": "10001",
"orderDate": "2026-09-01",
"source": "SHOPWARE",
"customer": { "name": "Ada Obi", "email": "ada@example.com", "country": "NG" },
"lines": [ { "sku": "SW10001", "qty": 2, "net": 100, "vat": 19 } ],
"total": 119
}Promotion and shipping lines are left out by the where filter.
Functions
| Function | Does | Example |
|---|---|---|
concat(a, b, …) | Joins values as text; empty values are skipped | concat(order.orderCustomer.firstName, ' ', order.orderCustomer.lastName) |
default(value, fallback) | fallback when value is empty | default(order.customerComment, '') |
money(amount, decimals = 2) | Rounds to a clean number | money(order.amountTotal) |
format_date(date, format = 'Y-m-d', timezone = 'UTC') | Formats a date (PHP format) | format_date(order.orderDateTime, 'd.m.Y H:i', 'Africa/Lagos') |
country_iso(code) | Upper-cases a country code | country_iso(order.billingAddress.country.iso) |
tax_rate(rate) | A tax rate as a number | tax_rate(item.price.calculatedTaxes[0].taxRate) |
tax_rate() with a list of taxes returns 0
tax_rate() is meant to also accept the whole list of calculated taxes and return the highest rate, but in 0.9.0-beta.2 that returns 0. Pass a single rate as in the example above. See Known issues.
The full syntax — operators, conditions, lists — is in the mapping language reference.
XML output
With Target format: XML, the same definition is written as XML with the root element <order>. List entries become repeated elements.
Keep payloads stable
The plugin skips an export when the rendered document is identical to the last one that succeeded. Avoid values that change on every render (current time, random IDs) — they make every export look new.