Shopify connector: what it reads, what it changes, and how to set it up
This page is for the Shopify store owner or the IT person who will bind a store to OrgRelay. After reading it you will know how to create the app, which scopes to grant, what each of the nine tools does, and what an approver sees before a price, stock or cancellation change reaches Shopify.
The connector talks to one store through the GraphQL Admin API. It does not use the REST Admin API. Every call is a POST to /admin/api/<version>/graphql.json with an access token in the X-Shopify-Access-Token header. The connector spec explains how connectors plug into OrgRelay in general.
What staff can ask
Typical questions, and the tool each one triggers:
- "Show me unfulfilled orders from last week." This calls
orders.searchwithstatus: unfulfilledand a date range. Results come back newest first. - "What did #1042 contain, and where is it shipping?" This calls
orders.getwithorder_no: 1042. The connector adds the#if it is missing, because Shopify order names look like#1042. - "Which SKUs are under ten units?" This calls
inventory.listwithlow_only: true. - "We received 24 more of TEE-BLK-M at the Leeds warehouse." This calls
inventory.adjustwithdelta: 24,reason: receivedand that warehouse'slocation_id, behind an approval. - "Cancel #1050, the customer changed their mind, refund it." This calls
orders.cancelwithreason: CUSTOMERandrefund: true, again behind an approval.
The tool names follow the shared domain vocabulary described in standard tools. The WooCommerce connector and the Amazon SP-API connector use the same names. A question about "orders" works the same way whichever store a department is granted.
Tools
| Tool | Access | What it does | Key parameters |
|---|---|---|---|
orders.search |
read | Lists orders, newest first | status (open, closed, cancelled, paid, unfulfilled, fulfilled), customer, date_from, date_to, query (raw Shopify search syntax), limit, cursor |
orders.get |
read | One order by name, with up to 50 line items, shipping city and country, and the order note | order_no |
products.search |
read | Searches product variants; returns SKU, title, price, status and quantity | keyword (passed to Shopify as the variant search query), limit, cursor |
inventory.list |
read | Variant quantities by SKU | sku, low_only (quantity under 10), limit, cursor |
customers.search |
read | Customers with email, country, order count and amount spent | keyword, limit, cursor |
reports.sales_summary |
read | Order count and sales total for a date range, up to 1,000 orders | date_from, date_to (both required) |
products.update_price |
write · approval | Sets the price of the variant that matches a SKU | sku, price |
inventory.adjust |
write · approval | Adds or removes available units at the primary location or a named one | sku, delta, reason (correction, cycle_count_available, damaged, received, restock), location_id |
orders.cancel |
write · approval | Cancels an order, with optional refund and restock | order_no, reason (CUSTOMER, INVENTORY, FRAUD, DECLINED, OTHER), refund, restock |
Behaviours worth knowing before you rely on the numbers:
- Paging uses Shopify's cursor.
limitdefaults to 20 and caps at 100. The connector returnsnext_cursorfrompageInfo.endCursor. status: paidbecomesfinancial_status:paid, the two fulfilment values becomefulfillment_status:..., and the rest becomestatus:...in the search string. Anything inqueryis passed through as written.inventory.listreports the variant'sinventoryQuantity, the total across locations.on_handandavailableshow the same figure.reports.sales_summaryskips cancelled orders. If the period holds more than 1,000 orders, the result carriestruncated: true, the number of orders counted and a notice to shorten the range.
Credentials and scopes
Shopify gives you two kinds of app, and the connector accepts both.
Dev Dashboard app. Since 1 January 2026 this is the only way to create a new app. You enter the shop domain (your-store.myshopify.com), the client ID and the client secret. OrgRelay requests an access token with the client credentials grant. Shopify returns expires_in of 86399 seconds, about 24 hours. OrgRelay keeps the token in memory, gets a new one five minutes before it expires, and asks again if Shopify rejects a call with 401. The app and the store must belong to the same Shopify organization. Client ID and secret support requires OrgRelay 1.4.0 or later.
Legacy custom app. An app created in the store admin before 2026 keeps working. Enter the shop domain and its Admin API access token, which starts with shpat_. That token does not expire. It is shown once and cannot be rotated; to replace it you uninstall and reinstall the app.
Two advanced fields are normally left alone: an API base URL and the API version, which defaults to 2026-10.
Scopes for read-only use: read_orders, read_products, read_inventory, read_locations and read_customers. To allow the three write tools, add write_orders, write_products and write_inventory. Shopify's access scopes reference lists the Location object under read_locations, and inventory.adjust reads a location before it writes. If a scope is missing, the connector reports Shopify's access-denied message and names the scope to add. An existing legacy app needs read_locations added too.
Two more Shopify rules affect what you see. Without read_all_orders, an app only sees orders from the last 60 days. Customer names and emails are protected customer data, and Shopify leaves them out until the app has requested that access in its API settings.
OrgRelay keeps the secret and any token encrypted and shows only the last four characters; the auth page explains how credentials are stored.
Which actions need approval
All three write tools create an approval request. Nothing reaches Shopify until the owner or a designated approver accepts it. The request shows the tool and its arguments, so the approver reads exactly what will be sent:
- Price change: the SKU and the new price. The connector finds the first variant whose SKU matches and updates it with
productVariantsBulkUpdate. - Stock adjustment: the SKU, the signed
delta, the reason (defaultcorrection) and, if given, thelocation_id. Without one, the change goes to the store's primary location; the result names the location used. On API version 2026-04 and later, if the SKU is not stocked at that location, the call stops with an error. - Cancellation: the order name, the reason (default
OTHER), and therefundandrestockflags. Read these flags carefully.refunddefaults to false.restockdefaults to true unless the request sets it to false. The connector always sendsnotifyCustomer: false, so Shopify does not email the customer.
Each approved call carries the idempotency key orgrelay-approval-<approval id>. For stock adjustments on API version 2026-04 and later, the connector passes that key to Shopify through the @idempotent directive and also sends changeFromQuantity, the available quantity it read just before writing. Shopify's inventoryAdjustQuantities reference states that from 2026-04 the idempotency key is required. With both values set, a retried approval does not apply twice, and the change is refused if someone else moved the stock in between. How approvals, rejections and expiries work in general is covered in approvals and writes, and the reasoning behind keeping a person in the loop is on human in the loop.
Set it up
- Sign in to the Shopify Dev Dashboard as the store owner and click Create app. Name it OrgRelay.
- In the app's Versions, choose the Admin API scopes listed above. Release the version and install the app on your store.
- If you need orders older than 60 days, request
read_all_orders. If staff should see customer names and emails, request protected customer data access in the app's API access settings. - Open the app's Settings and copy the client ID and client secret.
- In OrgRelay, open Admin → Business systems → App directory, pick Shopify, enter the shop domain, client ID and client secret, and click Connect. OrgRelay runs
{ shop { name } }and shows the store name and myshopify domain. For a legacy custom app, enter theshpat_token instead of the client ID and secret. - Grant the connector to the roles that need it, for example store operations and customer service. Switch off any tool a role should not have, such as
orders.cancelfor support staff.
If you are building or reviewing connectors yourself, the quickstart and the connector check show how a connector is checked before it is bound.
Limits and things it does not do
Shopify throttles the GraphQL Admin API by calculated query cost, not by request count. The rate limit page lists restore rates of 100 points per second on Standard, 200 on Advanced, 1,000 on Plus and 2,000 on Commerce Components, and a hard cap of 1,000 points for any single query. When Shopify answers with a THROTTLED error, the connector waits 10 seconds before OrgRelay retries. OrgRelay adds its own guards on top: at most 120 calls per minute per connection, and a 60-second pause after three failures in a row.
The connector pins API version 2026-10. Shopify supports each stable version for at least 12 months and then falls forward to the oldest supported one. If you lower the version in the advanced field below 2026-04, stock adjustments are sent without the idempotency key.
Things it deliberately leaves out:
- No refunds outside a cancellation, no fulfilment creation, no editing of addresses or line items.
- No product creation or deletion, and no changes to descriptions, images or tags.
- No street address, phone number or payment details in
orders.get. Only city and country are returned. - No metafields, discounts, gift cards or B2B company data.
The AI sees about 12,000 characters of any result, so ask for filtered lists rather than whole catalogues. Development stores made from the Dev Dashboard are free and are a safe place to try the write tools first.
Official MCP server and OrgRelay
Shopify publishes the Dev MCP server (@shopify/dev-mcp) as part of its AI Toolkit. It runs locally, needs no authentication, and helps a coding assistant search Shopify's documentation, explore the Admin API schema and check GraphQL. Store management in the toolkit goes through the Shopify CLI. If your developers use Claude Code or Cursor, the Dev MCP server is a good companion while building; see Claude Code and Cursor.
OrgRelay can attach a vendor MCP server directly as a third-party MCP connection when the server is reachable over HTTP with a token. Servers that only run over stdio, or that need an interactive OAuth sign-in with PKCE, cannot be connected that way. What OrgRelay adds is the layer a company needs when many staff share one store: per-role access, an approval before every write, one audit log across Shopify, your accounting system and your helpdesk, and all of it running on the company's own machine. The MCP enterprise patterns page compares the approaches, and official MCP servers lists what other vendors ship. For the business view of ecommerce teams using OrgRelay, see OrgRelay for ecommerce.
If you run a custom app or a Shopify Function of your own, you can expose it too, either through the GraphQL import or as your own server over the MCP transport.
Common questions
Should we use a Dev Dashboard app or our old custom app?
Either works. A Dev Dashboard app is connected with its client ID and secret, and OrgRelay exchanges them for a 24-hour access token and renews it on its own. An admin-created custom app from before 2026 is connected with its shpat_ token, which does not expire. Shopify no longer lets you create new apps in the admin, so new stores use the Dev Dashboard.
Why does the sales summary not match the Shopify Analytics report?
reports.sales_summary adds up totalPriceSet on non-cancelled orders and counts at most 1,000 orders. When a period has more, the result says truncated and tells you to split the range. Shopify Analytics also applies its own rules for returns, taxes and discounts, so use the tool for quick checks, not for closing the books.
Which location does inventory.adjust change?
The store's primary location unless the request names a location_id. Shopify's reference for the location query says that without an ID it returns the shop's primary location, which is the default set under Settings → Locations. Pass a location_id (gid://shopify/Location/…) to adjust a different warehouse.
Related
- All connectors
- Stripe connector for payments and refunds behind the same store
- Standard tools
- Approvals and writes
- Security model