Orders and customers
Stored orders by name or id, and what is stored for one email address.
/ordersRequires context:read. tRPC context.order.get, MCP get_order.
Reads one order a store lookup has already stored, without contacting the store. An order known only from the orders sync is not returned. Send exactly one of orderName or orderId, and storeConnectionId when your organization has more than one store; otherwise the answer is 400.
orderId matches only the id form a store lookup stores, gid://shopify/Order/1000000001. The numeric orderId on a ticket or in a customer's synced orders matches nothing: send orderName, or put gid://shopify/Order/ in front of the number.
An order read here names no customer, so it is always unverified: no tracking, no estimated delivery and no total. Read it through its ticket to see those.
Returns null when the store is readable but has no stored order with that name or id; a refresh of a ticket that mentions it may store it. A 404 means your organization has no enabled store, no store with that storeConnectionId, or the store is outside your connection access.
Authorization
apiKey In: header
Query Parameters
The order name, such as #1001. Case-insensitive. Send this or orderId.
1 <= length <= 128The order id as a store lookup stored it, such as gid://shopify/Order/1000000001, matched exactly. The numeric orderId on a ticket or a synced order matches nothing: send orderName, or put gid://shopify/Order/ in front of the number. Send this or orderName.
1 <= length <= 128The store to read. Required when your organization has more than one store.
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$uuidResponse Body
application/json
application/json
application/json
application/json
application/json
application/json
curl -X GET "https://example.com/orders"{ "storeConnectionId": "ccc7195b-c21e-4828-b08b-76e1da7e2a61", "orderId": "string", "orderName": "string", "association": "mentioned", "customerMatch": "email_match", "verification": { "state": "verified", "source": "email_match", "checkedAt": "string" }, "createdAt": "string", "cancelledAt": "string", "financialStatus": "string", "fulfillmentStatus": "string", "fetchedAt": "string", "total": { "amount": "string", "currency": "string" }, "items": [ { "itemId": "string", "title": "string", "variantTitle": "string", "sku": "string", "quantity": 0, "unfulfilledQuantity": 0, "free": true, "discounts": [ { "kind": "code", "name": "string" } ] } ], "fulfillments": [ { "fulfillmentId": "string", "status": "string", "displayStatus": "string", "deliveredAt": "string", "estimatedDeliveryAt": "string", "tracking": [ { "company": "string", "number": "string", "url": "string" } ] } ]}/orders/lookupRequires context:lookup on an API key, which context:read does not include; a sign-in session or an MCP sign-in is refused with 403. tRPC context.order.lookup (a mutation). No MCP tool. Only owners and admins can add context:lookup to a key; the Order lookup preset holds it alone. Keep the key on your server, never in an app.
For a store's own app: send the email a shopper placed an order with and its order name. When both match, the answer is the order's status, shipments with tracking, estimated delivery and latest update, and items. Never a total, a price, an address or the shopper's details. Reads stored data only and never calls the store.
orderNumberis an order name: letters, digits and# _ . / -, single spaces between parts, at least one digit. Anything else, such as an email typed into it, is a400. It matches the order name exactly, with ASCII letters in any case. Without a leading#it also tries#in front, so10482finds#10482. It never matches the order number alone.verifiedlists every matching order in the stores the key reaches. A cancelled or refunded order is verified too, with its status.no_matchis the one answer for a wrong email, an unknown or test order, and an order outside the key's stores.unavailablemeans no store the key reaches may have its order emails read now. Try again later.shippingReadAtis null until EcomSquad has read the order's shipping. A match asks for that read; the next scheduled one, normally within 30 minutes, fills it in.429after 5 failed lookups for one email or one order name, or 200 through one key, in the 24 hours before the call. A matched lookup counts toward none. A429also answers a call that waited more than a second behind your organization's other lookups. Limit each shopper on your side too.
A 400 never repeats what was sent, and no log line holds the email or the order number.
Authorization
apiKey In: header
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/orders/lookup" \ -H "Content-Type: application/json" \ -d '{ "email": "string", "orderNumber": "string" }'{ "result": "verified", "orders": [ { "storeConnectionId": "string", "orderName": "string", "createdAt": "string", "cancelledAt": "string", "financialStatus": "string", "fulfillmentStatus": "string", "checkedAt": "string", "shippingReadAt": "string", "fulfillments": [ { "displayStatus": "string", "deliveredAt": "string", "estimatedDeliveryAt": "string", "estimatedDeliveryText": "string", "latestUpdate": { "status": "string", "at": "string" }, "tracking": [ { "company": "string", "number": "string", "url": "string" } ] } ], "items": [ { "title": "string", "variantTitle": "string", "quantity": 0 } ] } ]}/orders/lookup-by-emailRequires context:lookupByEmail on an API key. context:lookup and context:read do not include it, and a sign-in session or an MCP sign-in is refused with 403. tRPC context.order.lookupByEmail (a mutation). No MCP tool. Only owners and admins can add context:lookupByEmail to a key. Keep the key on your server, never in an app.
For a store's own app whose server has verified that the shopper owns the email, for example through a sign-in provider. Sending the email vouches for that: anyone holding the key can read the orders of any email it sends. The answer is the order lookup's view of each order: status, shipments with tracking, estimated delivery and latest update, and items. Never a total, a price, an address or the shopper's details. Reads stored data only and never calls the store.
- A store answers only once EcomSquad has switched it on for lookups by email.
verifiedlists the newest non-test orders placed with the email in the 90 days before the call, newest first, at most 5. A cancelled or refunded order is listed too, with its status.no_matchmeans no such order. Ask for the order number and usePOST /orders/lookup.unavailablemeans no store the key reaches is switched on with its order emails caught up. Ask for the order number; that lookup says whether it can answer.- An order placed in the last few minutes may not be stored yet.
shippingReadAtis null until EcomSquad has read the order's shipping. A match asks for that read; the next scheduled one, normally within 30 minutes, fills it in.429after 20 calls through your key for one email, or once your key has looked up 300 different emails, in the 24 hours before the call, matched or not. Keep the answer for the shopper's session rather than calling on every screen. Repeating an email the key already looked up does not count toward the 300. A429also answers a call that waited more than a second behind your organization's other lookups by email.
A 400 never repeats what was sent, and no log line holds the email.
Authorization
apiKey In: header
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/orders/lookup-by-email" \ -H "Content-Type: application/json" \ -d '{ "email": "string" }'{ "result": "verified", "orders": [ { "storeConnectionId": "string", "orderName": "string", "createdAt": "string", "cancelledAt": "string", "financialStatus": "string", "fulfillmentStatus": "string", "checkedAt": "string", "shippingReadAt": "string", "fulfillments": [ { "displayStatus": "string", "deliveredAt": "string", "estimatedDeliveryAt": "string", "estimatedDeliveryText": "string", "latestUpdate": { "status": "string", "at": "string" }, "tracking": [ { "company": "string", "number": "string", "url": "string" } ] } ], "items": [ { "title": "string", "variantTitle": "string", "quantity": 0 } ] } ]}/customers/orders/searchRequires context:read, with the same organization and connection access as get_customer. tRPC context.customer.findOrders (mutation), MCP find_customer_orders. Live Shopify search through the flexible query job; no results are stored. Send name (at least 3 letters) and/or phone (6 to 15 digits), optionally ticketId to compare with a readable ticket's sender. Phone-looking names use the phone filter. Returns matches first, at most five newest orders, all unverified, with products/variants, statuses and Shopify admin links. orderEmail is sender, different or unknown, never an address; note is set only for different. multipleCustomers flags several matching customer records. For the support person only: do not quote results to the customer until confirmed. Provider search semantics determine candidates; a local case/accent-insensitive name check removes non-name hits. A 502 means the search failed; no partial matches are returned. No store or customer data is changed.
Authorization
apiKey In: header
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/customers/orders/search" \ -H "Content-Type: application/json" \ -d '{}'{ "matches": [ { "orderName": "string", "createdAt": "2019-08-24T14:15:22Z", "storeConnectionId": "ccc7195b-c21e-4828-b08b-76e1da7e2a61", "financialStatus": "string", "fulfillmentStatus": "string", "items": [ { "title": "string", "variantTitle": "string" } ], "itemsTruncated": true, "shopifyUrl": "http://example.com", "matchedBy": "name", "verification": "unverified", "orderEmail": "sender", "note": "string" } ], "multipleCustomers": true}/customersRequires context:read. tRPC context.customer.get, MCP get_customer.
Reads what is stored for one email address, without contacting the store. Addresses match after trimming, and lowercasing when the address is all ASCII: dots and +tags are not folded, and an order with no order email belongs to no one. It never returns other emails: asking for an address a second check recorded answers as for any address.
storeCustomer.orders is a lifetime count, orders covers each store's synced history and matchedOrders what the store's order lookup by the email returned, so the three can differ. This is a view of an email address, not evidence about who sent a message: a reply to a sender may use tracking only from a ticket's verified orders.
An address with no conversations or synced orders you may read returns zero counts and empty lists, not an error.
Authorization
apiKey In: header
Query Parameters
The customer's email address.
^(?:[A-Za-z0-9_'+\-]+\.)*[A-Za-z0-9_'+\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$emailResponse Body
application/json
application/json
application/json
application/json
application/json
curl -X GET "https://example.com/customers?email=user%40example.com"{ "email": "string", "name": "string", "conversations": 0, "storeCustomer": { "name": "string", "customerSince": "string", "orders": 0, "amountSpent": "string", "currency": "string", "countryCode": "string", "checkedAt": "string" }, "matchedOrders": [ { "storeConnectionId": "ccc7195b-c21e-4828-b08b-76e1da7e2a61", "orderId": "string", "orderName": "string", "association": "mentioned", "customerMatch": "email_match", "verification": { "state": "verified", "source": "email_match", "checkedAt": "string" }, "createdAt": "string", "cancelledAt": "string", "financialStatus": "string", "fulfillmentStatus": "string", "fetchedAt": "string", "total": { "amount": "string", "currency": "string" }, "items": [ { "itemId": "string", "title": "string", "variantTitle": "string", "sku": "string", "quantity": 0, "unfulfilledQuantity": 0, "free": true, "discounts": [ { "kind": "code", "name": "string" } ] } ], "fulfillments": [ { "fulfillmentId": "string", "status": "string", "displayStatus": "string", "deliveredAt": "string", "estimatedDeliveryAt": "string", "tracking": [ { "company": "string", "number": "string", "url": "string" } ] } ] } ], "omittedForAccess": 0, "matchedOrdersOmitted": 0, "orders": [ { "storeConnectionId": "ccc7195b-c21e-4828-b08b-76e1da7e2a61", "orderId": "string", "orderName": "string", "createdAt": "string", "financialStatus": "string", "fulfillmentStatus": "string", "cancelledAt": "string", "total": { "amount": "string", "currency": "string" }, "items": [ { "title": "string", "variantTitle": "string", "sku": "string", "quantity": 0 } ] } ], "ordersOmitted": 0, "ordersSince": [ { "storeConnectionId": "ccc7195b-c21e-4828-b08b-76e1da7e2a61", "label": "string", "ordersSince": "string" } ], "totalSpend": [ { "currency": "string", "amount": "string" } ]}The email the order was placed with, as the shopper typed it.
1 <= length <= 320The order name, such as #10482: letters, digits and # _ . / -, single spaces between parts, at least one digit. Without a leading # it also tries #10482; it never matches the order number alone.
^(?=.*[0-9])[A-Za-z0-9#_./-]+(?: [A-Za-z0-9#_./-]+)*$1 <= length <= 32The shopper's email, which your server has verified they own. Sending it vouches for that.
1 <= length <= 320Full or partial customer name, at least 3 letters. A phone-looking value is treated as a phone filter.
length <= 128At least 6 phone digits, with optional spaces, parentheses, + or hyphens. Use the country code when known.
length <= 32A readable ticket to compare the order email with its sender. Without it the relation is unknown.
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$uuid