CartRelay
쇼핑객이 승인한 소매업체 연결 기능을 갖춘 AI 쇼핑 에이전트용 실시간 상품 탐색.
호스팅형 MCP 서버
npx add-mcp 'https://cartrelay.market/mcp'Claude Code, Codex, Cursor 등에 설치됩니다
문서
Built for agents.Designed around real people.
Two agent entry points, one commerce service: authenticated hosted MCP and REST fallback. Humans set intent, connect agents and consent to signed intents. The website is not a parallel catalog browser. This concrete proposed v1 contract makes no compatibility claim for unavailable historical v2 interfaces or unverified assistant platforms.
A real connection, not a copied brief
New to agent shopping? Start with the human setup guide. Build your brief, then use an agent client that accepts a hosted MCP endpoint and a Bearer credential, or call REST from your agent integration. Copying a brief does not connect or authorize an assistant. Client features, subscriptions and account permissions vary; no consumer-assistant compatibility is claimed as tested here.
Use the actual origin you are visiting:
/mcp — hosted MCP /api/v1/search — REST search
- Create a short-lived delegated key in this shopper browser.
- Configure your trusted agent client with
Authorization: Bearer <key>. - List tools to verify transport. Query only for an explicit shopper need.
- Preserve exact variant IDs, quantities, currencies and unknown facts. Create the intent and give its
review_urlto the human. - The originating shopper browser reviews and authorizes handoff. An agent's
approval:truealone is not human consent.
Hosted MCP endpoint: /mcp
Authorization: Bearer <delegated-key>
Client syntax is client-specific; copying this is not a connection.
REST example — agent only
Set CARTRELAY_KEY securely. Never paste raw keys into shared logs.
POST /api/v1/search
Authorization: Bearer <delegated-key>
Content-Type: application/json
{"query":"laundry refill","context":{"country":"CA","currency":"CAD"},"limit":3}
Browser session & CSRF
GET /api/session with credentials included and X-CartRelay-Client: browser returns {csrf_token,expires_at}. Browser mutations include X-CartRelay-CSRF. Opaque cookies are HttpOnly and secure on HTTPS; CSRF stays in memory. These cookies authorize scoped key management, support and review of an agent-issued intent owned by that browser. They do not authorize /mcp or any /api/v1 commerce route. Open CartRelay directly if embedded cookies are blocked.
A key for your own agent
Guest-scoped delegated keys last two hours and can be revoked earlier. Guest sessions last 24 hours; intent tokens last ten minutes. A key holder can act within its permitted scope until expiry or revocation. Trust your client and keep the key private. Keys are not operator credentials.
Reference hosted MCP client
Node ESM example for the pinned SDK2 client package. It connects and lists tools; it does not query a catalog or order products. Run it against your actual service and inspect current capability status. Transport discovery is not proof of live source negotiation, browser-consent validation, or consumer-platform approval. Published source-profile verification remains a separate release condition.
pnpm add @modelcontextprotocol/client@2.4.0
# Save as client.mjs, set CARTRELAY_KEY privately,
# and run: node client.mjs
import { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';
const client = new Client({name: 'cartrelay-reference', version: '1.0.0'});
// Complete origin-derived example appears with JavaScript enabled.
Use only documented transport modes reported by the service. See MCP protocol documentation ↗.
Five tools. Two agent entry points.
Every commerce route requires delegated Bearer authentication; browser cookies cannot substitute. Success envelope: {ok:true,data:{…}}. Context: {country:"CA",currency:"CAD",postal_code?:string}. CAD is a preference, not a conversion. Prices are {amount:integer_minor,currency:string} or null; preserve their currency exponent.
| Tool / REST route | Request | Response data |
|---|---|---|
cartrelay_search POST /api/v1/search | {query,context,max_price_minor?,limit?} | {products,pagination:{cursor,has_next_page},notices,source,fetched_at} |
cartrelay_detail POST /api/v1/detail | {id,context,selected?:[{name,label}]} | Same discovery envelope with exact offers. |
cartrelay_price_stock POST /api/v1/price-stock | {ids:[id],context} | Same envelope with current permitted offer facts. |
cartrelay_cart_create POST /api/v1/cart | {lines:[{id:exact_variant_id,quantity:1..12}],context} | {cart_token,review_url,expires_at,items:[{id,quantity,product_title,image_url?:string|null,offer|null}],notices,not_a_reservation:true} |
cartrelay_checkout_handoff POST /api/v1/handoff | {cart_token,approval:true}; requires recorded human approval for the reviewed token. | {review_required,groups:[{merchant|null,items,links}],notices,commission_tracked:false,purchase_completed:false} |
Product and exact-offer shape
{
id, title, url, image_url,
offers: [{
id, title, price: {amount, currency} | null,
available: true | false | null, availability_status,
options: [{name, label}],
merchant: {name, id, domain, url, policy_links} | null,
retailer_url, quantity_link_support, missing_facts
}],
options: [{name, values: [string]}],
description_inferred, missing_facts
}
Cart and handoff offers, and group merchants, can be null. Preserve unresolved exact references visibly; do not silently remove or substitute them. Group items add changed and unavailable. Group links are {id,url,label,quantity,quantity_link_support:"one_item_only"|"unknown"}. Support defaults to unknown: a link may open one item only and may not set your quantity; no support is asserted as proven.
GET /api/contracts is public metadata: no delegated key, browser cookie or operator login is required. It exposes concrete input and output schemas for the proposed v1 contract. Current live schemas, authentication and owner/consent checks are authoritative.
GTINfetch identity evidence, not another storefront
POST /api/v1/identity is an explicit, optional agent lookup using the same delegated Bearer key; a browser cookie alone is denied. The five MCP tools and GET /api/contracts remain unchanged. GET /api/identity/contracts is separate public input/output schema metadata, requiring no key, cookie or operator access. The existing capability check and /api/status describe the Shopify commerce provider only, not GTINfetch availability.
Supply a complete GTIN explicitly obtained by the agent or from a permitted source for the exact variant and pack. Do not infer it from titles, brand similarity or partial barcodes. No automatic Shopify barcode extraction or barcode availability is claimed. Strict input: {gtin:string,market?:string}, no extra keys. GTINs must have a genuine valid check digit and 8, 12, 13 or 14 digits; surrounding whitespace is trimmed, all-zero values are rejected, and accepted values are padded to 14 digits. This is syntactic validation, not GS1 registration or product-association verification. Market, if present, is exactly two uppercase letters such as CA or UK; omission becomes null.
Agent request — securely injected credential
Use the actual CartRelay origin and inject CARTRELAY_KEY privately through your trusted client or secret environment. Never hardcode or share raw credentials, put them in briefs or log keys/records. This illustrative GTIN is not permission to associate it with an unrelated offer.
POST /api/v1/identity
Authorization: Bearer <securely injected delegated key>
Content-Type: application/json
{"gtin":"626027814026","market":"CA"}
Exact response envelope
{ok:true,data:{
provider:'gtinfetch', status:'available'|'unknown'|'unavailable',
gtin14:string, market:string|null, fetched_at:ISO_date_time,
signature_verified:boolean, record:original_full_signed_JSON|null,
code:string|null, retry_after:positive_integer_seconds_up_to_3600|null,
notices:string[]
}}
available and unknown return the complete, unmodified signed source record only after detached Ed25519 verification against the fixed public JWKS. Both have signature_verified:true; available has code:null, while unknown has no observations and code:"NO_OBSERVATION". Missing fields stay missing. Verification proves origin/integrity relative to the keyring, not accuracy, freshness, GS1 registration or product association. Unavailable returns record:null, signature_verified:false and one of SOURCE_UNAVAILABLE, SOURCE_TIMEOUT, SOURCE_RATE_LIMITED, SOURCE_BUSY, INVALID_SOURCE_RESPONSE or SIGNATURE_UNVERIFIED.
A valid request with unknown/unavailable evidence returns HTTP 200 with explicit status/code, not a fabricated record. Invalid input is 400, invalid/missing Bearer authentication 401 and local quota violations 429. Honor nullable retry_after and notices without aggressive retries or polling. record.fields.product, brand, category and pack may exist as source metadata. Preserve exact field attribution/product links, licences, dates, confidence, conflicts, original signature and full signed JSON; any normalized fields are separately labelled derived data, not provider truth. Source text and URLs are untrusted data: no HTML insertion, prompt-instruction execution, automatic URL fetching or checkout authority.
Fixed free path, bounded and request-local
Only the fixed free GTINfetch REST source is used: no payment, x402, wallet, paid fallback or paid gate. Overall budget is five seconds; identity limits are six calls per session/minute, the existing shared agent budget of 24/minute and 300/day, global 30/minute and two concurrent source calls per instance. Maximum source record is 128 KiB, keyring 16 KiB. Only public keys may be cached in memory for 15 minutes. There is no product-record cache, storage, record logging, catalogue accumulation, scheduled refresh or background timer; responses are no-store.
No identity call is made inside Shopify, search, detail, price-stock, showcase, cart, review or handoff. GTINfetch is not an offer provider or Canadian stock, shipping or safety evidence; a market tag is not availability and no recall field is not a safety clearance. It provides no approval and cannot mutate a cart. Human consent, exact-variant resolution and fresh offer rechecks remain unchanged. No partnership solicitation, outreach or automatic approval is part of this feature.
Privacy and licences still apply
GSC-operated GTINfetch receives the normalized GTIN and optional market as lookup data, not your CartRelay key, cookie, postal code or brief. Ordinary network metadata remains subject to the recipient's policies. The provider may queue a market-tagged miss as a sourcing lead under its own terms; CartRelay does not initiate outreach. Your agent client's own retention policy also applies.
Carry the exact field source/product link and licence in client displays and downstream API use, not just a generic GTINfetch credit. Open Food Facts database material is ODbL 1.0, with individual contents under DbCL 1.0. Nudger's reference distribution is ODbL; a specific mirror/version may be CC BY 4.0. Establish the actual contributing version rather than choosing the least restrictive label. Record licence notices are not blanket retention/republication permission, and memory-only use is not a licence exemption; attribution and any applicable public-use/share-alike obligations remain. A durable merged product spine, retained normalization, copied images and descriptions remain excluded pending rights assessment. The full signed record is passed through as evidence, not permission to extract or display its media.
GTINfetch homepage ↗ · GSC terms ↗ · Open Food Facts terms ↗ · ODbL 1.0 ↗ · DbCL 1.0 ↗ · Nudger reference dataset ↗ · Specific CC BY-labelled distribution ↗ · Privacy · Terms
Human consent, not browser commerce
The agent-created review_url uses /review#cart=<token>. The fragment keeps the intent out of HTTP URL logs. Open it in the browser whose shopper cookie owns the delegated agent key. The page reads the fragment into memory and immediately erases it using history replacement. A new agent link that changes the fragment in the same open document clears the old local review, cancels pending browser requests and loads the new token with fresh unchecked consent; prior local consent does not transfer. Cancellation does not undo consent already processed by the service for an older intent. Never persist tokens, put them in query parameters or share them with support.
POST /api/review/open
# Browser cookie + X-CartRelay-CSRF
{"cart_token":"<agent-issued-token>"}
{ok:true,data:{
cart_token, expires_at,
items:[{id,quantity,product_title,image_url?:string|null,offer|null}],
notices, not_a_reservation:true
}}
The returned token represents freshly resolved exact offers. Human approval must use that new returned token, not the original fragment token. The page has no discovery, manual variants, quantity editing, new product IDs or generic cart creation. Its explicit checkbox authorizes retailer handoff, not a purchase.
POST /api/review/approve
# Same owning browser cookie + X-CartRelay-CSRF
{"cart_token":"<new-returned-token>","approval":true}
{ok:true,data:{
review_required,
groups:[{merchant:null|{…},items:[{id,quantity,product_title,image_url?:string|null,
offer:null|{…},changed,unavailable}],
links:[{id,url,label,quantity,quantity_link_support}]}],
notices, commission_tracked:false, purchase_completed:false
}}
Tokens are independently signed with a server-held secret, not derived from a guest cookie. The server records an opaque human approval hash scoped to owner and expiry, then rechecks source price, availability, exact variants, merchant and link fingerprints. Changed fingerprints require renewed review. Changed, missing or unknown current selections withhold all retailer action links. Ask the agent to revise and send a new review link; no source fallback or manual shopping is offered. Wrong browser, missing token and expired intents remain locked. Successful consent only releases permitted source-returned retailer links. Confirm exact variant, quantity, currency, final price, taxes, shipping and payment there. Leaving the review page clears token/response memory and rendered source details; refresh requires a fresh agent link.
Live source. No copied catalog.
The homepage has one explicit limited-preview exception: GET /api/showcase resolves four fixed references with a fresh batch lookup and no query/ref/cursor parameters. It returns source-listed titles, variants, direct merchant-image URLs, seller attribution and actual-currency prices; no checkout/action links. Responses are no-store and globally limited to ten requests per minute to preserve source capacity for agents. Images render in real time with their related listings and are not downloaded or rehosted. The card CTA starts a local agent brief; commerce, intent creation and retailer handoff still require authenticated agent tools and independent human consent.
Shopify Global Catalog is the first outbound provider. Agents query a bounded live source for a current shopper intent; CartRelay retains no permanent product index, retailer descriptions, image copies, source-result bodies or price snapshots. Source imagery, when used by clients, must be externally hosted and accompanied by merchant attribution. The human review page displays source photos and returned facts and releases retailer navigation only after consent and recheck.
Catalog and credential responses use Cache-Control: no-store. Do not cache or persist provider payloads, bulk harvest, log raw keys or tokens, or export a copied catalog. Keep offer details request-local or transient. Four stored homepage references are configuration for fresh lookup, not a retained catalog. CartRelay-owned storage includes hashed credentials, rates, minimal operational outcomes, opaque approval hashes and submitted support requests, not catalog tables.
Unknown stock, shipping, ingredients, certifications and pack sizes stay unknown; inferred descriptions are not verified evidence. Preserve currencies; never relabel USD as CAD, invent FX or total mixed currencies as a single quote. Retailers handle checkout, payment, fulfillment and returns. No stock is reserved, no universal merchant cart is created and no commission tracking is enabled.
Expired credential and approval state is removed by daily cleanup. Application-database support and operational records are deleted after 30 days on the next daily run (up to 31 days). App cleanup does not delete email/message copies delivered in owner notifications; owner inboxes and notification providers follow separate retention policies. Request operator help for those copies through a privacy request. Native retention registration and own-profile source verification follow deployment; documentation is not evidence that they succeeded.
Shopify source documentation ↗ · CartRelay public capability profile · Privacy · Terms
Errors, management & limits
Error envelope: {ok:false,error:{code,message,retry_after?}}. Application errors use JSON, including 401 with WWW-Authenticate: Bearer realm="CartRelay". A plain-text/HTML unauthorized response without the application envelope is not evidence of a CartRelay key-scope error; capture your client/runtime, exact method/path, response Content-Type and response headers (never keys/tokens) for support. Successful standard Node REST checks do not establish support for every proxy or runtime. Statuses: 400 invalid input, 401 unauthenticated/expired, 403 forbidden/CSRF/wrong owner, 404 missing resource, 409 conflict/changed state, 429 rate limited, 502 source failure, 503 unavailable. Honor retry_after; no aggressive retries or unattended catalog polling. Limits and current tool input schemas are enforced by the service.
POST /api/agent-keys {label} reveals {id,raw_key,prefix,expires_at} once. GET /api/agent-keys lists {keys:[{id,label,prefix,expires_at,revoked,last_used_at,calls}]}. DELETE /api/agent-keys/:id revokes only the owning guest's key. Browser mutations require CSRF.
POST /api/support {email,message,kind:"support"|"privacy"} returns {reference,notification_accepted}. GET /api/status reports configuration and verification, not retail coverage or product discovery. The locked operator area requires verified identity and separate exact owner authorization. Missing source data is never replaced with demo products. Use support when setup is unavailable.