Reference
URLs
| Thing | Production | Dev |
|---|---|---|
| Bridge MCP | https://agent.artos.sh/mcp | https://agent.dev.artos.sh/mcp |
| API / OAuth AS issuer | https://api.artos.sh | https://api.dev.artos.sh |
| Global catalog MCP (Direct) | https://api.artos.sh/mcp | https://api.dev.artos.sh/mcp |
| Per-store MCP (Direct) | https://api.artos.sh/s/:slug/mcp | same shape |
| OAuth token | https://api.artos.sh/ucp/oauth2/token | https://api.dev.artos.sh/ucp/oauth2/token |
| AS metadata | https://api.artos.sh/.well-known/oauth-authorization-server | same shape |
| Discovery | https://api.artos.sh/s/:slug/.well-known/ucp | same shape |
| Consent | https://my.artos.sh/oauth/consent | https://my.dev.artos.sh/oauth/consent |
| Agent profile / CIMD | profile.artos.sh | same |
SDK (Build track)
@artos-commerce/ucp-client — npm install @artos-commerce/ucp-client (Node 22+; optional @mysten/sui peer for crypto).
| Export | Purpose |
|---|---|
UcpClient | Typed transport: globalSearch, callGlobalTool, callStoreTool, listAccountTools, callAccountTool, fetchStoreProfile, fetchImage, hasBuyerToken, ucpAgentHeader |
Ap2Signer | mintCheckoutMandate, mintPaymentMandate (compact ES256 JWS) |
createCheckoutHandlers | Read tools + confirmPurchase (one-call card / crypto / $0) |
createAccountHandlers | Typed wrappers over buyer-account MCP tools (buyer bearer) |
OAuthClient, createPkce, DEFAULT_BUYER_SCOPE | Buyer OAuth discovery, PKCE, token exchange/refresh |
canonicalJson, verifyDetachedJws, verifyMerchantAuthorization | Byte-parity canonical JSON + AP2 verification |
toMinorUnits, normalizeSearchFilters, resolveRail, grandTotal, currencyOf, asAllowanceId, isUcpError, messageOf | Helpers |
resolveCryptoDeps (/crypto), SuiSigner (/sui) | Crypto rail — sign + submit the Sui PTB (need @mysten/sui). Subpath-only — not on the root barrel |
Subpath entries: @artos-commerce/ucp-client/{ucp,ap2,checkout,account,oauth,sui,crypto}.
The crypto symbols (resolveCryptoDeps, SuiSigner) are importable only from
/crypto and /sui, so card-only builds never load the optional @mysten/sui peer.
Bridge tool catalog (Connect)
Flat inputs; the bridge adds the UCP envelope. Price filters use major units (dollars).
| Tool | Input | Auth |
|---|---|---|
search_products | query?, filters?, sort?, pagination? | Platform key |
lookup_products | ids: string[] | Platform key |
get_product | id, store_slug?, selected?, context? | Platform key |
create_cart | store_slug, items: [{ id, quantity }] | Platform key |
update_cart | store_slug, id, items | Platform key |
get_cart | store_slug, id | Platform key |
create_checkout | store_slug, cart_id? | items?, buyer?, shipping_address? | Platform key |
update_checkout | store_slug, id, buyer?, shipping_address?, shipping_method_id?, discounts? | Platform key |
confirm_purchase | store_slug, checkout_id, payment_method?, payment_mandate_id?, apply_coupon? | Platform key (+ buyer bearer for crypto) |
get_order | store_slug, id | Platform key + orders:read |
get_agent_identity | — | None (local) |
| Buyer account tools | see Buyer account | Buyer bearer (proxied) |
fetch_image exists but is widget-only (hidden).
The Auth column describes what the bridge sends. On the raw API the global
catalog (POST /catalog/*, global /mcp tools) also works at the anonymous
tier with no key at all — see Catalog crawler and
Authentication.
Bridge tools carry MCP tool annotations so a host can reason about safety:
the read tools (search_products, lookup_products, get_product,
get_cart, get_order, get_agent_identity) are
readOnlyHint; cart/checkout writes are additive; only confirm_purchase is
destructiveHint (it places the order). Proxied buyer-account tools default to
read-only unless the API marks them otherwise.
Bridge → raw UCP mapping (Build track)
| Bridge tool | Raw UCP tool | Endpoint |
|---|---|---|
search_products | POST /catalog/search (REST, not an MCP tool) | global |
lookup_products | lookup_catalog | /mcp (global) |
get_product | get_product | /s/:slug/mcp with store_slug, else /mcp (global) |
create_cart / update_cart / get_cart | create_cart / update_cart / get_cart | /s/:slug/mcp |
create_checkout / update_checkout | create_checkout / update_checkout | /s/:slug/mcp |
confirm_purchase | complete_checkout (+ prepare_checkout_payment for crypto) | /s/:slug/mcp |
get_order | get_order | /s/:slug/mcp |
Raw UCP differences (see Direct UCP):
args wrapped under catalog/cart/checkout; line items { item: { id }, quantity };
price filters in minor units; rails selected by inner id artos.card /
artos.crypto (not the sh.artos.* registry key).
Transport headers (Direct UCP)
Required on the UCP shopping surfaces (/mcp, /s/:slug/mcp, REST
/s/:slug/...). The buyer-account surface (/account/mcp) needs none of these —
it is bearer-scoped.
| Header | When | MCP | REST |
|---|---|---|---|
Request-Id | Every call | required | required |
UCP-Agent: profile="…" | Every shopping call | required (+ body meta["ucp-agent"].profile) | required |
Idempotency-Key | State-changing calls | use body meta["idempotency-key"] instead | required (header) |
REST paths (Direct UCP)
| Operation | Method + path |
|---|---|
| Global catalog search | POST /catalog/search |
| Per-store catalog | … /s/:slug/catalog |
| Cart | … /s/:slug/carts |
| Checkout | POST /s/:slug/checkout-sessions, …/:id (GET/PUT), …/:id/complete, …/:id/payment-intent, …/:id/cancel |
| Orders | … /s/:slug/orders |
OAuth grants
POST /ucp/oauth2/token (form-urlencoded):
| Grant | Required params |
|---|---|
authorization_code | code, code_verifier, client_id, redirect_uri |
refresh_token | refresh_token (rotated, single-use) |
client_credentials | client_id, client_secret (post or Basic) |
Buyer OAuth scopes (advertised by the AS): purchase:complete,
offline_access. orders:read is a permission on platform / merchant
credentials, not a buyer OAuth scope — see Authentication.
Error signals
| Code / signal | Meaning | Fix |
|---|---|---|
invalid_api_key | Unknown/revoked platform key | Seed/rotate the platform credential |
invalid_token | Expired/invalid bearer | Refresh via OAuth (refresh_token) |
missing_request_id | No Request-Id header | Send a unique Request-Id per call |
missing_ucp_agent / invalid_ucp_agent | No/malformed UCP-Agent header | Send UCP-Agent: profile="…" |
missing_idempotency_key | State-changing REST call without the header | Send an Idempotency-Key header |
invalid_profile_url | Malformed agent profile URL | Send a valid profile URL |
insufficient_trust | Tier too low for the operation | Authenticate (token tier) |
insufficient_scope | Missing required permission | Buyer OAuth: purchase:complete; platform key: grant orders:read on the credential |
payment_selection_required | Multiple rails, none chosen | Read ucp.payment_handlers, retry with payment_method |
mandate_expired | AP2 exp missing/past | Mint a fresh mandate |
mandate_scope_mismatch | Mandate merchant ≠ store | Bind the mandate to the store slug |
| UCP error envelope | Business outcome (often HTTP 200, ucp.status: error) | Read messages[] and severity |
Webhook events
See Orders → Lifecycle webhooks.
Spec & schemas
UCP spec — UCP schemas, services, and documentation.