Order mapping
Orders are the heaviest resource. StagingOrder mixes flat fields
(addresses split into shipping_address1 etc., a single discount
shape) with nested pass-through arrays for line items,
transactions, tax lines, and shipping lines.
Quick reference — minimum loadable order
{
"original_id": increment_id,
"name": "#" & $string(increment_id),
"email": customer_email,
"processedAt": created_at,
"currency": order_currency,
"financialStatus": "PAID",
"lineItems": items.{
"title": name,
"sku": sku,
"quantity": qty_ordered,
"priceSet": {
"shopMoney": { "amount": $string(price), "currencyCode": $$.order_currency }
}
}
}processedAt is critical. If you omit it, the order’s
“created at” defaults to load time, breaking historical reports.
Always emit it from the source’s order timestamp.
Identity & status
namestringOrder display name (e.g. #1042). Customers and merchants see this.
"name": "#" & $string(increment_id)emailstringOrder contact email — used for notifications. Falls back to the customer’s email if omitted.
phonestringOrder contact phone.
processedAtstring (ISO8601)When the order was placed on the source platform. Always emit this on historical orders so the timeline is preserved.
"processedAt": created_atclosedAtstring (ISO8601)When the order was closed (typically equal to processedAt for
fully-fulfilled historical orders).
financialStatusstringOne of PENDING, AUTHORIZED, PARTIALLY_PAID, PAID,
PARTIALLY_REFUNDED, REFUNDED, VOIDED.
"financialStatus": is_paid ? "PAID" : "PENDING"fulfillmentStatusstringOne of FULFILLED, PARTIALLY_FULFILLED, RESTOCKED. Omit for
unfulfilled orders.
taxesIncludedbooleantrue if line item prices already include tax (common in EU
merchants), false if tax is added on top (common in US).
buyerAcceptsMarketingbooleansourceIdentifierstringThe original platform’s order ID — preserves cross-system
traceability. Often the same as original_id for orders.
sourceNamestringWhere the order originated (e.g. web, pos, magento).
Currency
currencystringISO 4217 currency code for the shop’s base currency on this order.
Used inside priceSet.shopMoney.currencyCode of every line item.
"currency": order_currencypresentmentCurrencystringThe currency the customer saw at checkout, if multi-currency. Often
equal to currency for single-currency orders.
Customer
The order's customer is composed from these fields. The staging model assembles them into Shopify's customer.toUpsert shape.
firstNamestringUsed on the order’s customer record AND on shipping/billing addresses.
lastNamestringcustomerNotestringNote attached to the customer on this order. Different from note
(below), which is the order-level admin note.
customerTagsstring[]Tags attached to the customer (not the order).
Shipping address (flat)
Shopify nests its address shapes; the staging model flattens them. Setting shipping_address1 is what triggers the shipping address being attached.
shipping_address1string"shipping_address1": shipping.streetshipping_address2stringshipping_citystringshipping_provincestringState / province.
shipping_countrystringCountry code (ISO 3166-1 alpha-2 preferred).
shipping_zipstringBilling address (flat)
Same shape as shipping, with a billing_ prefix. Setting billing_address1 triggers the billing address.
billing_address1stringbilling_address2stringbilling_citystringbilling_provincestringbilling_countrystringbilling_zipstringLine items (nested pass-through)
Each line item is a Shopify-shaped object. The staging model validates each one and rejects malformed entries early.
lineItemsLineItem[]requiredArray of order line items. Each entry has the same shape Shopify’s
OrderCreateLineItemInput accepts:
| Field | Notes |
|---|---|
title | Product name as it was at purchase. |
quantity | int. Required per line. |
sku | Variant SKU at purchase. |
variantId | Shopify variant GID, if known. Omit and Graftport resolves via original_id matching after the products migrate. |
priceSet | { shopMoney: { amount: string, currencyCode } } — money is always strings. |
taxLines | Per-line-item tax breakdown. |
taxable / requiresShipping | Booleans. |
properties | Array of { name, value } for line-item customizations. |
vendor | Snapshotted vendor name. |
weight | Snapshotted weight. |
"lineItems": items.{
"title": name,
"sku": sku,
"quantity": qty_ordered,
"priceSet": {
"shopMoney": {
"amount": $string(price),
"currencyCode": $$.order_currency
}
}
}Discounts (flat — pick one)
Set exactly one discount field. The staging model wires it into Shopify's discount-code shape with a placeholder code.
itemPercentageDiscountnumberPercentage off as a number 0-100 (25 = 25%). Applied to qualifying
items.
"itemPercentageDiscount": discount_percentitemFixedDiscountnumberFixed money amount off (in the order’s currency). Rounded to 2 decimals.
freeShippingDiscountbooleantrue if the order had a free-shipping discount.
Fulfillment (flat)
Setting locationId is what triggers the fulfillment record. Without locationId, no fulfillment is created — even if you set the other fields.
locationIdstringThe Shopify location GID this order ships from. Required to create a fulfillment.
"locationId": $$.config.default_location_gidnotifyCustomerbooleanWhether to send a fulfillment notification email when the load creates the fulfillment. Default behavior is Shopify’s (no email for migrated orders is usually right).
trackingCompanystringCarrier name (e.g. UPS, DHL).
trackingNumberstringshipmentStatusstringOne of Shopify’s shipment statuses (e.g. DELIVERED,
IN_TRANSIT).
Transactions (nested pass-through)
transactionsTransaction[]Array of payment transactions. Each entry follows Shopify’s
OrderCreateOrderTransactionInput shape:
| Field | Notes |
|---|---|
kind | SALE, AUTHORIZATION, CAPTURE, REFUND, VOID, CHANGE. |
status | SUCCESS, FAILURE, PENDING, ERROR. |
amountSet | Money bag — { shopMoney: { amount, currencyCode } }. |
gateway | Payment processor name. |
processedAt | ISO8601. |
"transactions": [{
"kind": "SALE",
"status": "SUCCESS",
"gateway": payment_method,
"processedAt": created_at,
"amountSet": {
"shopMoney": { "amount": $string(grand_total), "currencyCode": order_currency }
}
}]Tax & shipping lines (nested pass-through)
taxLinesTaxLine[]Order-level tax breakdown. Each entry is { title, rate, priceSet }.
Mixing order-level and line-item-level tax lines double-counts the
total — pick one consistently per merchant.
shippingLinesShippingLine[]Shipping methods used on the order. Each entry is { title, priceSet }.
"shippingLines": [{
"title": shipping_method,
"priceSet": {
"shopMoney": { "amount": $string(shipping_amount), "currencyCode": order_currency }
}
}]Custom attributes & notes
dict_customAttributesobjectFree-form { key, value } map of order-level custom attributes
(notes from checkout, gift options, custom forms). Each entry
becomes one Shopify custom attribute.
"dict_customAttributes": {
"gift_message": gift_message,
"preferred_delivery": delivery_window
}notestringOrder-level admin note (separate from customerNote).
tagsstring[] | stringOrder-level tags.
Patterns
Magento order — minimum viable
{
"original_id": increment_id,
"name": "#" & increment_id,
"email": customer_email,
"phone": billing_address.telephone,
"firstName": customer_firstname,
"lastName": customer_lastname,
"processedAt": created_at,
"currency": order_currency_code,
"presentmentCurrency": order_currency_code,
"financialStatus": "PAID",
"taxesIncluded": false,
"shipping_address1": shipping_address.street[0],
"shipping_city": shipping_address.city,
"shipping_province": shipping_address.region_code,
"shipping_country": shipping_address.country_id,
"shipping_zip": shipping_address.postcode,
"billing_address1": billing_address.street[0],
"billing_city": billing_address.city,
"billing_country": billing_address.country_id,
"billing_zip": billing_address.postcode,
"lineItems": items.{
"title": name,
"sku": sku,
"quantity": qty_ordered,
"priceSet": {
"shopMoney": { "amount": $string(price), "currencyCode": $$.order_currency_code }
}
},
"transactions": [{
"kind": "SALE",
"status": "SUCCESS",
"gateway": payment.method,
"processedAt": created_at,
"amountSet": {
"shopMoney": { "amount": $string(grand_total), "currencyCode": order_currency_code }
}
}]
}Order with a percentage discount
{
"original_id": increment_id,
…,
"itemPercentageDiscount": discount_percent
}The staging model wires this into a Shopify discount code with a
placeholder code (migration_placeholder_percentage_code) — the
discount applies to the order, but no real coupon code is created.
Order with shipping fulfillment
{
"original_id": increment_id,
…,
"locationId": $$.config.default_location_gid,
"trackingCompany": shipment.carrier,
"trackingNumber": shipment.tracking_number,
"shipmentStatus": shipment.status = "delivered" ? "DELIVERED" : "IN_TRANSIT"
}Capture custom checkout fields
"dict_customAttributes": {
"gift_message": gift_message,
"delivery_instructions": delivery_notes,
"purchase_order": po_number
}Gotchas
Money amounts are strings inside priceSet. amount: 19.99
fails; amount: "19.99" works. Wrap with $string().
processedAtis critical for historical orders. Without it, the order shows up as created today.- Variants must exist before orders. Run the products load
before the orders load — otherwise
lineItemscan’t resolve to Shopify variant IDs and lose their product link. - Discount codes are placeholders. Setting
itemPercentageDiscountdoesn’t create a real reusable code on Shopify — it applies the discount to this single order with a generated placeholder. Use the discount code resource for real reusable codes. - Tax lines at order level vs line-item level: don’t mix. Pick one consistent level per merchant.
- Currency consistency. Top-level
currencyand thecurrencyCodeinside everypriceSet.shopMoneymust match for single-currency orders. shipping_address1is the trigger — without it, no shipping address is created even if you set city/zip/country.- Fulfillment requires
locationId. SettingtrackingNumberalone produces no fulfillment record.