Developer Documentation

Integrate with The Store using REST, ACP, UCP, MCP, or TAP.

Quickstart

Want to shop with an AI agent? Follow the customer-facing Claude Code guide for our verified setup. The same MCP endpoint is available to Codex, OpenCode, Hermes Agent, OpenClaw, and other compatible clients. The rest of this page is an implementation reference for integration developers.

The Store exposes multiple interfaces on a single deployment:

  • SSH (port 2222) — Human TUI experience
  • HTTP (port 3000) — REST API, ACP, UCP, and webhooks
  • MCP (port 8080) — Model Context Protocol server for LLM tool use

All prices are in cents (integer). $9.99 = 999.

Browse products (no auth required)

curl https://storeapi.globalringai.com/api/v1/products

Filter by category or search

# By category
curl "https://storeapi.globalringai.com/api/v1/products?category=Software"

# By keyword
curl "https://storeapi.globalringai.com/api/v1/products?q=keycap"

# In-stock only
curl "https://storeapi.globalringai.com/api/v1/products?in_stock=true"

Authenticated development access

Production API keys are issued by The Store operator with a fixed role, exact scopes, budget, and expiration. Public self-service key creation is not available. The local --gen-api-key command is an operator-only development utility and is not a customer onboarding path.

Authentication

Pass your API key via the Authorization header:

Authorization: Bearer ${THESTORE_BUYER_TOKEN}

Scopes

ScopeGrants
cart:readGet cart contents
cart:writeCreate sessions, add/update/remove items
checkout:writeCreate checkouts, ACP/UCP sessions
orders:readList and view orders

Budget Controls

API keys can have spending limits. Budget is checked at checkout and incremented when payment completes (via webhook for Stripe, immediately for SPT).

FieldDescription
budget_limitMax spend in cents per period (null = unlimited)
budget_spentRunning total of completed transactions
budget_perioddaily, weekly, monthly, or lifetime
categoriesOptional category restrictions (empty = unrestricted)

Error Format

All endpoints return errors in a standard envelope:

{
  "error": {
    "code": "not_found",
    "message": "Product not found"
  }
}
HTTPCodeMeaning
400invalid_requestBad JSON, missing fields, invalid state
401unauthorizedMissing/invalid API key or signature
403forbiddenMissing scope, wrong owner, or budget exceeded
404not_foundResource not found
405method_not_allowedWrong HTTP method
409out_of_stockInsufficient inventory
500internal_errorServer error

REST API

Session-based shopping for HTTP clients. Base path: /api/v1

Quickstart: Place an Order

# 1. Browse products (no auth)
curl https://storeapi.globalringai.com/api/v1/products

# 2. Create a session
curl -X POST -H "Authorization: Bearer tsk_..." \
  https://storeapi.globalringai.com/api/v1/sessions

# 3. Add to cart (use session_id from step 2 and copy a product id/tspn from step 1)
curl -X POST -H "Authorization: Bearer ***" \
  -H "Content-Type: application/json" \
  -d '{"product_id": "TSPN-...", "quantity": 1}' \
  https://storeapi.globalringai.com/api/v1/sessions/{session_id}/cart/items

# 4. Checkout
curl -X POST -H "Authorization: Bearer tsk_..." \
  -H "Content-Type: application/json" \
  -d '{"email": "buyer@example.com"}' \
  https://storeapi.globalringai.com/api/v1/sessions/{session_id}/checkout

# Response includes checkout_url — open in browser to pay

Catalog (Public)

MethodEndpointDescription
GET/api/v1/productsList products. Query params: category, q, in_stock
GET/api/v1/products/{id}Get product details

Sessions & Cart

MethodEndpointScopeDescription
POST/api/v1/sessionscart:writeCreate shopping session
GET/api/v1/sessions/{id}/cartcart:readGet cart contents
POST/api/v1/sessions/{id}/cart/itemscart:writeAdd item. Body: {"product_id", "quantity"}
PUT/api/v1/sessions/{id}/cart/items/{pid}cart:writeUpdate quantity. Body: {"quantity"}
DEL/api/v1/sessions/{id}/cart/items/{pid}cart:writeRemove item

Checkout & Orders

MethodEndpointScopeDescription
POST/api/v1/sessions/{id}/checkoutcheckout:writeInitiate checkout. Body: {"email", "name", "shipping_address"} (all optional)
GET/api/v1/accountanyGet API key info, budget, scopes
GET/api/v1/ordersorders:readList orders (most recent 50)
GET/api/v1/orders/{id}orders:readGet order details

Response Shapes

Success responses are wrapped in {"data": {...}}. Key shapes:

// Product
{"id", "tspn", "name", "type", "price", "price_currency", "price_formatted",
 "description", "category", "stock", "stock_status", "in_stock"}

// Cart
{"session_id", "items": [{"product_id", "name", "price", "price_currency",
 "price_formatted", "quantity", "subtotal"}],
 "total", "price_currency", "total_formatted", "item_count"}

// Checkout
{"order_id", "checkout_url", "total", "total_formatted"}

// Order
{"order_id", "email", "total", "price_currency", "total_formatted", "status",
 "items": [{"product_id", "name", "price", "price_currency",
 "price_formatted", "quantity", "subtotal", "subtotal_formatted"}],
 "created_at"}

Agent Commerce Protocol (ACP)

Single-session checkout for AI agents with line items, fulfillment, and budget tracking. Base path: /acp/v1

Quickstart: Agent Checkout with Stripe

# 1. Create checkout session
curl -X POST -H "Authorization: Bearer ***" \
  -H "Content-Type: application/json" \
  -d '{
    "line_items": [{"product_id": "PRODUCT_ID", "quantity": 2}],
    "customer_email": "agent@example.com"
  }' \
  https://storeapi.globalringai.com/acp/v1/checkout_sessions

# 2. After reviewing the authoritative quote, complete without a token
curl -X POST -H "Authorization: Bearer ***" \
  -H "Content-Type: application/json" \
  -d '{}' \
  https://storeapi.globalringai.com/acp/v1/checkout_sessions/{id}/complete

# Response: status "awaiting_payment", checkout_url for Stripe
# Payment confirmed asynchronously via webhook

Endpoints

MethodEndpointDescription
POST/acp/v1/checkout_sessionsCreate session with line items
GET/acp/v1/checkout_sessions/{id}Get session state
POST/acp/v1/checkout_sessions/{id}Update (items, address, shipping, customer)
POST/acp/v1/checkout_sessions/{id}/completeCreate Stripe Checkout or consume a separately issued approval
POST/acp/v1/checkout_sessions/{id}/cancelCancel session

All endpoints require checkout:write scope.

Session Lifecycle

                      ┌──────────────────┐
        Digital items  │ ready_for_payment │  Physical items
        ──────────────►│                  │◄────────────────
                       └────────┬─────────┘   (after address
                                │              provided)
                 ┌──────────────┼──────────────┐
                 │              │              │
       signed approval     no token        cancel
                 │              │              │
                 ▼              ▼              ▼
            completed    awaiting_payment   canceled
                              │
                         webhook confirms
                              │
                              ▼
                          completed

Physical goods start as not_ready_for_payment until a fulfillment address is provided via update.

Create Request

{
  "line_items": [                    // required, at least 1
    {"product_id": "...", "quantity": 1}
  ],
  "customer_email": "...",           // optional
  "customer_name": "...",            // optional
  "currency": "usd"                 // optional, default "usd"
}

Update Request

{
  "line_items": [...],               // optional, replaces items
  "fulfillment_address": {           // optional, for physical goods
    "name": "...", "line1": "...", "line2": "...",
    "city": "...", "state": "...", "zip": "...", "country": "..."
  },
  "selected_fulfillment": "express", // optional: "standard" ($5) or "express" ($15)
  "customer_email": "...",           // optional
  "customer_name": "..."             // optional
}

Session Response

{
  "id": "uuid",
  "status": "ready_for_payment",
  "line_items": [{"product_id", "name", "description",
                  "quantity", "unit_price", "currency"}],
  "fulfillment_address": null | {...},
  "fulfillment_options": [
    {"id": "standard", "label": "Standard Shipping (5-7 days)", "cost": 500, "currency": "usd"},
    {"id": "express", "label": "Express Shipping (2-3 days)", "cost": 1500, "currency": "usd"}
  ],
  "selected_fulfillment": null | "standard" | "express",
  "customer_email": "...",
  "customer_name": "...",
  "totals": {"subtotal": 999, "tax": 0, "shipping": 0, "total": 999, "currency": "usd"},
  "order_id": null,
  "checkout_url": null,
  "created_at": "2026-...",
  "expires_at": "2026-..."   // 1 hour from creation
}

Payment authorization

Ordinary user-present checkout omits payment_token and returns secure Stripe Checkout. Delegated completion requires a real, short-lived authorization issued through The Store's separately authenticated approval flow and bound to the exact current checkout snapshot. Example token strings are intentionally not published because they would not be valid authorizations.

Optional: HMAC Signature

If ACP_HMAC_SECRET is configured, all requests must include:

Signature: hex(HMAC-SHA256(request_body, secret))

Unified Commerce Protocol (UCP)

Standardized checkout with service discovery. Base path: /ucp/v1

Quickstart: Discover and Checkout

# 1. Discover capabilities
curl https://storeapi.globalringai.com/.well-known/ucp

# 2. Browse the canonical catalog and copy the selected variant's id/tspn
curl -H "Authorization: Bearer ***" \
  "https://storeapi.globalringai.com/api/v1/products?in_stock=true"

# 3. Create session using that canonical variant identifier
curl -X POST -H "Authorization: Bearer ***" \
  -H "Content-Type: application/json" \
  -d '{
    "line_items": [{"product_id": "TSPN-...", "quantity": 1}],
    "customer_email": "agent@example.com"
  }' \
  https://storeapi.globalringai.com/ucp/v1/checkout-sessions

# 4. Add shipping (physical good)
curl -X PUT -H "Authorization: Bearer tsk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "fulfillment_address": {"line1": "123 Main St", "city": "Portland", "state": "OR", "zip_code": "97201", "country": "US"},
    "selected_fulfillment": "standard"
  }' \
  https://storeapi.globalringai.com/ucp/v1/checkout-sessions/{id}

# 5. After reviewing the quote, create secure Stripe Checkout
curl -X POST -H "Authorization: Bearer ***" \
  -H "Content-Type: application/json" \
  -d '{}' \
  https://storeapi.globalringai.com/ucp/v1/checkout-sessions/{id}/complete

Discovery Manifest

GET /.well-known/ucp

{
  "version": "1.0",
  "name": "The Store",
  "description": "A cyberpunk e-commerce store...",
  "services": [{"type": "checkout", "base_url": "/ucp/v1/checkout-sessions"}],
  "capabilities": [
    "checkout.create", "checkout.update",
    "checkout.complete", "checkout.cancel",
    "fulfillment.address", "fulfillment.options"
  ]
}

Endpoints

MethodEndpointDescription
GET/.well-known/ucpDiscovery manifest (no auth)
POST/ucp/v1/checkout-sessionsCreate session
GET/ucp/v1/checkout-sessions/{id}Get session state
PUT/ucp/v1/checkout-sessions/{id}Update session
POST/ucp/v1/checkout-sessions/{id}/completeFinalize (SPT or Stripe)
POST/ucp/v1/checkout-sessions/{id}/cancelCancel session

Key Differences from ACP

AspectACPUCP
Base path/acp/v1/checkout_sessions/ucp/v1/checkout-sessions
Update methodPOSTPUT
Address zip fieldzipzip_code
Money formatFlat: "subtotal": 999Nested: "subtotal": {"amount": 999, "currency": "usd"}
Status namesready_for_paymentready_for_complete
HMAC headerSignatureRequest-Signature
DiscoveryNone/.well-known/ucp

UCP Status Mapping

InternalUCP Status
not_ready_for_paymentincomplete
ready_for_paymentready_for_complete
awaiting_paymentrequires_escalation
completedcompleted
canceledincomplete

Model Context Protocol (MCP)

Native LLM tool integration via JSON-RPC 2.0 over authenticated Streamable HTTP.

Invite-only beta MCP client setup

Claude Code is the currently verified client. Invited buyers using Claude should follow the complete Shop with Claude guide. The verified configuration command is:

claude mcp add --scope user --transport http thestore \
  https://storemcp.globalringai.com/ \
  --header 'Authorization: Bearer ${THESTORE_BUYER_TOKEN}'

The environment-variable reference is stored literally. Launch Claude with the variable loaded from your protected credential file; never paste the raw value into this command or into Claude chat.

Codex, OpenCode, Hermes Agent, OpenClaw, and other MCP-compatible clients can connect to https://storemcp.globalringai.com/ with the same issued bearer credential. Use the client’s documented mechanism for an authenticated Streamable HTTP MCP server, and keep the raw credential in a protected file or process environment rather than pasting it into chat or source control.

The invite-only beta requires its issued buyer token at the MCP transport boundary. Missing or incorrect credentials receive 401 Unauthorized. Public OAuth and browser consent are not implemented yet.

Configuration

Env VarRequiredDescription
Authorization request headerYesCaller-specific buyer bearer; the MCP server forwards the same identity to The Store
THESTORE_API_URLNoStore API base URL (default: http://localhost:3000)
MCP_PORTNoListen port (default: 8080)

Advanced tool reference (19)

Ordinary shoppers should not need these names. The MCP server instructs the connected agent to search, compare, collect only missing delivery information, present an authoritative quote, wait for explicit confirmation, open Stripe Checkout, and report verified order status.

CategoryToolInput
Catalogsearch_productscategory?, query?
get_productproduct_id
Shoppingcreate_session(none)
add_to_cartsession_id, product_id, quantity?
view_cartsession_id
checkoutsession_id, email?, name?, shipping_address?
get_orderorder_id
get_account(none)
list_orders(none)
ACPacp_create_sessionline_items, email?, name?, currency?
acp_get_sessionsession_id
acp_update_sessionsession_id, line_items?, customer_email?, customer_name?
acp_complete_sessionsession_id, payment_token?
acp_cancel_sessionsession_id
UCPucp_create_sessionline_items, email?, name?, currency?
ucp_get_sessionsession_id
ucp_update_sessionsession_id, line_items?, customer_email?, customer_name?
ucp_complete_sessionsession_id, payment_token?
ucp_cancel_sessionsession_id

Resources

URITypeDescription
thestore://catalogStaticFull product catalog as Markdown
thestore://products/{id}TemplateSingle product details as JSON

Prompts

NameArgsDescription
shopping_assistanttask?Pre-built shopping assistant with inventory context and all tool references

Trusted Agent Protocol (TAP)

Optional RFC 9421 HTTP message signatures for cryptographic request authentication. TAP is additive — requests without TAP headers pass through normally. Invalid signatures get 401.

Quickstart: Sign a Request

# 1. Place your Ed25519 public key PEM in the TAP keys directory:
#    $TAP_KEYS_DIR/my-agent.pem

# 2. Enable TAP on the server:
#    TAP_ENABLED=true TAP_KEYS_DIR=/app/tap-keys

# 3. Sign your request with these headers:
Signature-Input: sig1=("@method" "@target-uri" "content-type");\
  created=1709000000;keyid="my-agent";alg="ed25519";\
  nonce="unique-value-123"
Signature: sig1=:base64-ed25519-signature:

Signature Construction

Build the canonical signature base, then sign with Ed25519:

# Signature base (one line per component + params):
"@method": POST
"@target-uri": https://storeapi.globalringai.com/api/v1/orders
"content-type": application/json
"@signature-params": ("@method" "@target-uri" "content-type");\
  created=1709000000;keyid="my-agent";alg="ed25519";nonce="abc123"

Signable Components

ComponentValue
@methodHTTP method (GET, POST, etc.)
@target-uriFull URI with scheme and host
@pathPath component only
@authorityHost header
@schemehttp or https
@request-targetPath + query string
Any header nameHeader value (e.g. "content-type")

Validation Rules

  • Timestamp skew: ±8 minutes
  • Nonce replay: Rejected if seen within 16-minute window
  • Algorithm: ed25519 only
  • Key format: PEM-encoded Ed25519 public keys, filename = key ID

Configuration

Env VarDescription
TAP_ENABLEDtrue to enable TAP middleware
TAP_KEYS_DIRDirectory of {keyid}.pem files

Identity Injection

After successful verification, a TAPIdentity is injected into the request context with KeyID, Tag, Algorithm, and Verified=true. Handlers can use this for additional authorization decisions.

x402 Payment Protocol

x402 checkout settlement is not available in this release. User-present purchases use secure Stripe Checkout. The Store will not advertise or accept x402 order payment until settlement is bound atomically to an authoritative quote and resulting order.

Webhooks

MethodEndpointEvents
POST /webhook/stripe checkout.session.completed, checkout.session.expired

Paid checkout.session.completed

Finalization occurs only when Stripe reports payment_status=paid and the signed amount and currency match the immutable local order.

  1. Order status: pendingpaid
  2. Product stock decremented
  3. API key budget_spent incremented
  4. Linked ACP/UCP session: awaiting_paymentcompleted
  5. Real-time event published to connected TUI sessions

checkout.session.expired

  1. Order status: pendingexpired
  2. No stock or budget changes
  3. Event published to TUI sessions

Protocol Comparison

Feature REST ACP UCP MCP TAP
PurposeShoppingAgent checkoutUnified checkoutLLM toolsRequest signing
AuthAPI KeyAPI Key + HMAC?API Key + HMAC?API KeyEd25519 sig
PaymentStripeStripe / separate approvalStripe / separate approvalvia ACP/UCPN/A
FulfillmentNoYesYesvia ACP/UCPN/A
BudgetAt checkoutYesYesYesN/A
DiscoveryNoNo.well-knownTool listN/A