Mapping Notation
When payload reshaping is enabled on a pipeline, you use field paths to describe where data comes from in the Shopify payload and where it should appear in the forwarded payload. The notation is based on JSON dot-notation.
Basic Syntax
A path is a dot-separated sequence of property names that describes how to navigate a JSON object.
idThe [] suffix on a segment marks that property as an array. It tells Shop Vector to iterate over every item in that array.
line_items[]Two ways to build a mapping
Payload reshaping offers two editors for the same mapping, and you can switch between them at any time:
- Visual editor — a drag-and-drop canvas where you add source and output nodes and connect them.
- Text (JSON) — a JSON text box for entering the whole mapping at once. Handy for large mappings, or for pasting a mapping in from somewhere else.
Both produce exactly the same result, and every path pattern described on this page works identically in either editor.
The Text (JSON) format
The Text (JSON) editor holds a single JSON object. Each key is an output path and each value is the input path it's mapped from:
{
"id": "id",
"contact.email": "email",
"totals.grand_total": "total_price",
"customer.name": "customer.first_name"
}This is the single field to single field example below, written as JSON. Note the direction: the output path is the key (on the left) and the input path is the value (on the right) — the reverse of the column order used by the tables on this page.
Array and fixed-position paths are written the same way; the key and value are just paths:
{
"lineitems[].name": "line_items[].name",
"lineitems[].count": "line_items[].quantity",
"blocks[0].name": "customer.first_name"
}Templated fields
A templated field (Scale and Enterprise) has no input path — its value is composed from literal text and ${...} references to source fields. In the Text (JSON) editor, write it as an object value with a type of "template" and a value string:
{
"customer.name": "customer.first_name",
"greeting": { "type": "template", "value": "Hi ${customer.first_name}" }
}Each ${...} token references a source path from the incoming payload. A token that resolves to nothing is substituted with an empty string, so a single missing field won't fail the whole mapping.
When you save, every input path is checked against the source properties for the selected webhook topic, and an unknown field name is reported before the pipeline is saved. A fixed array position such as line_items[0].name is validated as line_items[].name — the field must exist, but the index itself isn't checked (the property list is built from a sample payload, so array lengths aren't known).
Round-tripping
Switching from the visual editor to Text (JSON) regenerates the JSON from the canvas. Nodes that aren't connected to anything contribute nothing to the output, so they won't appear in the JSON.
The example payload
Every example on this page uses the same Shopify payload as its input. It is a trimmed orders/create webhook. Refer back to it as you read through the patterns below.
{
"id": 820982911946154508,
"email": "[email protected]",
"name": "#9999",
"total_price": "404.95",
"customer": {
"first_name": "John",
"last_name": "Smith"
},
"line_items": [
{ "name": "Aviator sunglasses", "quantity": 2, "price": "89.99", "sku": "SKU2006-001" },
{ "name": "Mid-century lounger", "quantity": 1, "price": "159.99", "sku": "SKU2006-020" }
]
}Mapping Patterns
Single field to single field
Maps one scalar value to a new key. Both the source and the destination can be nested — customer.first_name navigates down through the input, and an output path like customer.name builds nested objects in the forwarded payload.
| Input path | Output path |
|---|---|
id | id |
email | contact.email |
total_price | totals.grand_total |
customer.first_name | customer.name |
Applied to the example payload, this produces:
{
"id": 820982911946154508,
"contact": {
"email": "[email protected]"
},
"totals": {
"grand_total": "404.95"
},
"customer": {
"name": "John"
}
}Array to array
Copies an entire array (each item in full) into a new key.
| Input path | Output path |
|---|---|
line_items[] | lineitems[] |
Produces:
{
"lineitems": [
{ "name": "Aviator sunglasses", "quantity": 2, "price": "89.99", "sku": "SKU2006-001" },
{ "name": "Mid-century lounger", "quantity": 1, "price": "159.99", "sku": "SKU2006-020" }
]
}Property inside an array to a property inside another array
Extracts a single property from each item in an array and places it under a new property name on each corresponding item in the output array.
| Input path | Output path |
|---|---|
line_items[].name | lineitems[].name |
Produces:
{
"lineitems": [
{ "name": "Aviator sunglasses" },
{ "name": "Mid-century lounger" }
]
}The output array has the same number of items as the input array. This single rule contributes only the one mapped property; to place several properties on each item, you combine multiple rules — see Merging properties into the same output array.
Property inside an array to a flat array
Collects a single property from every item in an array into a new flat array of scalar values.
| Input path | Output path |
|---|---|
line_items[].name | lineitems_names[] |
Produces:
{
"lineitems_names": ["Aviator sunglasses", "Mid-century lounger"]
}The difference from the previous pattern is in the output path: lineitems[].name produces an array of objects, while lineitems_names[] produces an array of values.
Writing to a specific array position
Where [] iterates over a whole array, a numeric index like [0] targets one specific position in an output array. Use it when your destination expects a fixed structure — for example the ordered blocks of a Slack Block Kit message.
| Input path | Output path |
|---|---|
customer.first_name | blocks[0].name |
Produces:
{
"blocks": [
{ "name": "John" }
]
}You can set several properties on the same indexed item, and you can target more than one index. Any position you don't map is filled with null so the remaining items keep their place:
| Input | Output |
|---|---|
customer.first_name | blocks[0].name |
total_price | blocks[2].amount |
Produces:
{
"blocks": [
{ "name": "John" },
null,
{ "amount": "404.95" }
]
}To drop a value straight into a slot — rather than as a property of an object — omit the trailing property name:
| Input | Output |
|---|---|
email | recipients[0] |
Produces:
{
"recipients": ["[email protected]"]
}Reading a specific array element
A numeric index also works on the input path, to pull a single element out of a Shopify array:
| Input path | Output path |
|---|---|
line_items[0].name | first_item |
Produces:
{
"first_item": "Aviator sunglasses"
}Rules for fixed positions
- A path can't combine
[]and[n]— a segment either iterates the whole array or targets one position. - Each indexed property can only be mapped once.
- A position is either a single value or an object of properties, not both.
- Templated fields (Scale and Enterprise) can both read an indexed element and target one — for example, writing a literal or composed value to
blocks[0].type.
Combining Multiple Mappings
Multiple mappings are applied together to build a single output payload. Each mapping contributes its output key(s), and the results are merged.
Merging properties into the same output array
When two or more mappings share the same output array name, Shop Vector merges them into a single array — each item in the array receives all the mapped properties.
| Input | Output |
|---|---|
line_items[].name | lineitems[].name |
line_items[].quantity | lineitems[].count |
Both mappings target lineitems[], so their properties are combined per item:
{
"lineitems": [
{ "name": "Aviator sunglasses", "count": 2 },
{ "name": "Mid-century lounger", "count": 1 }
]
}The source property quantity is also renamed to count in the process. You can map and rename as many properties from the same source array as you need, and they all land on the same output item.
Mixing array merges with other mappings
You can freely combine array merges with scalar and flat-array mappings in the same pipeline. An output array item doesn't have to be built entirely from another array — a scalar input can be mapped onto every item, so a shared value like the order id is repeated across each one:
| Input | Output |
|---|---|
id | id |
customer.first_name | customer_name |
id | lineitems[].order_id |
line_items[].name | lineitems[].name |
line_items[].quantity | lineitems[].count |
line_items[].name | lineitems_names[] |
Produces:
{
"id": 820982911946154508,
"customer_name": "John",
"lineitems": [
{ "order_id": 820982911946154508, "name": "Aviator sunglasses", "count": 2 },
{ "order_id": 820982911946154508, "name": "Mid-century lounger", "count": 1 }
],
"lineitems_names": ["Aviator sunglasses", "Mid-century lounger"]
}Because id is a scalar rather than an array, its value is copied into every item of lineitems[].
Summary
| Pattern | Input example | Output example |
|---|---|---|
| Single field | id → id | Scalar value at new key |
| Array | line_items[] → lineitems[] | Full array under new key |
| Array property → object array | line_items[].name → lineitems[].name | Array of objects, one property each |
| Array property → value array | line_items[].name → lineitems_names[] | Flat array of scalar values |
| Merged array properties | line_items[].name → lineitems[].name + line_items[].quantity → lineitems[].count | Array of objects with multiple properties |
| Fixed array position | customer.first_name → blocks[0].name | Value written to one specific array item |
| Fixed element read | line_items[0].name → first_item | Single element pulled from an input array |
