@shopify/shop
v1.2.0
Published
Shop for agents: product discovery, checkout, and Shop order tracking across millions of stores
Keywords
Readme
shop
shop lets agents search millions of stores, build carts, check out and pay with the shopper's Shop account, and track orders. When a store has no agent checkout, the shopper can approve a purchase on Shop and the agent gets a one-time credential to pay at the site's own checkout.
Contents
- Install
- Search for products
- Sign in for personalization and accelerated checkout
- Read the shopper's addresses and payment methods
- Create a pre-filled checkout
- Complete the checkout
- Track the order
- Approve a browser purchase
- Direct MCP integration
- Reference
Install
npm install --global @shopify/shop@latest
shop skill --installInstalls the shop command, then teaches your agent when and how to use it. Then ask your agent:
Find three rain jackets under US$100 that ship to the US.
A full purchase, from search to tracking, takes five commands:
shop search "trail running shoes" --ships-to US --limit 3
shop cart create --shop example-store.com --variant gid://shopify/ProductVariant/1001 --quantity 1
shop checkout create --shop example-store.com --cart gid://shopify/Cart/…
shop checkout complete gid://shopify/Checkout/… --shop example-store.com --instrument '…'
shop order search "trail running shoes"Search for products
shop search "trail running shoes" --ships-to US --currency USD --limit 3{
"ok": true, "v": 1,
"data": {
"products": [
{
"id": "gid://shopify/p/7Qk2mN9pR4sT6vW8xY0zA1",
"title": "Ridgeline Trail Runner",
"description": { "plain": "Lightweight trail running shoes with a grippy outsole…" },
"variants": [{
"id": "gid://shopify/ProductVariant/1001",
"price": { "amount": 14500, "currency": "USD" },
"availability": { "available": true },
"options": [{ "name": "Size", "label": "10" }, { "name": "Color", "label": "Slate" }],
"rating": { "value": 4.7, "scale_max": 5, "count": 212 },
"seller": { "name": "Example Store", "url": "https://example-store.com", "domain": "example-store.myshopify.com" },
"checkout_url": "https://example-store.com/cart/1001:1?…&payment=shop_pay"
}]
},
// …two more products
],
"pagination": { "has_next_page": true, "total_count": 1180 },
"next": [
"A featured variant may already answer the user's needs; use get_product only for other options or a concrete missing fact…",
// …
]
}
}Prices are integers in the currency's minor units, so 14500 is US$145.00.
Beyond a text query, a search can be shaped three ways:
- Filters such as
--ships-to,--price-maxand--sizeare hard constraints. --intentdescribes what the shopper needs and steers the ranking.--like-imageand--like-idfind products similar to an image or to another product.
shop search --like-image ./jacket.jpg --ships-to US
shop search --like-id gid://shopify/p/7Qk2mN9pR4sT6vW8xY0zA1 --limit 3
shop search "trail shoes" --intent "wide feet, wet Pacific Northwest trails" --currency USD --price-max 20000 --size 11Every variant also has a checkout_url, a buy-now link to the merchant's checkout. A shopper signed in to Shop sees a one-tap review screen there. They can approve the purchase as it is, or change the delivery option, payment method, discounts, and more first.
Sign in for personalization and accelerated checkout
Sign-in is optional: search, carts, and checkouts work without it. Signing in to Shop adds:
- Search results ranked using the shopper's own history.
- Carts and checkouts that arrive with the shopper's saved address and payment preference filled in.
- The account, checkout completion, order, and spend-request commands in the sections below.
shop account login --device-name "My Awesome Agent"{
"ok": true, "v": 1,
"data": {
"signed_in": false,
"pending": {
"verification_uri": "https://accounts.shop.app/device",
"verification_uri_complete": "https://accounts.shop.app/device?user_code=…",
"user_code": "…",
"expires_at": "…",
"interval": 5
}
}
}Signing in takes two runs of the same command:
- With
--wait 0, it returns a link and code right away. The agent shows them to the shopper. - With
--wait 90, it waits up to 90 seconds for the shopper to approve on Shop and returnssigned_in: trueas soon as they do. If they haven't approved yet, it returnssigned_in: falseand the agent can run it again.
--device-name is the name Shop's approval page shows for the agent. Once the shopper approves, the CLI attaches the credential to every request.
Read the shopper's addresses and payment methods
shop account{
"ok": true, "v": 1,
"data": {
"signed_in": true,
"buyer": { "email": "[email protected]" },
"addresses": [{
"id": "address-a", "type": "shipping_address",
"first_name": "Ada", "last_name": "Lovelace",
"street_address": "1 Example Way", "address_locality": "London", "address_country": "GB", "postal_code": "SW1A 1AA"
}],
"preferred_address_id": "address-a",
"spend_permissions": [{
"id": "spend-permission-a", "status": "active", "currency": "USD",
"limit": 10000, "period": { "interval": "month", "ends_at": "…" },
"allowance": { "status": "available", "remaining": 8000 }
}],
"selectable_instruments": [{
"id": "3f1e2d4c-5b6a-4789-8abc-def012345678",
"type": "shop_pay",
"display": { "funding_instrument": { "type": "card", "brand": "visa", "last_digits": "4242" } }
}],
"preferred_instrument_id": "3f1e2d4c-5b6a-4789-8abc-def012345678",
// …links, messages
}
}The response has the shopper's saved details, each with an id:
addresses: saved delivery addresses.preferred_address_idis the one the shopper prefers.selectable_instruments: saved Shop Pay cards.preferred_instrument_idis the one the shopper prefers.spend_permissions: what the shopper allowed this agent to spend ahead of time on shop.com. Each may set a totallimit, aper_purchase_limitand aperiodafter which the limit starts over (none means it never does), in minor units of its own currency, and shows how much of the limit remains; a permission can also set no money limit at all. Within a permission, the agent can complete Shop Pay purchases without asking for approval each time. When it is missing,messagessays why.
When a checkout needs a destination or a payment instrument, the agent passes one of these ids. It never types an address or asks for a card number.
Create a pre-filled checkout
Create a cart, then turn it into a checkout:
shop cart create --shop example-store.com --variant gid://shopify/ProductVariant/1001 --quantity 1
shop checkout create --shop example-store.com --cart gid://shopify/Cart/… # the response below{
"ok": true, "v": 1,
"data": {
"id": "gid://shopify/Checkout/…",
"status": "ready_for_complete",
"buyer": { "email": "[email protected]", "phone_number": "+1555…" },
"line_items": [{ "id": "line-a", "item": { "id": "gid://shopify/ProductVariant/1001", "title": "Ridgeline Trail Runner — Size 10, Slate", "price": 14500 }, "quantity": 1 }],
"fulfillment": { "methods": [{ "type": "shipping", "selected_destination_id": "address-a", "groups": [{ "selected_option_id": "standard", "options": [ /* … */ ] }] }] },
"totals": [{ "type": "subtotal", "amount": 14500 }, { "type": "fulfillment", "amount": 0 }, { "type": "tax", "amount": 1290 }, { "type": "total", "amount": 15790 }],
"payment": { "instruments": [{ "id": "instrument-a", "handler_id": "shop_pay", "type": "shop_pay", "display": { "funding_instrument": { "brand": "visa", "last_digits": "4242" } } }] },
"continue_url": "https://example-store.com/checkouts/…"
}
}The checkout's status says what happens next:
ready_for_complete: nothing is missing. The contact details, delivery address, and Shop Pay card all came from the shopper's account.requires_escalation: something is missing.messages[]says what, and the shopper finishes atcontinue_url.
--patch is the efficient way to change a checkout. You write only the edit, as an RFC 6902 patch, and the CLI:
- Reads the current checkout.
- Applies the patch to that copy.
- Sends the merchant the full updated document.
An edit to a line must first test that line's id. If the checkout changed after the CLI read it, the edit then fails instead of changing the wrong line:
shop checkout update gid://shopify/Checkout/… --shop example-store.com \
--patch '[{"op":"test","path":"/line_items/0/id","value":"line-a"},{"op":"replace","path":"/line_items/0/quantity","value":2}]'Complete the checkout
Pass one of the instruments the checkout offered in payment.instruments. The CLI marks it selected and changes nothing else:
shop checkout complete gid://shopify/Checkout/… --shop example-store.com \
--instrument '{"id":"instrument-a","handler_id":"shop_pay","type":"shop_pay","credential":{"type":"shop_token"}}'{
"ok": true, "v": 1,
"data": {
"status": "completed",
"order": { "id": "gid://shopify/Order/…", "label": "#1042", "permalink_url": "https://example-store.com/…/orders/…" }
// …line items, totals, payment as charged
}
}Track the order
shop order search "trail runner"{
"ok": true, "v": 1,
"data": {
"orders": [{
"id": "…", "label": "#1042", "placed_at": "…",
"seller": { "name": "Example Store", "domain": "example-store.com" },
"line_items": [{ "item": { "title": "Ridgeline Trail Runner — Size 10, Slate", "price": 14500 }, "quantity": { "original": 1, "fulfilled": 1 } }],
"fulfillment": { "events": [{ "carrier": "UPS", "tracking_url": "https://…", "occurred_at": "…" }] },
"permalink_url": "https://…"
}],
"shipments": [ /* standalone shipments Shop tracks without an order */ ]
// …
}
}The results cover every order Shop tracks for the shopper, from any store. By default only in-progress orders are shown; pass --status all to search the full order history.
Approve a browser purchase
Some stores have no agent checkout API (UCP); the agent has to enter a payment credential into the site's checkout form in a browser. A spend request covers that case — it is not a fallback for a Shop checkout that failed or needs the shopper:
- The agent describes the purchase with
shop spend-request create. - The shopper reviews and approves it on Shop.
shop spend-request getreturns a one-time credential that fills the card fields of the site's checkout form, good for up to theapproval_limitthe shopper saw and approved.- The agent pays at the site's checkout and reports the outcome with
shop spend-request complete.
--intent is required: describe the purchase and rationale in the shopper's language (100–500 characters; no links, card details, emails or addresses) — it is what they read on the Shop approval page. In --arguments it is context.intent. --instrument-id names one of the selectable_instruments from shop account; omit it to use the shopper's preferred card. --currency is the code the site's checkout charges in; never convert. --business-country is the business's two-letter country when the site states it; omit it rather than guess. Nested values such as line items take JSON, a @file, or - for stdin:
shop spend-request create \
--business-name "Ridgeline Running" --business-url https://ridgeline-running.example \
--currency USD --approval-limit 12500 \
--line-item @items.json \
--total '{"type":"total","amount":12500}' \
--intent "The trail running shoes you asked me to order this morning from Ridgeline Running, wide fit, in your usual size"// items.json
{ "item": { "title": "Trail running shoe, wide, men's 11", "price": 12500 }, "quantity": 1 }{
"ok": true, "v": 1,
"data": {
"id": "0198e63b-1234-7abc-8def-123456789abc",
"status": "pending",
"approval_limit": 12500,
"continue_url": "https://accounts.shop.app/…",
"expires_at": "…"
}
}Give the shopper the continue_url, then wait for their approval. --output-file keeps the credential out of the transcript: the issued instrument is written to a new file only you can read, and stdout carries the status and terms:
shop spend-request get 0198e63b-1234-7abc-8def-123456789abc --wait 90 --output-file ./card.json{
"ok": true, "v": 1,
"data": {
"status": "consumed",
"credential_output_file": "./card.json"
// …terms as approved
}
}// card.json
{
"spend_request_id": "0198e63b-1234-7abc-8def-123456789abc",
"instrument": {
"type": "card",
"display": { "last_digits": "…" },
"credential": { "type": "pan", "number": "5556…", "expiry_month": "…", "expiry_year": "…", "cvv": "…", "name": "Ada Lovelace" },
"billing_address": { "street_address": "1 Example Way", "address_locality": "London", "address_country": "GB", "postal_code": "SW1A 1AA" }
}
}The credential arrives when the status is consumed. Hand the file to the program that fills the checkout form; without --output-file, the instrument is returned inline instead.
After paying at the site's checkout, the agent reports the outcome:
shop spend-request complete 0198e63b-1234-7abc-8def-123456789abc \
--status success --order '{"id":"EB-20931","total":1495,"currency":"USD"}'{
"ok": true, "v": 1,
"data": { "id": "0198e63b-1234-7abc-8def-123456789abc", "result": { "status": "success", "recorded_at": "…" } }
}The response only confirms that Shop recorded the report. It is not proof that the payment went through.
Direct MCP integration
The CLI is a client of Shop's MCP server at https://mcp.shop.com/. Apart from sign-in, each command above calls one of its tools:
- Most commands send a single
tools/call.--patchreads the checkout before it writes, and--waitpolls. - The CLI adds argument parsing, sign-in, and the JSON envelope.
To see the requests, or to call a tool by its MCP name:
shop checkout create --shop example-store.com --cart gid://shopify/Cart/… --dry-run # the exact request, unsent
shop cart get gid://shopify/Cart/… --shop example-store.com --as curl # the exact request, as curl
shop call search_catalog --arguments '{"catalog":{"query":"rain jacket","pagination":{"limit":3}}}' # any tool by MCP name
shop tools # every command, its tool, its schemaTo use the server without the CLI:
- Connect an MCP host to
https://mcp.shop.com/to access the same tools. Sign-in goes through the host's OAuth flow, against the same Shop account, and the tools behave as they do in the CLI. - A host that supports the skills extension (SEP-2640) finds the server's skill with
skills/liston the same connection and reads its files withresources/read, so there is nothing to install. This package bundles the same skill. - A backend that already holds a Shop token for this resource can hand it to the CLI as
SHOP_ACCESS_TOKEN; the CLI sends it unchanged, never stores or refreshes it, and a rejected token says whether to mint a fresh one (401) or widen the grant (403). The full contract is in the CLI guide.
Install the skill from an installed shop command:
shop skill --installReference
shop --help # the command tree
shop search --help # a command's flags and examples
shop search --schema # its complete input schema
shop tools # every command with its MCP tool, usage and schema, as JSON — for agents
shop skill # the bundled agent guidance, as proseEvery command accepts --arguments <JSON|@FILE|-> with the complete argument object from --schema.
| Exit | Meaning | | --- | --- | | 0 | ok | | 1 | no response from the network | | 2 | usage error | | 3 | sign-in required | | 4 | the merchant or Shop answered with an error, or a precondition failed |
Errors use the same JSON envelope, and their next steps say what to do:
{"ok":false,"v":1,"error":{"code":"auth_required","message":"Not signed in on this device","retryable":false,"next":["Run shop account login --wait 0 and show the shopper the verification URL and code","Run shop account login --wait 90 to finish once they approve","Retry this command after signing in"]}}Run shop skill --install again after upgrading shop to replace the installed guidance.
By accessing or using Shopify technology, or any data or content provided through it, you agree to the Shopify API Terms.
