Meta's Muse can find a jacket, fill the address, compute the tax and still be unable to pay, because Meta gives it permission to spend from outside the model, bound to one order and one clock. That gate is the consumer half of the story. The merchant half is a contract most teams get backwards: cart first, checkout last, and five MCP surfaces instead of three. This article walks both halves once, with the exact statuses, tiers and idempotency rules Shopify now documents.
11:47 pm, Muse has a jacket and no permission to pay
A buyer tells Muse it wants a rain shell under two hundred dollars. Muse searches, compares four jackets, opens one product page, picks a size, fills the shipping address, reaches the order review screen, and stops. The total is on screen. The card is on file. Nothing moves.
Muse has not been denied. It has reached a boundary the architecture draws on purpose, and everything interesting about agentic commerce sits on either side of it. Search is a read operation, and a wrong answer costs nothing. Payment is a write operation with a financial consequence, so it needs its own permission model, its own failure path and its own evidence trail. Meta built Muse around that distinction, and Shopify built the merchant side of it into a protocol that is versioned, testable and rather unforgiving.
Two source families sit under this piece. The consumer flow, the approval rules and the wallet limits come from a leaked copy of Muse's internal agent prompt corpus, published on GitHub as asgeirtj/system_prompts_leaks, cross-checked against Meta's engineering posts, Stripe's announcements and the press reporting around them. The merchant contract comes from Shopify's agentic commerce documentation and the Universal Commerce Protocol specification, which I read page by page rather than from snippets. Where the two disagree, the protocol wins, and I say so.
Muse's five steps, and the wall at step two
Meta launched Muse in the United States on 8 September 2026, in the Muse app and inside WhatsApp. Stripe, which supplies the payment rail, reported three weeks later that agentic purchases through Link had risen 38x in a single month. Whatever you think of the product, the volume is real enough that the protocol under it deserves a reading.
Five steps carry a purchase.
Find and compare. Catalog search needs no purchase approval. Meta Catalog has its own search permission, set to allow by default, so the first search in a task may ask once and that approval covers the rest of the task. Presenting results moves no money.
Checkout. A background browser task drives the merchant's checkout until the final terms are ready for review, or, for catalog products that support agentic checkout, opens a session over UCP without a live browser. Creating a checkout still moves no money. If a size, a colour or a model is missing, Muse asks.
Review. Final items, selected options, delivery and contact details, total and payment method appear together. For a wallet purchase, the review appears only once the wallet is configured.
Confirm. For a wallet purchase, the payment provider's approval card is the confirmation. It authorises that exact reviewed order, and Muse is told not to ask for a second confirmation in chat. For other browser methods, the buyer confirms in chat and a plain yes is accepted.
Completion. After approval, the task finishes checkout and submits the order. Shop Pay hands back a one-time token. Stripe Link issues a one-time virtual card funded for that purchase.
Step two is where the wall stands. Muse can do everything except spend, and permission to spend arrives later, from outside the model, bound to one transaction and one expiry.
Shopper { # Shopper
s1: circle label:"Ask for a jacket under 200 dollars"
s2: rectangle label:"Approve one order one amount one method"
s3: circle label:"Order confirmed"
s4: circle label:"No order approval expired"
s1.handle(right) -> Agent.a1.handle(left)
a3.handle(bottom) -> s2.handle(top) [label="Approval card"]
s2.handle(right) -> Agent.a4.handle(top) [label="Approved"]
a4.handle(bottom) -> s4.handle(left) [label="Refused or late"]
}
Agent { # Agent
a1: rectangle label:"Search and compare products"
a2: rectangle label:"Prepare checkout and totals"
a3: rectangle label:"Present reviewed order"
a4: diamond label:"Approved within ten minutes"
a5: rectangle label:"Pay with one-time credential"
a6: circle label:"Submit order"
a1.handle(right) -> a2.handle(left)
a2.handle(right) -> a3.handle(left)
a4.handle(right) -> a5.handle(left) [label="Yes"]
a5.handle(right) -> a6.handle(left)
a6.handle(bottom) -> Shopper.s3.handle(top) [label="Confirmation"]
}
The four rules that make Muse's gate hold
An approval Muse could talk itself past would not be a gate. Four rules close that door, and three of them are enforced outside the conversation.
Every purchase re-prompts. The approval binds to that exact checkout: same merchant, same amount, same payment selection. Change any of the three and a fresh card fires. The one exception sits on the card itself, where the buyer can pick another saved wallet card and the approval then covers that choice.
Approvals cannot be pre-granted, batched or automated. A friendly agreement in the conversation is not an approval, and the system rejects stored or reusable spending grants. A scheduled task can walk all the way to a pending approval card, and then it waits. That is the entire unattended story, and the merchant side now says the same thing in its own language: a token-tier call made by an agent with no buyer present fails, because Shopify has no placeholder for the buyer's IP address and will not fall back to the agent's own address.
Approvals are short-lived. A pending checkout expires after about ten minutes, after which the flow restarts from search. Separately, reaching a checkout page during a browser task can raise its own consent card, and once that is approved, later checkout pages in the same task at the same merchant do not re-ask for roughly three hours.
Browsing and spending are separate mechanisms. A site can earn a per-site always-allow for browsing. Spending never can. Meta's own documentation puts it plainly, and the protocol mirrors it: the capability that lets an agent prepare a purchase is not the capability that lets it complete one.
Behind the gate sit the wallet limits. Link exposes a per-purchase limit plus daily and thirty-day windows through wallet.get_user_info, and Muse reads them fresh on every purchase instead of quoting an older figure. Link's purchase protections apply to eligible orders: up to $500 for damage, theft or loss, up to $500 for a price drop, up to $250 for return shipping and restocking, and up to $1,000 under a refund guarantee. Those programmes belong to Stripe, not to Meta, and Muse is forbidden from telling a buyer that a specific purchase is covered.
The merchant side: four capability families, five endpoints
The consumer protocol only works if the merchant publishes a machine-readable surface. That surface is the Universal Commerce Protocol, co-developed for shopping by Google, Shopify, Etsy, Wayfair, Target, Walmart, Amazon, Microsoft, Meta and Stripe, and it rides on JSON-RPC 2.0 over MCP, with REST as the other sanctioned transport.
Shopify implements it in four capability families served by five endpoints. If you want the same handshake at sequence level, the earlier map of the UCP flow on this blog still holds; what it predates is the cart surface, which is where most of the operational risk now sits. The distinction matters more than the count, because the two middle families do different jobs and carry different limits.
| Family | Endpoint | Tools | Moves money |
|---|---|---|---|
| Global Catalog | catalog.shopify.com/api/ucp/mcp | search_catalog, get_product, lookup_catalog | No |
| Storefront Catalog | {shop}/api/ucp/mcp | same three tool names, scoped to one merchant | No |
| Cart | merchant MCP endpoint | create_cart, get_cart, update_cart, cancel_cart | No |
| Checkout | merchant UCP endpoint, /api/ucp/mcp | create_checkout, get_checkout, update_checkout, complete_checkout, cancel_checkout | Only complete_checkout |
| Order | merchant MCP endpoint, plus webhooks | get_order | No |
Two consequences fall straight out of that table, and most integrations get both wrong on the first pass.
Carts are for thinking, checkouts are for committing. A cart is a long-lived, unauthenticated-friendly container: add line items, set the country, estimate totals, share the cart's continue_url with the buyer, keep iterating over several turns. A checkout is short-lived, stricter on freshness and idempotency, and throttled harder. The numbers are published: global catalogue traffic runs at 5 requests per second per API client, and storefront catalogue traffic is limited per store. Shopify says it in one sentence on the checkout page: use Cart MCP to iterate, reserve Checkout MCP for buyers who are ready to buy. An agent that calls create_checkout at the first impulse burns its rate limit on a buyer who is still comparing colours, and the conversion it loses never appears as an error.
Conversion between the two is a field, not a rebuild. create_checkout takes an optional cart_id, which turns a cart built with Cart MCP into a checkout session. The line items do not get rebuilt, and the totals do not get recomputed by the agent.
Agent { # Agent
b1: circle label:"Buyer starts shopping"
b2: rectangle label:"Iterate lines and context on cart"
b3: rectangle label:"Buyer commits to the order"
b4: rectangle label:"Open a checkout from the cart"
b5: rectangle label:"Complete once with the same key"
b6: circle label:"Order placed"
b1.handle(right) -> b2.handle(left)
b2.handle(right) -> b3.handle(left)
b3.handle(right) -> b4.handle(left)
b4.handle(right) -> b5.handle(left)
b5.handle(right) -> b6.handle(left)
b2.handle(bottom) -> Business.c1.handle(top) [label="update_cart"]
c1.handle(bottom) -> b3.handle(bottom) [label="Live totals"]
b4.handle(bottom) -> Business.c2.handle(top) [label="create_checkout"]
c2.handle(bottom) -> b5.handle(bottom) [label="ready_for_complete"]
}
Business { # Merchant API
c1: rectangle label:"Cart tools answer at the highest rate limit"
c2: rectangle label:"Checkout tools answer once then throttle"
}
Negotiation, tiers, and who may actually complete
The next surprise is that the merchant does not expose a fixed menu. It negotiates.
You publish a platform profile at an HTTPS URL and reference it in every request through meta.ucp-agent.profile. The merchant publishes its own business profile at /.well-known/ucp, declaring protocol version, capabilities, payment handlers and signing keys. Shopify then fetches and validates your profile, checks version alignment, intersects your declared capabilities with what the shop supports, and prunes any extension whose parent capability did not survive the intersection. Negotiation is server-selected. What you expose is a contract that gets negotiated, not a catalogue that gets listed.
The tier comes next, and it decides the only question that matters commercially: may this agent complete, or must it hand the buyer back. Shopify documents three tiers, and the difference is entirely about how much the merchant knows about who is calling.
| Tier | Catalog, Cart, Checkout tools | complete_checkout |
Order tools |
|---|---|---|---|
| Token, with purchase permission | Yes, and buyer-linked tokens personalise search and apply automatic discounts | Yes | Yes, with read_global_api_orders, limited to orders your agent placed |
| Signed | Yes | No | No |
| Anonymous | Yes | No | No |
Two operational details live inside that table. Token-tier requests must carry a Shopify-Buyer-IP header on every tools/call, including read-only calls, and a missing or invalid IP returns HTTP 422 with no fallback and no placeholder. Signed and anonymous traffic keeps read and prepare rights but loses completion entirely, plus most of the rate limit. An agent that cannot say who it is can still browse the catalogue and build a cart, and that is exactly the level of trust the merchant is willing to extend.
Agent { # Agent
n1: circle label:"Call create_checkout with profile URI"
n2: rectangle label:"Publish platform profile over HTTPS"
n3: rectangle label:"Declare checkout and extensions"
n4: diamond label:"Negotiated set includes checkout"
n5: circle label:"Muse completes the order"
n6: circle label:"Prepare only and hand back"
n1.handle(right) -> n2.handle(left)
n2.handle(right) -> n3.handle(left)
n3.handle(bottom) -> Shopify.m1.handle(top) [label="meta.ucp-agent.profile"]
m4.handle(bottom) -> n4.handle(top) [label="Active capability set"]
n4.handle(bottom) -> n5.handle(top) [label="Token with permission"]
n4.handle(right) -> n6.handle(left) [label="Read only"]
}
Shopify { # Shopify business
m1: rectangle label:"Fetch and validate the profile"
m2: diamond label:"Protocol versions align"
m3: rectangle label:"Intersect capabilities"
m4: rectangle label:"Prune orphan extensions"
m5: circle label:"Return an error path"
m1.handle(right) -> m2.handle(left)
m2.handle(bottom) -> m3.handle(top) [label="Yes"]
m2.handle(right) -> m5.handle(left) [label="No"]
m3.handle(right) -> m4.handle(left)
}
Six requirements your surface has to meet
Syntax is the easy part. These six decide whether the integration survives its first month, and each one is documented rather than inferred.
Idempotency on the two destructive verbs. complete_checkout and cancel_checkout require a UUID in meta["idempotency-key"]. An agent under a network timeout does not know whether the order exists, so it retries, and without the key a retry becomes a second order. Treat the key as the identity of the intent, not of the request: derive it from the checkout session plus the intent, keep it for the life of the session, and reuse it verbatim when you retry after a 429.
Cart for iteration, checkout for commitment. The rate-limit design is a design instruction. Cart tools take unauthenticated requests and answer at the highest limits. Checkout tools are throttled harder at every tier. Build the shopping turn on cart tools, and open a checkout only when the buyer has decided.
Escalation as a first-class answer. A checkout carries a status and a messages array, and each message carries a severity. recoverable means call update_checkout and fix the data. requires_buyer_input or requires_buyer_review means hand the buyer continue_url. Twelve lines of code around those severities replace a support queue, and none of it is a failure path: 3-D Secure, account creation, age verification and loyalty gates all arrive the same way, as designed.
Price, stock, shipping and tax as data. An agent cannot negotiate. Every response should carry the checkout state, a version or updated-at marker, the currency, and the total split into items, shipping and tax. If availability or delivery cost lives only in a rendered page, the checkout fails at the last screen, after the buyer has already approved a total.
Honest identity, and a tier you can defend. Say who is calling, accept the buyer IP requirement, and design for the tier you actually qualify for rather than the one in your pitch deck. The alternative is being blocked, which is what happened to Muse at Amazon.
One charge, capped. The wallet path issues a single-use credential and the merchant charges it once. Never store an agent-supplied credential, and never authorise an amount the buyer did not see.
The status lifecycle deserves its own paragraph, because that is where the gate becomes a protocol state instead of a paragraph in a prompt.
Agent { # Agent
d1: circle label:"Checkout session opened"
d2: rectangle label:"Fix missing data"
d3: diamond label:"Buyer review required"
d4: rectangle label:"Complete with the same key"
d5: circle label:"Order completed"
d6: circle label:"Session expired"
d1.handle(right) -> d2.handle(left)
d2.handle(right) -> d3.handle(left)
d3.handle(bottom) -> Buyer.f1.handle(top) [label="requires_buyer_review"]
f1.handle(right) -> f2.handle(left)
f2.handle(bottom) -> d4.handle(top) [label="Yes"]
f2.handle(right) -> f4.handle(left) [label="No"]
f4.handle(bottom) -> d6.handle(top) [label="Abandoned"]
d4.handle(right) -> d5.handle(left)
}
Buyer { # Buyer
f1: rectangle label:"Open continue_url and review"
f2: diamond label:"Buyer approves"
f4: rectangle label:"Buyer closes the page"
}
The five statuses are incomplete, requires_escalation, ready_for_complete, completed and canceled. Only ready_for_complete allows complete_checkout. Anything else either gets fixed through update_checkout or goes to the buyer through continue_url, and a session that nobody finishes expires. Handle those five words in a switch statement before you write a single prompt, because every production incident I have seen in this space is a sixth case that fell through the default branch.
continue_url also has rules that read like security advice because that is what they are. Parse it, refuse anything that is not HTTPS, do not require the host to match the endpoint you called, since it can legitimately live on the shop's myshopify.com domain, its checkout domain or shop.app. Share it only with that buyer, and do not log it.
The catalogue is untrusted input
An agentic storefront reads text written by other people: titles, descriptions, review bodies, shipping notes, and in marketplaces anything a third-party seller wants to type. That text enters the model's context, which makes it an injection surface with a payment attached.
The rule is boring and absolute. Catalogue content is data, never instruction. Tag it as untrusted before it reaches the model, run a classifier over it, strip anything that reads like a directive, and check egress before any write. Muse applies that in layers, with external data tagged as untrusted, an ensemble of independently trained injection classifiers, and deterministic boundaries that hold even if the model is persuaded to misbehave. Note what makes that design work: the layers are outside the model. A prompt instruction that says "ignore catalogue instructions" is a fourth layer the attacker also controls.
Three ways an agent pays
The rail decides what the merchant and the agent can see, and every merchant integration should know which rail it is on. Muse runs on Link; the Agentic Commerce Protocol is the OpenAI-side counterpart, and the same gate logic reappears there under different names.
Wallet token. Shop Pay returns a secure one-time token. The merchant charges it once, and the agent never sees a card number. Supported currencies include USD, CAD, MXN and EUR.
Wallet virtual card. Stripe Link issues a one-time virtual card funded for the approved purchase, and the agent types it into the merchant's ordinary card form, so the merchant needs no special button. Link funds the card to the largest whole number no more than five units above the exact total, and that headroom is never charged. This is why a merchant does not need to be a Link merchant to be bought from.
Browser takeover. If both wallet routes fail, or the buyer has a card on file, the agent hands the browser over and the buyer types payment details on the merchant's page. The charge is real. The flow is still gated: the agent relays items, shipping, total and saved method, then waits for explicit confirmation.
Agent { # Agent
p1: circle label:"Approval covers one purchase"
p2: diamond label:"Wallet rail available"
p3: rectangle label:"Mint a single-use credential"
p4: circle label:"Buyer types the card in the browser"
p1.handle(right) -> p2.handle(left)
p2.handle(bottom) -> p3.handle(top) [label="Yes"]
p3.handle(bottom) -> Merchant.q1.handle(top) [label="Credential"]
p2.handle(top) -> p4.handle(bottom) [label="No"]
}
Merchant { # Merchant
q1: rectangle label:"Verify merchant amount and method"
q2: rectangle label:"Charge once and issue receipt"
q3: circle label:"Payment settled"
q1.handle(right) -> q2.handle(left)
q2.handle(right) -> q3.handle(left)
}
What broke Muse first, and what will break you
Four failures recur, and none of them is a bug in the ordinary sense.
Muse got blocked for identity. Amazon began blocking Muse from its site on Sunday 20 September, twelve days after launch and on the same weekend that Patrick Wardle's zero-day went public; Meta shipped a hotfix more than twelve hours after disclosure. The stated reason for Amazon's block was not the vulnerability. The agent had not identified itself while browsing, and Amazon had not been told in advance that Muse would access its store. Amazon's principle was that third-party applications buying on behalf of customers should operate openly and respect whether a provider wants to participate. If your surface cannot say who is calling, expect the same answer, and expect it fast.
The approval expires before the buyer acts. Ten minutes is generous for a card tap and short for a 3-D Secure challenge on a new device. The correct behaviour is to restart from review, not to reuse the stale approval, and to tell the buyer why.
Negotiation removes the checkout silently. Capability intersection is a feature until it prunes the capability you were counting on. Instrument the negotiated scope you actually received, compare it to what your release notes promise, and alert on the difference.
The browser path raises a consent card nobody expects. When an agent drives a real browser and lands on a checkout page, the client can raise its own consent request, separate from the payment approval. Some teams read that as a double confirmation and strip one of the two. Keep both: one belongs to the client and covers the site, the other belongs to the payment and covers the amount.
Shipping order
If you are building the merchant side this quarter, the order that survives contact with a deadline is this one.
- Publish the business profile and the read-only surfaces first: catalogue, then cart.
- Make
complete_checkoutandcancel_checkoutidempotent, and prove it by replaying the same key against a sandbox order. - Return
requires_escalationwith a workingcontinue_urlbefore you accept a single live payment. - Instrument the negotiated scope and the tool calls you actually receive, then reconcile them against your release notes.
- Only then expose checkout completion, and only at a tier you can defend.
For a Shopify merchant the decision is mostly made for you: direct checkout through Meta is active by default for eligible stores, it can be switched off, and with it off buyers are simply redirected to your storefront. Eligibility runs on the country you sell into, and Canada is on the list. What is not made for you is the internal conversation: whether your return policy, your stock data and your fulfilment promises survive a buyer who never sees your site.
In summary
- Muse's gate is the protocol. Five steps, only the last two move money, and permission to spend is bound to one merchant, one amount and one method for about ten minutes.
- The merchant side is a negotiated contract with four families. Catalog for discovery, cart for iteration, checkout for commitment, orders for proof. Most teams invert the middle two and blame the model.
- Most production failures are contract failures. Missing idempotency, stale approvals, silent capability pruning, agents that cannot name themselves, and a default branch that swallows
requires_escalation.
Sources
- Meta, Introducing Muse (8 September 2026): https://about.fb.com/news/2026/09/introducing-muse-personal-ai-agent/
- Meta AI, Muse for Shopping: https://ai.meta.com/muse/shopping/
- Meta AI Research, How We Built Safety Into Muse: https://research.meta.ai/blog/security-and-safety-for-ai-agents-our-approach-with-muse
- Muse agent prompt corpus (leaked),
docs/payments-and-purchases.md: https://github.com/asgeirtj/system_prompts_leaks/tree/main/Meta/muse-agent - Shopify, Build commerce agents with UCP: https://shopify.dev/docs/agents
- Shopify, Cart MCP server: https://shopify.dev/docs/agents/carts-and-checkout/cart-mcp
- Shopify, Checkout MCP server: https://shopify.dev/docs/agents/carts-and-checkout/checkout-mcp
- Shopify, Agent profiles and UCP negotiation: https://shopify.dev/docs/agents/profiles
- Shopify, Auth and rate limiting: https://shopify.dev/docs/agents/profiles/auth-and-rate-limiting
- Shopify, Order MCP server: https://shopify.dev/docs/agents/orders/order-mcp
- Shopify Help, Selling on Meta: https://help.shopify.com/en/manual/online-sales-channels/agentic-storefronts/meta
- Universal Commerce Protocol specification: https://ucp.dev/
- Stripe Newsroom, Stripe helps Muse shop with Link (8 September 2026): https://stripe.com/newsroom/news/stripe-helps-meta-muse-shop-with-link
- Stripe Blog, Helping personal agents shop more intelligently and reliably with Link (29 September 2026): https://stripe.com/blog/helping-personal-agents-shop-more-intelligently-and-reliably-with-link
- Link, Protect your purchases: https://link.com/protections
- Ars Technica, Muse, Meta's extraordinarily privileged AI assistant, has a serious 0-day: https://arstechnica.com/security/2026/09/muse-metas-extraordinarily-privileged-ai-assistant-has-a-serious-0-day/
- Reuters, Meta bolsters Muse safety warning (25 September 2026): https://www.reuters.com/technology/meta-bolsters-muse-safety-warning-after-security-vulnerability-found-information-2026-09-25/
- CNBC, Meta Muse shopping: checkout, payments, privacy (3 October 2026): https://www.cnbc.com/2026/10/03/meta-muse-shopping-ai-agent.html
