Shopify GraphQL migration¶
Linnworks is upgrading Shopify integrations from Shopify's REST API to its GraphQL API. After an integration is upgraded, new orders arrive with a differently shaped order XML. This page explains what changed, what XmlExtractor 1.1.0 handles for you, and what to check in your own configurations.
Linnworks' guide: Shopify integration upgrade to GraphQL in Linnworks. Section 7 covers the order XML. Linnworks' detailed companion to that section, Shopify OrderXML Data Changes, lists every field rename; ask Linnworks support for a copy. The tables below include everything it describes.
What changed in the XML¶
| Change | Before, REST | After, GraphQL |
|---|---|---|
| Node names | PascalCase, for example LineItems |
camelCase, for example lineItems |
| Renamed nodes | FinancialStatus = paid |
displayFinancialStatus = PAID |
| IDs | 6380782551076 |
gid://shopify/Order/6380782551076 |
| Prices | Price |
Blank. The amount is in originalUnitPriceSet > shopMoney > amount |
| Line items | A flat list | lineItems with one nodes element per line |
| Shipping lines | A flat list | shippingLines > nodes with code and title |
| Custom attributes | NoteAttributes > Property on the order and Properties > Property on line items, as Name/Value pairs |
customAttributes on the order and on each line item, as key/value pairs. The Property wrapper is gone |
| Other renamed nodes | Currency, PresentmentCurrency, OrderNumber, BuyerAcceptsMarketing, BrowserIp, OrderStatusUrl, PaymentGatewayNames > string |
currencyCode, presentmentCurrencyCode, number, customerAcceptsMarketing, clientIp, statusPageUrl, paymentGatewayNames |
| Removed nodes | Number, the internal sequence number; ProductExists |
Gone. Number now matches number, the customer-facing order number, through the case fallback |
| SKU and vendor | LineItems > LineItem > Sku and Vendor |
Blank at line level. The SKU is under lineItems > nodes > variant > sku or variant > inventoryItem > sku, the vendor under product > vendor |
| Money | ShopMoney listed first |
presentmentMoney listed first, and currencyCode blank inside each money set; the currency is stated once at order level |
| Status values | Lower case: paid, open |
Upper case: PAID, OPEN |
| Dates | 2026-01-22T08:44:12+00:00 |
2026-01-22T08:44:12Z |
| Delivery method | FulfillmentOrders > FulfillmentOrder > DeliveryMethod > MethodType = shipping |
fulfillmentOrders > nodes > deliveryMethod > methodType = SHIPPING. MethodType alone still resolves; the value is upper case |
| Gift card flag | LineItems > LineItem > GiftCard |
lineItems > nodes > isGiftCard |
| Transactions | Transactions > Transaction > Gateway |
transactions > gateway; the Transaction wrapper is gone |
| Browser IP | ClientDetails > BrowserIp |
clientIp |
| Staff user | UserId |
No equivalent seen. staffMember exists but is empty in the samples |
| Risk block | Risks > Data > Order > Risk > Assessments > Assessment > Fact > Description |
risk > assessments > facts > description, each with a sentiment |
| Blank nodes | Rare | Common. GraphQL only returns what Linnworks asks for, so many nodes are empty. |
| Fulfillment orders | Not present | fulfillmentOrders, listed before the order's own nodes, with its own id, a location > id, and a partial lineItems |
Only orders downloaded after the upgrade use the new shape. Orders already in Linnworks keep the old one, so both exist side by side for a while.
Linnworks also changes the order reference to
{ShopifyOrderId}-{FulfillmentOrderId}. XmlExtractor receives Linnworks
order IDs from the Rules Engine and never reads the reference, so that change
doesn't affect it.
What XmlExtractor 1.1.0 does for you¶
NoteAttribute.reads both shapes. It looks for aname/valuepair first and akey/valuepair when there is none. A configuration such asNoteAttribute.Gift wrapkeeps working on old and new orders without a change.- Case no longer breaks a path. Exact case still wins when it exists.
When it doesn't, the first node that matches ignoring case is used, so
LineItems>SkufindslineItems > nodes > sku. - Empty copies are skipped. When a match has an empty value, or the rest
of the path finds nothing under it, the next match is tried. The partial
lineItemsunderfulfillmentOrdersno longer hides the real one. - The macro records the format. Each order in the new shape is marked in the macro's log, which support can read, so we can tell you which of your orders arrive in the new shape.
- Empty nodes can't break an order. The new XML contains many empty
nodes such as
<name />. Version 1.0.0 could fail the whole order on them. Version 1.1.0 ignores them.
What to check in your configurations¶
- Renamed nodes.
FinancialStatusis nowdisplayFinancialStatus, and its values are upper-case,PAIDrather thanpaid. Update the path and any Rules Engine condition that compares the value. - Blank line-item names.
lineItems > nodes > nameis empty in the new shape. Usetitle, soLineItems>NamebecomeslineItems>nodes>titleor, with the case fallback,LineItems>Title. - Prices. Plain price nodes are blank. Use the money objects, for
example
totalPriceSet>shopMoney>amountorlineItems>nodes>originalUnitPriceSet>shopMoney>amount. - Shadowed nodes.
idnow returns a location id andnamereturns the billing name, becausefulfillmentOrdersandbillingAddresscome first. Use>>idand>>name: a leading>>prefers the shallowest match, which is the order's own node. The same applies totags:customer > tagscomes before the order's owntags, so use>>tagsfor the order's tags. See path-syntax.md. - Custom attributes. Order-level
NoteAttributesand line-itemPropertiesboth becomecustomAttributeswithkey/valuepairs.NoteAttribute.<name>reads both shapes, so a configuration such asNoteAttribute.Gift messageneeds no change. A raw path such asNoteAttributes>Property>Valuedoes: switch it toNoteAttribute.<name>. When an order-level and a line-level attribute share a key, the order-level one is returned, because it comes first in the document. - Lines from sibling orders. With the Split Orders by Shopify
Fulfillments setting on, each Linnworks order carries the full Shopify
order data, so
lineItems>nodes>skumay return a line that belongs to another fulfillment. Check theremainingQuantityvalues underfulfillmentOrdersif that matters to you. - SKU and vendor. Both are blank at line level in the new shape. Paths
such as
LineItems>SkuandlineItems>nodes>skustill resolve, because XmlExtractor skips the empty node and finds the SKU undervariant, andLineItems>Vendorfindsproduct > vendorthe same way. To be explicit, uselineItems>nodes>variant>sku. - Money sets. Each money set lists
presentmentMoneybeforeshopMoney. A path that stops atamount, such astotalPriceSet>amount, returns the presentment amount. Name the side you want:totalPriceSet>shopMoney>amount. Number. The internal sequence number is gone. A configuration that extractedNumbernow receives the customer-facing order number, becauseNumbermatchesnumberignoring case. If you usedOrderNumber, switch tonumber.- Customer tags. Linnworks renders
customer > tagsempty in the new shape, soCustomer>Tagsfinds nothing on GraphQL orders. If you rely on it, ask Linnworks to include customer tags in the order XML. - Verify on a real order. Open the order's XML in Linnworks and
check the node names against your paths, or set
Troubleshoottotruefor one order and ask support to confirm the path. See Troubleshooting.
How to tell which shape an order has¶
- Support can see
Order XML format: Shopify GraphQLin the macro's log for each order in the new shape. - In the order's XML view in Linnworks, the new shape has
displayFinancialStatusand afulfillmentOrdersblock. Don't rely ongid://ids alone: Shopify REST payloads also carry them inadmin_graphql_api_idfields. - Linnworks' FAQ: if your Shopify integration settings show Split Orders by Shopify Fulfillments and Use Presentment Currency, the integration is on GraphQL.
Path examples, old and new¶
The REST names below match Linnworks' notice and a live rendering of a
REST-format order: Id, Name, FinancialStatus, LineItems,
ShippingLines, NoteAttributes. Take the exact old names from your own
configuration.
| You want | REST path | GraphQL path | Works on both |
|---|---|---|---|
| A checkout or line-item custom field | NoteAttribute.Gift wrap |
NoteAttribute.Gift wrap |
Yes |
| The first line's SKU | LineItems>Sku |
lineItems>nodes>variant>sku |
Yes. The line-level sku is blank in the new shape and skipped, so the old path reaches the variant's SKU |
| The currency | Currency |
currencyCode |
No. List both |
| The order number | OrderNumber |
number |
No. List both |
| The payment gateway | PaymentGatewayNames>string |
paymentGatewayNames |
No. List both |
| Marketing consent | BuyerAcceptsMarketing |
customerAcceptsMarketing |
No. List both |
| The order total | TotalPrice |
totalPriceSet>shopMoney>amount |
No. List both |
| The first line's product name | LineItems>Name |
lineItems>nodes>title |
No. name is blank in the new shape. List both |
| Payment status | FinancialStatus |
displayFinancialStatus |
No. List both: FinancialStatus, displayFinancialStatus |
| The order name | Name |
>>name |
No. List both |
| The Shopify order id | Id |
>>id |
No. List both |
| The shipping service code | ShippingLines>Code |
shippingLines>nodes>code |
Yes, thanks to the case fallback |
| A line price | Price |
lineItems>nodes>originalUnitPriceSet>shopMoney>amount |
No. List both |
| The order's tags | Tags |
>>tags |
Use >>tags on both. On the new shape a plain Tags can return the customer's tags instead, because customer > tags comes first in the document |
| The customer's tags | Customer>Tags |
Not available | Linnworks renders customer > tags empty in the new shape, on every order seen since the switch. Raise it with Linnworks if you need it |
Listing both paths in one configuration is safe. The one that doesn't exist
on an order logs Did not find value and nothing is written for it.