Troubleshooting
401 on buyer-bound calls (key + bearer)
The API prefers X-API-Key over a bearer, so a crypto prepare/complete or
/account/mcp call that sends both resolves as the platform identity and the
buyer is never loaded. Send the buyer bearer only on those calls.
missing_request_id / missing_ucp_agent
Every Direct UCP shopping call (MCP and REST) needs a Request-Id header and a
UCP-Agent: profile="…" header. The buyer-account surface (/account/mcp) needs
neither. See Direct UCP → the raw transport.
”Tool … requires meta.ucp-agent.profile”
On the MCP transport you must repeat the profile in the body as
meta["ucp-agent"].profile in addition to the UCP-Agent header. The header
clears the transport guard; the body clears the tool layer.
missing_idempotency_key
State-changing REST calls (cart/checkout create/update/cancel, complete)
require an Idempotency-Key header. On MCP, use the body
meta["idempotency-key"] instead.
404 on a checkout call
The REST checkout base path is /s/:slug/checkout-sessions (not /checkouts):
POST /s/:slug/checkout-sessions, then …/:id/complete, …/:id/payment-intent,
…/:id/cancel.
Wrong handler_id / rail not selected
Select a rail by the handler’s inner id — artos.card or artos.crypto — not the
sh.artos.card / sh.artos.crypto registry key from the profile.
”Tool … requires meta[idempotency-key]”
State-changing Direct UCP tools (cart/checkout create/update/cancel,
complete_checkout) require meta["idempotency-key"]. Reusing a key with
different params is rejected — generate a fresh key per logical attempt and reuse
it only to retry the same call.
Validation error on cart/checkout line items
Raw UCP line items are { "item": { "id": "…" }, "quantity": n }, not the
bridge’s flat { id, quantity }. Args are also wrapped under
catalog/cart/checkout.
resolveCryptoDeps / SuiSigner import fails
The crypto symbols are not on the root barrel. Import
resolveCryptoDeps from @artos-commerce/ucp-client/crypto and SuiSigner from
@artos-commerce/ucp-client/sui (card-only builds skip them and never install
@mysten/sui). See Build with the SDK.
continue_url isn’t a payment link
A continue_url on a cart or an incomplete checkout is just a “continue in
browser” link, not a payment page. The hosted payment link only appears on a
checkout with status: requires_escalation (card with no token / 3-DS), and
is dropped once the session is terminal. See
Checkout handoff.
Catalog price filter returns the wrong range
Bridge search_products price is major units (dollars: max: 100); raw UCP
search_catalog price is minor units (cents: max: 10000). Don’t mix them.
Crypto checkout fails after OAuth
OAuth consent (Connected apps) is not the AP2 spend mandate (Agents). Authorize the agent under My Artos → Agents and set caps. Exceeding a cap fails completion before any order is placed.
payment_selection_required
The store offers more than one rail and none was selected. Read
ucp.payment_handlers, ask the buyer, and retry confirm_purchase /
complete_checkout with payment_method (the handler id) set. No order is placed
on the gated call.
mandate_expired / mandate_scope_mismatch
The AP2 mandate must carry a future exp and bind merchant to the store slug,
over the live re-priced terms. Mint a fresh mandate bound to the current quote.
CIMD redirect_uri is not registered
Add every callback (including http://localhost:8898/oauth/callback) to the
published oauth-client.json redirect_uris and redeploy. CIMD docs are
TTL-cached (~600s) — restart the local API in dev to flush.
invalid_api_key on a fresh database
Seed the platform agent credential (pnpm seed in artos-api creates
ck_artos_agent.…). A fresh DB without the seed 401s store tool calls.
Silent refresh not working
All three must line up: the AS advertises offline_access, the resource returns
401 with WWW-Authenticate: Bearer error="invalid_token", and your client
relays that 401 + header (doesn’t flatten it). The client must have requested
offline_access and stored the rotated refresh token.
No webhooks received
Confirm ucp.webhookUrl / UCP_WEBHOOK_URL is set and HTTPS. A blank URL
disables webhooks silently. Verify signatures before acting; reconcile missed
deliveries by polling get_order / get_my_order.
Native Connector can’t reach localhost
Anthropic’s Connector OAuth runs in the cloud and can’t reach a localhost dev
stack. Use mcp-remote for local dev, and set NODE_EXTRA_CA_CERTS to your
mkcert root CA for dev TLS. See Local development.
Deep reference
For bridge deployment, OAuth relay, and auth edge cases, see Local development, Authentication, and the sections above.