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, PaymentGatewayNames > string |
currencyCode, presentmentCurrencyCode, number, paymentGatewayNames |
| Renamed but empty | BuyerAcceptsMarketing, BrowserIp, OrderStatusUrl |
customerAcceptsMarketing, clientIp, statusPageUrl exist in the XML but Linnworks' query doesn't request them, so they're blank. See Waiting on Linnworks |
| 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 |
The SKU is at lineItems > nodes > sku in the query Linnworks shared on 17 September 2026; their earlier notice placed it under variant, which the query doesn't request. LineItems>Sku resolves either way, because XmlExtractor skips an empty node. The vendor isn't requested at all, so it's blank |
| 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.
LineItems>SkuandlineItems>nodes>skuboth resolve: the query Linnworks shared on 17 September 2026 requests the SKU at line level, and if a store still renders it undervariant, XmlExtractor skips the empty line-level node and reaches it there. The vendor isn't in the query, soLineItems>Vendorfinds nothing; see Waiting on Linnworks. - 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.- Fields the new XML doesn't carry.
Customer>Tags,Customer>Note,Customer>OrdersCount,BuyerAcceptsMarketing, transaction authorization codes, order-level tax lines and duties, and a few others find nothing on GraphQL orders, because Linnworks' query doesn't ask Shopify for them. No path fixes that. See Waiting on Linnworks. - 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>sku |
Yes, through the case fallback |
| 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' query doesn't request customer > tags, so the node is empty on every GraphQL order. See Waiting on Linnworks |
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.
Waiting on Linnworks¶
The GraphQL order XML lists every field of Shopify's order type, but only the fields Linnworks' query asks Shopify for carry a value. On 17 September 2026 Linnworks shared that query with us, with the note that "certain nodes and data are currently not included, but the team is actively looking into it". The fields below are in the XML as empty nodes, so any path that points at them finds nothing, on every version of XmlExtractor, until Linnworks adds them to the query. We have raised each one with Linnworks and will update this page when the query changes.
| What you extracted on REST | Where it would be on GraphQL | Status |
|---|---|---|
Customer>Tags |
customer > tags |
Not requested |
Customer>Note |
customer > note |
Not requested |
Customer>Email |
customer > email |
Not requested. The order's email is available |
Customer>OrdersCount |
customer > numberOfOrders |
Not requested |
BuyerAcceptsMarketing |
customerAcceptsMarketing |
Not requested, although Linnworks' notice lists it as a rename |
BrowserIp, OrderStatusUrl |
clientIp, statusPageUrl |
Not requested, although listed as renames |
UserId |
staffMember |
Not requested |
Transactions>Transaction>Authorization |
transactions > authorizationCode |
Not requested |
Transactions>Transaction>Receipt>... |
transactions > receiptJson |
Not requested |
TaxLines>TaxLine>Price |
order-level taxLines |
Not requested. Tax lines exist per line item, shipping line, and duty |
CurrentTotalDutiesSet, OriginalTotalDutiesSet |
the same names | Not requested. Duties exist per line item under lineItems > nodes > duties > price |
TotalPriceSet>PresentmentMoney>CurrencyCode |
currencyCode inside a money set |
Not requested. Use presentmentCurrencyCode or currencyCode at order level |
SubtotalPrice, TotalTax, TotalShippingPrice, TotalDiscounts |
subtotalPriceSet, totalTaxSet, totalShippingPriceSet, totalDiscountsSet |
Not requested. Only totalPriceSet is |
DiscountCodes |
discountCodes |
Not requested. discountApplications>nodes>code carries the code that was applied |
LineItems>LineItem>Vendor |
lineItems > nodes > product > vendor |
Not requested |
LineItems>LineItem>Name |
lineItems > nodes > name |
Not requested. Use title |
Phone |
order-level phone |
Not requested. The shipping and billing addresses carry phone |
Two more limits of the query are worth knowing. It fetches the first 5 line items, 3 shipping lines, 3 fulfillment orders, 3 discount applications, and 5 metafields of an order; whether Linnworks fetches the following pages into the XML is a question we have put to them. And metafields, risk assessments, transactions, and refunds are optional blocks that Linnworks switches on per request; the orders we've seen include all but refunds.
If one of these fields matters to your workflow, tell Linnworks support which one, and tell us at support: the more merchants ask for a field, the sooner it's added.