Order MCP
The Order MCP server enables AI agents to fetch the current state of an order placed through their agent, including line items, fulfillment events, and post-purchase adjustments.
Anchor to How it worksHow it works
Order MCP implements the UCP order capability (dev.ucp.shopping.order, version 2026-04-08). The capability exposes a single tool, get_order, which returns the full current state of an order.
For background, see About orders. For the canonical specification, see the Order capability and the Order MCP binding.
Use webhooks as the primary update channel. Webhooks deliver the full current order state whenever a committed change occurs. Use get_order for buyer-initiated views, reconciling dropped webhook deliveries, or any case where you need fresh state on demand. Don't poll get_order on a schedule. Subscribe to Order webhooks instead.
Use webhooks as the primary update channel. Webhooks deliver the full current order state whenever a committed change occurs. Use get_order for buyer-initiated views, reconciling dropped webhook deliveries, or any case where you need fresh state on demand. Don't poll get_order on a schedule. Subscribe to Order webhooks instead.
Anchor to Use with the AI ToolkitUse with the AI Toolkit
The Shopify AI Toolkit installs the ucp skill, which lets agents in Cursor, Claude Code, and other compatible IDEs call Order MCP by name. Ask your assistant in natural language ("track order <id> from <shop>") and the skill picks the right UCP CLI command, or run ucp order get directly in a terminal. Pair either mode with the order webhooks delivered to your endpoint to keep your local view in sync.
Use --view and --format md to project the response for the buyer; use --format json to feed it back into your agent loop.
Fetch order state
ucp order get gid://shopify/Order/789 \
--business https://{shop}.example.comBuyer-facing summary
ucp order get gid://shopify/Order/789 \
--business https://{shop}.example.com \
--view 'result.{id: id, status: financial_status, fulfillment: fulfillment_status, total: totals[-1].amount}' \
--format mdAnchor to Rate limitsRate limits
Order MCP is available only to Token-tier agents. get_order requires a Global API JWT with the read_global_api_orders scope, which Signed-tier and Anonymous-tier agents can't obtain. The agent profile must also declare dev.ucp.shopping.order for the tool to appear on the negotiated session.
Webhooks remain the primary update channel for the order capability. Reserve get_order for buyer-initiated reads and reconciliation. When the server rate-limits a request, retry after the delay specified by the HTTP Retry-After response header and apply exponential backoff with jitter.
For tier definitions, capability matrices, and the full guidance, see Auth and rate limiting.
| Use case | Recommended surface |
|---|---|
| Proactive notifications and timeline UIs | Order webhooks |
| Buyer-initiated "Where's my order?" views | get_order |
| Reconciling missed webhook deliveries | get_order |
| Scheduled polling | Not recommended. Process incoming order webhook deliveries instead. |
Anchor to AuthenticateAuthenticate
Order MCP requests require a Global API JWT with the read_global_api_orders scope. Obtain your client credentials from the Catalog section of Dev Dashboard and exchange them for a token.
The response contains:
access_token: A JWT used in theAuthorization: Bearer {token}header on subsequent requests.scope: The list of access scopes granted to the token.expires_in: The number of seconds until the access token expires.
Access tokens have a 60-minute TTL. Mint a fresh token rather than reusing one across long-lived sessions. You can only fetch orders that were placed through your agent.
For details on traffic tiers and what each can do, see Auth and rate limiting.
https://api.shopify.com/auth/access_token
{} Response
Anchor to Make requestsMake requests
Order MCP shares the merchant's UCP MCP endpoint with Cart MCP and Checkout MCP. Send POST requests to https://{shop-domain}/api/ucp/mcp using the JSON-RPC 2.0 protocol.
Every request must include a meta object in arguments. Include meta["ucp-agent"] with a profile URI (your agent's UCP profile at /.well-known/ucp) for capability negotiation.
The order is returned in result.structuredContent. The result.content array also includes a stringified text representation of the order.
For testing, you can reference Shopify's hosted profile fixture at https://shopify.dev/ucp/agent-profiles/2026-04-08/valid-with-capabilities.json, which already declares the order capability.
https://{shop-domain}/api/ucp/mcp
Anchor to Order toolsOrder tools
Tool use is subject to access and rate limiting that scale with how your agent identifies itself. See Auth and rate limiting for traffic tiers and what each can do.
Tool use is subject to access and rate limiting that scale with how your agent identifies itself. See Auth and rate limiting for traffic tiers and what each can do.
Order MCP provides one tool for retrieving the current state of an order.
get_order: Fetch the current state of an order placed through your agent.
Anchor to [object Object]get_order
get_orderReturns the current-state snapshot of an order placed through your agent.
The order ID must be a Shopify Global ID returned by complete_checkout on a checkout your agent originated. Orders placed through other apps or directly on the merchant's storefront aren't accessible, and get_order can't look up cross-channel buyer order history. Buyer identity linking isn't supported in v1.
Allow propagation time after complete_checkout. After complete_checkout returns, allow about 10 seconds before calling get_order for the first time. The order needs time to propagate to the order service.
Allow propagation time after complete_checkout. After complete_checkout returns, allow about 10 seconds before calling get_order for the first time. The order needs time to propagate to the order service.
When to use:
- The buyer asks "Where's my order?" or "What's the status of order #1042?"
- You need to reconcile state after a missed webhook delivery.
- You need fresh data on demand for a buyer-facing UI.
Anchor to ParametersParameters
Request metadata. You're required to include ucp-agent.profile, the URI of your agent's UCP profile for capability negotiation. The profile must declare dev.ucp.shopping.order for get_order to be available in the negotiated session.
The Shopify Global ID of the order. Format: gid://shopify/Order/{id}.
Anchor to Call from the Shopify AI Toolkit and UCP CLICall from the Shopify AI Toolkit and UCP CLI
With the Shopify AI Toolkit installed, ask your assistant in natural language ("where's my order from <shop>?") and the ucp skill picks the right UCP CLI command. You can also run the command directly in a terminal:
Fetch order state
Anchor to Call the tool directlyCall the tool directly
https://{shop-domain}/api/ucp/mcp
{} Response
Anchor to Order data modelOrder data model
An order is the full state of a buyer's purchase after checkout completes. Both get_order and order webhooks return the same shape: a top-level envelope with four nested structures (totals, line_items, fulfillment, and adjustments).
The payload reflects current state at the time of the request or delivery. Shopify doesn't expose historical snapshots. To track changes over time, store webhook deliveries.
Monetary values are signed integers in the order's presentment currency, expressed in minor units. $10.00 USD is 1000. Negative values are reductions (refunds, discounts). Positive values are additions.
Example order
Anchor to Top-level fieldsTop-level fields
Every order payload starts with the same envelope: identifiers (id, label, checkout_id), the public permalink_url, the presentment currency, and four nested structures (totals, line_items, fulfillment, adjustments) that carry the rest of the state.
| Field | Type | Description |
|---|---|---|
ucp | object | The UCP envelope carries the negotiated version and capabilities map for this response. |
id | string | The order's Shopify Global ID is formatted as gid://shopify/Order/{numeric_id}. Use it as your storage key, not as a buyer-facing label. |
label | string | The buyer-facing identifier defaults to the order name (for example, #1042). Shops with use_confirmation_number_on_buyer_facing_communication enabled send a confirmation number instead. |
checkout_id | string | The Shopify Global ID of the originating checkout. The value includes a ?key=… parameter when a confirmation receipt URL has been issued. |
permalink_url | string | The merchant's unauthenticated public order status page. It renders a limited buyer-facing view without PII and is the authoritative reference for refund initiation, returns, and the detailed timeline. |
currency | string | The presentment currency, expressed as an ISO 4217 code. The currency matches the originating checkout. |
totals | array | The order's money breakdown as an array of typed rows. See Totals. |
line_items | array | The items the buyer purchased, including any later removed by an order edit. See Line items. |
fulfillment | object | The buyer-facing expectations and the event log for the order. See Fulfillment. |
adjustments | array | The committed post-purchase changes to the order. See Adjustments. |
Anchor to TotalsTotals
totals is an array of typed money rows that mirrors the merchant's checkout breakdown. The same structure also appears on each line item under line_items[].totals.
Each row carries a display_text field that currently mirrors the raw type. Don't render it directly to buyers. Map types to your own localized labels.
type | Sign | When present |
|---|---|---|
items_discount | ≤ 0 | Shopify includes this row when one or more lines have a line-level discount. It appears at both the order and line level. |
subtotal | ≥ 0 | This row is always present at both the order and line level. Its value is the sum of pre-tax line totals after item discounts. |
discount | ≤ 0 | Shopify includes this row at the order level when an order-level or cart-level discount is applied (for example, a promo code or automatic discount). |
fulfillment | ≥ 0 | This row captures shipping or fulfillment fees. It's always present at the order level. |
tax | ≥ 0 | This row is present at both the order and line level for tax-exclusive orders. It's omitted everywhere for tax-inclusive orders, so treat its absence as a signal that prices already include tax. |
fee | ≥ 0 | This row captures additional fees, such as marketplace or platform fees. It's always present at the order level. |
total | signed | This row is the grand total at the order level and the all-in total at the line level. It's always present. |
Anchor to Line itemsLine items
Each line item represents one product variant in the order.
Compare quantity.original, quantity.total, and quantity.fulfilled to render edit history, current state, and shipping progress.
Removed items stay in the array with quantity.total: 0 and status: "removed" so timeline UIs can show the full edit history.
| Field | Type | Description |
|---|---|---|
id | string | The line item's Shopify Global ID. The ID is stable across the order's lifetime, so use it as the correlation key across deliveries. |
item.id | string | The product variant's Shopify Global ID. |
item.title | string | The variant's display title, for example Large / Black. |
item.price | integer | The unit price of the variant at purchase, expressed in minor units of the order's currency. |
item.image_url | string or null | The URL of the variant's product image on Shopify's CDN. The value is null when no image is available. |
quantity.original | integer | The quantity the buyer ordered at checkout. This value never changes after the order is placed. |
quantity.total | integer | The current active quantity for this line, after any post-purchase order edits. |
quantity.fulfilled | integer | The quantity of this line that has shipped or otherwise been fulfilled so far. |
totals | array | The per-line money breakdown, using the same row taxonomy as Totals. |
status | string | A derived rollup of the line's fulfillment progress. Treat the value as an open string.
|
parent_id | string or null | The line item GID of this line's parent, when the line is part of a nested structure such as a bundle or component. The value is null for top-level lines. |
Anchor to FulfillmentFulfillment
fulfillment has two parts:
expectations: Describes where items go and what's in each package. Render it as the destination card on an order page.events: A timeline of fulfillment milestones. Replay it for "Where's my order?" UIs.
| Field | Type | Description |
|---|---|---|
expectations | array | A list of buyer-facing groupings, one per package. Shopify currently emits a single synthetic expectation when the order has a shipping address. Orders without a shipping address (digital-only, in-store pickup) emit an empty array. The canonical UCP specification permits multiple expectations with splits, merges, per-item dates, and fulfillable_on. Shopify doesn't emit those today. |
events | array | A log of fulfillment milestones, sorted by occurred_at. Treat each event's type as an open string.The spec allows new values without a breaking change, and internal merchant-only statuses (label printing, fulfillment failures) aren't exposed. The values Shopify currently emits, grouped by category: Creation
|
Anchor to AdjustmentsAdjustments
Adjustments capture committed post-purchase changes (refunds, returns, exchanges, edits, cancellations).
Only finalized actions appear. Intermediate states, like a requested-but-unprocessed return, stay out of the array until they complete. The original sale or capture from the checkout is filtered out, so you'll see only post-purchase money movements.
For precise timing, the permalink_url is the authoritative source.
| Field | Type | Description |
|---|---|---|
id | string | The Shopify Global ID of the underlying sales agreement or transaction. The ID is stable across deliveries, so use it as the deduplication key. |
type | string | The kind of adjustment, expressed as an open string. The values Shopify currently emits:
|
occurred_at | string | The RFC 3339 timestamp at which the adjustment was committed. |
status | string | The adjustment's lifecycle state. The value is always "completed" today. The schema permits "pending" and "failed", but Shopify only emits adjustments after they finalize. |
totals | array | A single-row array with one total entry carrying a signed amount. A negative amount means money is flowing back to the buyer. A positive amount means net money is owed (for example, an exchange to a more expensive item). |
description | string or null | Reserved for a future human-readable description. The value is always null in v1. |
line_items | array | The line items affected by the adjustment, each with a signed quantity. The array may be empty for adjustments not tied to specific lines (for example, standalone payment-only transactions). |
Anchor to Error handlingError handling
UCP distinguishes between protocol errors and business outcomes.
- Business outcomes: Application-level results from successful request processing, returned as JSON-RPC
resultwith the UCP envelope and amessagesarray. - Protocol errors: Transport-level failures (authentication, rate limiting, unavailability) that prevent request processing. Returned as JSON-RPC
errorwith code-32000, or-32001for discovery errors.
See the Cart MCP binding, the Checkout MCP binding, and Core Specification error handling for the complete error code registry and examples.
Anchor to Protocol errorsProtocol errors
Transport-level failures that prevent the request from being processed (for example authentication failure, rate limiting, or service unavailability) are returned as JSON-RPC error with code -32000, or -32001 for discovery errors. These are not application outcomes: the server did not complete the operation.
When the server rate-limits your request, retry after the delay specified by the HTTP Retry-After response header. Clients should honor Retry-After and apply exponential backoff with jitter when the header is absent. Don't retry inside the same checkout or payment lifecycle without an idempotency-key.
Protocol error (JSON-RPC error)
Anchor to Order error codesOrder error codes
When get_order can't return an order, the response sets result.isError to true and includes a messages array on result.structuredContent. Always check messages before reading order fields. The codes below diverge in name from the canonical UCP specification's not_found and unauthorized, but carry equivalent semantics.
| Code | Severity | Cause |
|---|---|---|
invalid_order_id | recoverable | The id argument isn't a valid Shopify Order GID. Reformat and retry. |
order_not_found | unrecoverable | The order doesn't exist or wasn't placed through your agent. Don't retry. |
orders_not_allowed | unrecoverable | The token is missing the read_global_api_orders scope. Mint a new token with the correct scope. |
A request for an order that doesn't exist or wasn't placed through the requesting agent returns order_not_found. Immediately after complete_checkout, this can also surface transiently while the order propagates. If you're calling get_order right after checkout completes, wait a few seconds and retry.