Platform Spoke · BigCommerce
Spoke · Make Your Platform Agent-Ready

BigCommerce + Agentic Commerce — The Integration Playbook.

BigCommerce is the open, API-first platform of the mid-market — and the agent-readiness story is more developer-shaped than Shopify's. The Stencil theme emits a thin Product + Offer + BreadcrumbList JSON-LD that you must extend. The v3 REST and GraphQL Storefront APIs already cover all eight canonical agent endpoints — generously, at 450 requests per 30 seconds on Pro. The native BigCommerce Storefront MCP is in AI Labs Developer Beta as of September 2025, so you ship a custom Python MCP wrapper today. And UCP-style autonomous checkout lands cleanly through the open-source checkout-js fork plus Stripe's Agentic Commerce Suite — with BigCommerce as a named partner platform.

4
Layers to Close
450/30s
Pro API Rate Limit
MCP Beta
Sept 2025 · AI Labs
Stripe SPT
Named ACS Partner
§1 · The Mid-Market Reality

Four layers. One open platform. One MCP wrapper you ship yourself.

BigCommerce sits in the agentic-commerce conversation as the open, programmable mid-market alternative — the platform Etsy graduates and Shopify Plus churners benchmark against. Three of the four agent-readiness layers are already in the box on every plan: Cornerstone (the default Stencil theme) emits a baseline Product + Offer + BreadcrumbList JSON-LD via the templates/components/products/schema.html Handlebars partial; the v3 REST and GraphQL Storefront APIs already cover all eight canonical agent endpoints with X-Auth-Token auth; the open-source checkout-js (github.com/bigcommerce/checkout-js) plus the Stripe Agentic Commerce Suite — naming BigCommerce as a partner platform — gives you a UCP-style autonomous checkout path. The one layer you ship yourself this month is MCP: BigCommerce's native Storefront MCP is in AI Labs Developer Beta as of September 2025 and is not yet generally available (re-verify before launch). Your build is to extend the schema, wire the API, ship a Python MCP wrapper, and register an Agent Commerce channel so every agent-driven order is attributable in your analytics. The four BigCommerce facts that separate this spoke from Shopify and WooCommerce: native gtin product field, generous v3 rate limits, MCP beta status, and Stripe Shared Payment Tokens as the cleanest autonomous-checkout path.

§2 · The 4-Layer Model on BigCommerce

What you build on top of what BigCommerce already gives you.

The full agent-readiness model is documented on the AgentMall Roadmap. On BigCommerce, three of the four layers ship in the box but each needs an extension. The MCP layer is where you do real work this month.

Layer 1 · Schema

Structured Data via Stencil

Cornerstone auto-emits Product + Offer + BreadcrumbList from schema.html. You extend with gtin (native field), mpn, hasMerchantReturnPolicy, shippingDetails, aggregateRating. See Product Data for the field reference.

Layer 2 · API

v3 REST + GraphQL Storefront

v3 REST at api.bigcommerce.com/stores/{hash}/v3/ covers all eight canonical endpoints under X-Auth-Token. Generous rate limits: Pro 450 req/30s. GraphQL Storefront for headless reads. See API Endpoint for the canonical surface.

Layer 3 · MCP

Custom Python Wrapper · Native Beta

BigCommerce Storefront MCP is AI Labs Developer Beta (Sept 2025) — not GA. Until GA, ship the Python FastMCP server in this spoke. Eight tools wired to v3 REST. See MCP for the protocol overview.

Layer 4 · UCP

checkout-js + Stripe SPT

Open-source checkout-js forkable on Plus+. Eight-step headless checkout via Checkout SDK. Stripe Agentic Commerce Suite names BigCommerce as partner — Shared Payment Tokens = autonomous path. See UCP.

Why This Order Matters

Schema is the discovery layer — without it, agents cannot find or rank your products. The API is the transaction layer — without it, they cannot buy. MCP is the negotiation layer — without it, every agent runtime has to write your API integration itself, every time. UCP is the standardization layer — without it, autonomous checkout becomes a custom Stripe integration for every agent partner. Build them in order on BigCommerce: extend Stencil first, then create v3 credentials, then ship the MCP wrapper, then choose your checkout path.

Layer 1 · Structured Data

Stencil JSON-LD: extend schema.html, fill agent_commerce metafields.

Cornerstone — the default Stencil theme — emits a JSON-LD block on product pages via the Handlebars partial at templates/components/products/schema.html. It covers @type: Product with name, description, image, brand, sku, and an @type: Offer with price, priceCurrency, availability, url, plus a BreadcrumbList. That satisfies Google's minimum Product rich-result requirements — and stops there. Google AI Overviews and AI shopping agents treat the absence of gtin, hasMerchantReturnPolicy, and shippingDetails as a disqualifying signal. The fix is a single extended Handlebars partial plus matching v3 product metafields in an agent_commerce namespace.

What Cornerstone auto-emits (and what it leaves out)

Open templates/components/products/schema.html in the Stencil CLI or the Theme Editor and you will find the default partial. The output is valid JSON-LD but minimal: no gtin emission, no mpn, no hasMerchantReturnPolicy, no shippingDetails, no aggregateRating, no item dimensions. Validate the live page once at Google's Rich Results Test and you will see exactly which fields Google flags.

The 20-field MVP — what to add

FieldSourceBigCommerce LocationStatus
@typeSchema.orgHandlebars literalAuto
name{{product.title}}Product detailAuto
description{{product.description}}Product detailAuto
image{{product.images}}Product mediaAuto
brand{{product.brand.name}}Brand recordAuto
sku{{product.sku}}Product/variantAuto
price{{product.price.without_tax.value}}Product/variantAuto
priceCurrency{{currency_selector.active_currency_code}}Store settingsAuto
availability{{product.stock_level}}InventoryAuto
url{{product.url}}ComputedAuto
gtin{{product.gtin}}Native product fieldPopulate
mpn{{product.mpn}}Native product fieldPopulate
itemCondition{{product.condition}}Native product fieldPopulate
aggregateRating.ratingValue{{product.rating}}Stencil contextPopulate
aggregateRating.reviewCount{{product.num_reviews}}Stencil contextPopulate
hasMerchantReturnPolicyCustom field or metafieldcustom_fields.return_days or agent_commerce.return_policyAdd
shippingDetailsHandlebars literal + productSnippetAdd
weight{{product.weight}}Native product fieldPopulate
depth / width / height{{product.depth}} etc.Native product fieldPopulate
seller{{settings.store_name}}Store settingsAdd
BigCommerce-only · Native gtin Field

Unlike Shopify (which stores GTIN in variant.barcode) and WooCommerce (which uses global_unique_id as of recent core versions), BigCommerce has a first-class native gtin product field. Reference it directly as {{product.gtin}} in the Handlebars partial and pull it as product.gtin from the v3 catalog API. No theme hack, no metafield workaround required. This is the cleanest GTIN story of any major commerce platform.

The extended schema.html Handlebars partial

Replace the default contents of templates/components/products/schema.html with the partial below. It pulls native product fields where Stencil exposes them and uses custom fields plus metafields for anything not in the default context. Push the theme via Stencil CLI (stencil push) or upload via the Theme Editor.

<script type="application/ld+json">
{
  "@context": "https://schema.org/",
  "@type": "Product",
  "name": "{{product.title}}",
  "description": "{{product.description}}",
  "sku": "{{product.sku}}",
  "mpn": "{{product.mpn}}",
  "gtin": "{{product.gtin}}",
  "brand": {
    "@type": "Brand",
    "name": "{{product.brand.name}}"
  },
  "image": [
    {{#each product.images}}
    "{{getImageSrcset this use_default_sizes=true}}"{{#unless @last}},{{/unless}}
    {{/each}}
  ],
  "offers": {
    "@type": "Offer",
    "url": "{{product.url}}",
    "priceCurrency": "{{currency_selector.active_currency_code}}",
    "price": "{{product.price.without_tax.value}}",
    "priceValidUntil": "{{product.preorder_release_date}}",
    "availability": "{{#if product.stock_level}}https://schema.org/InStock{{else}}https://schema.org/OutOfStock{{/if}}",
    "itemCondition": "{{#if product.condition}}https://schema.org/{{product.condition}}Condition{{else}}https://schema.org/NewCondition{{/if}}",
    "seller": {
      "@type": "Organization",
      "name": "{{settings.store_name}}"
    },
    "shippingDetails": {
      "@type": "OfferShippingDetails",
      "shippingRate": {
        "@type": "MonetaryAmount",
        "value": "{{#if product.shipping.fixed_shipping_price}}{{product.shipping.fixed_shipping_price.value}}{{else}}0{{/if}}",
        "currency": "{{currency_selector.active_currency_code}}"
      },
      "shippingDestination": {
        "@type": "DefinedRegion",
        "addressCountry": "US"
      },
      "deliveryTime": {
        "@type": "ShippingDeliveryTime",
        "handlingTime": { "@type": "QuantitativeValue", "minValue": 0, "maxValue": 1, "unitCode": "DAY" },
        "transitTime":  { "@type": "QuantitativeValue", "minValue": 3, "maxValue": 7, "unitCode": "DAY" }
      }
    },
    "hasMerchantReturnPolicy": {
      "@type": "MerchantReturnPolicy",
      "returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow",
      "merchantReturnDays": {{#if product.custom_fields.return_days}}{{product.custom_fields.return_days}}{{else}}30{{/if}},
      "returnMethod": "https://schema.org/ReturnByMail"
    }
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "{{product.rating}}",
    "reviewCount": "{{product.num_reviews}}"
  },
  "weight": {
    "@type": "QuantitativeValue",
    "value": "{{product.weight.value}}",
    "unitCode": "{{product.weight.unit}}"
  },
  "depth":  { "@type": "QuantitativeValue", "value": "{{product.depth.value}}",  "unitCode": "{{product.depth.unit}}"  },
  "width":  { "@type": "QuantitativeValue", "value": "{{product.width.value}}",  "unitCode": "{{product.width.unit}}"  },
  "height": { "@type": "QuantitativeValue", "value": "{{product.height.value}}", "unitCode": "{{product.height.unit}}" }
}
</script>
Critical · Re-verify Before Launch

The 3–7 day transit window and the default 30-day return window in the partial are placeholders — replace both with your store's published policy. Both values must match your live shipping and returns pages or Google will flag a structured-data-vs-content mismatch. The shipping schema also supports per-region rates via an array of OfferShippingDetails — extend the partial if your store ships internationally with different policies. Always run the live page through Google's Rich Results Test after every push.

Custom Fields vs Metafields — which to use

BigCommerce has two distinct extensibility mechanisms. Both matter for agent commerce; they are not interchangeable.

MechanismEndpointVisibilityPermissionsUse For
Custom Fields/v3/catalog/products/{id}/custom-fieldsStorefront-visible by default; appear in Stencil as product.custom_fieldsNo permission scopingHuman-facing copy — return window text, warranty summary, trust badges
Product Metafields/v3/catalog/products/{id}/metafieldsAPI-only by default; surface in GraphQL Storefront only with read_and_sf_accessNamespace isolation, app_only / read / write / read_and_sf_access / write_and_sf_accessMachine-readable agent data — gtin override, return_policy JSON, trust_score, agent_tags

For agent commerce, the rule is: metafields with permission_set: "read_and_sf_access" in an agent_commerce namespace for everything machine-readable; custom fields only for human-facing copy you also want surfaced on the storefront.

Create an agent_commerce metafield

curl -X POST \
  "https://api.bigcommerce.com/stores/{store_hash}/v3/catalog/products/{product_id}/metafields" \
  -H "X-Auth-Token: $BC_API_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "namespace": "agent_commerce",
    "key": "return_policy",
    "value": "{\"window_days\": 30, \"restocking_fee\": 0, \"free_return_shipping\": true}",
    "permission_set": "read_and_sf_access",
    "description": "Structured return policy for agent decision-making"
  }'

Each product supports up to 250 metafields per client ID, and the value field accepts up to 65,535 characters — enough to carry a JSON blob describing return policy, trust score, sizing chart URL, agent tags, or any other structured agent payload. The agent_commerce namespace keeps your agent-specific fields isolated from any other app integration that writes to the same product.

Where each data path lives

Data PathMechanismAgent Access
Stencil JSON-LD in page HTMLschema.html Handlebars partialAny agent that reads page HTML
REST Catalog APIGET /v3/catalog/products/{id}Server-side MCP tool
Metafields (read_and_sf_access)REST or GraphQL StorefrontMCP tool or browser-class agent
Custom FieldsREST or Stencil contextMCP tool or page-class agent
GraphQL Storefrontproduct(entityId: N)Headless agent, Catalyst, MCP

The most robust pattern: serve JSON-LD in HTML for passive AI crawlers and use the MCP server (Layer 3) for active agent queries that need real-time inventory and pricing. For the cross-platform field reference that this Stencil partial implements, see the Product Data spoke. Run every change through the Rich Results Test and Schema.org validator before deploying to production.

Layer 2 · API Endpoint

v3 REST for the buyer flow. v2 for order reads. GraphQL Storefront for headless.

BigCommerce exposes three API surfaces relevant to agent commerce: v3 REST at https://api.bigcommerce.com/stores/{store_hash}/v3/ for catalog, carts, checkouts, channels, and payment actions; v2 REST at the same host under /v2/ as the primary path for order reads (the v3 Management API's Orders section primarily covers payment actions and currency); and GraphQL Storefront at https://store-{store_hash}.mybigcommerce.com/graphql for headless and browser-class agent reads. For an agent MCP server operating on behalf of a shopper, v3 REST under X-Auth-Token is the right surface; GraphQL Storefront is for Catalyst or browser-side use.

Auth — pick the right token

TokenWhere CreatedHeaderUse ForNotes
Store-level API account tokenSettings → Store-level API accountsX-Auth-TokenServer-side MCP, backend jobsDoes not expire by time; scope by feature (Catalog, Orders, Checkouts, Carts)
OAuth (marketplace app) tokenBigCommerce App Marketplace installX-Auth-TokenDistributed appsIssued via OAuth flow; rate limiting differs from store-level
GraphQL Storefront API tokenPOST /v3/storefront/api-tokenAuthorization: Bearer ...Browser/CatalystTokens created after June 30, 2026 will no longer support server-to-server use; tokens issued on or before that date keep server-to-server until March 31, 2027 — re-verify before launch
Critical · GraphQL Storefront Token Deprecation

If you are designing an MCP server today and considering GraphQL Storefront for server-to-server reads, do not. The June 30, 2026 deprecation removes server-to-server support for new tokens, and the March 31, 2027 sunset retires legacy server-to-server tokens entirely. Use X-Auth-Token with v3 REST in the MCP server; reserve GraphQL Storefront tokens for browser/Catalyst contexts. Re-verify both dates against the current BigCommerce dev docs before launch.

v3 REST rate limits (re-verified)

PlanQuotaWindowHourly Equivalent
Standard / Core150 req30 seconds~20,000/hour
Plus / Growth150 req30 seconds~20,000/hour
Pro / Scale450 req30 seconds~60,000/hour
Enterprise / PerformanceVaries by plan and resourceRe-verify with account team
Enterprise (Unlimited)No rate limitPhysical infra only

Rate-limit response headers on every v3 call:

X-Rate-Limit-Time-Window-Ms: 30000
X-Rate-Limit-Time-Reset-Ms: 15000
X-Rate-Limit-Requests-Quota: 450
X-Rate-Limit-Requests-Left: 312

On 429 Too Many Requests, read X-Rate-Limit-Time-Reset-Ms and sleep that many milliseconds before retrying. Pro's 450/30s comfortably handles dozens of simultaneous agent sessions — a single product-fetch pipeline rarely exceeds 10–20 requests per session. For comparison: this is materially more generous than Shopify's calculated-cost-per-query model and substantially more headroom than typical mid-market WooCommerce hosts allow.

GraphQL Storefront limits

For browser/Catalyst contexts: each GraphQL Storefront query has a maximum complexity score of 10,000 (returned in the X-Bc-Graphql-Complexity header) and a maximum query depth of 16. Deep queries that fetch a product with every variant, every option, every image, every metafield, and a full reviewSummary in a single request can exceed both. Break into parallel queries or use v3 REST from the MCP server.

The eight canonical agent endpoints — mapped to BigCommerce

The API spoke defines eight canonical endpoints that cover the full agent purchase flow. BigCommerce implements all eight through v3 REST plus v2 for order reads. Map yours from this table.

Canonical EndpointBigCommerce APIPath
list_productsv3 RESTGET /v3/catalog/products
get_product_detailsv3 RESTGET /v3/catalog/products/{id}
search_productsv3 RESTGET /v3/catalog/products?keyword=...
check_availabilityv3 RESTGET /v3/catalog/products/{id}?include_fields=inventory_level,inventory_tracking,availability
initiate_checkout (cart)v3 RESTPOST /v3/carts?include=redirect_urlsPOST /v3/checkouts/{cartId}/consignments
get_order_statusv2 RESTGET /v2/orders/{id}
process_refundv3 RESTPOST /v3/orders/{id}/payment_actions/refund_quotes/refunds
webhook_order_updatesv3 WebhooksPOST /v3/hooks with store/order/* scope

list_products — v3 REST

curl -X GET \
  "https://api.bigcommerce.com/stores/{store_hash}/v3/catalog/products?is_visible=true&include=images,variants&limit=50" \
  -H "X-Auth-Token: $BC_API_TOKEN" \
  -H "Accept: application/json"

get_product — v3 REST

curl -X GET \
  "https://api.bigcommerce.com/stores/{store_hash}/v3/catalog/products/{product_id}?include=images,variants,custom_fields" \
  -H "X-Auth-Token: $BC_API_TOKEN" \
  -H "Accept: application/json"

Key response fields for agent consumption: name, sku, price, sale_price, retail_price, calculated_price, inventory_level, inventory_tracking, availability, gtin, mpn, upc, weight, condition.

search_products — keyword filter

curl -X GET \
  "https://api.bigcommerce.com/stores/{store_hash}/v3/catalog/products?keyword=running+shoes&price_max=80&include=images&limit=20" \
  -H "X-Auth-Token: $BC_API_TOKEN" \
  -H "Accept: application/json"

The keyword param searches name, description, sku, and search_keywords. Additional filter params: price_min, price_max, categories, brand_id, availability, condition, is_featured, is_visible.

check_inventory — and the variant-tracking trap

curl -X GET \
  "https://api.bigcommerce.com/stores/{store_hash}/v3/catalog/products/{product_id}?include_fields=inventory_level,inventory_tracking,availability" \
  -H "X-Auth-Token: $BC_API_TOKEN" \
  -H "Accept: application/json"

If inventory_tracking is "variant", the product-level inventory_level is always 0. Fetch per-variant inventory at /v3/catalog/products/{id}/variants. The check_inventory tool in Layer 3 handles both cases.

create_cart — append redirect_urls

curl -X POST \
  "https://api.bigcommerce.com/stores/{store_hash}/v3/carts?include=redirect_urls" \
  -H "X-Auth-Token: $BC_API_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "customer_id": 0,
    "channel_id": 1,
    "line_items": [
      { "product_id": 118, "quantity": 1, "variant_id": 140 }
    ],
    "currency": { "code": "USD" },
    "locale": "en-US"
  }'

Response includes id (which is also the checkout ID), cartAmount, baseAmount, discountAmount, and — because we appended ?include=redirect_urls — a redirect_urls object with cart_url, checkout_url, and embedded_checkout_url.

initiate_checkout — consignment, shipping, payment access token

The cart ID and checkout ID are the same value. Use it directly against checkout endpoints.

Step A — Create a consignment with the shipping address
curl -X POST \
  "https://api.bigcommerce.com/stores/{store_hash}/v3/checkouts/{cartId}/consignments?include=consignments.available_shipping_options" \
  -H "X-Auth-Token: $BC_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '[{
    "address": {
      "first_name": "Agent",
      "last_name": "User",
      "email": "agent@example.com",
      "address1": "123 Main St",
      "city": "Austin",
      "state_or_province_code": "TX",
      "postal_code": "78701",
      "country_code": "US",
      "phone": "5125551234"
    },
    "line_items": [
      { "item_id": "{lineItemId}", "quantity": 1 }
    ]
  }]'
Step B — Select a shipping option
curl -X PUT \
  "https://api.bigcommerce.com/stores/{store_hash}/v3/checkouts/{cartId}/consignments/{consignmentId}" \
  -H "X-Auth-Token: $BC_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "shipping_option_id": "{shippingOptionId}" }'
Step C — Create a Payment Access Token (PAT)
curl -X POST \
  "https://api.bigcommerce.com/stores/{store_hash}/v3/checkouts/{cartId}/payments" \
  -H "X-Auth-Token: $BC_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "payment": { "instrument": {}, "payment_method_id": "stripe.card" } }'

The PAT is used in Layer 4 to submit the payment to the BigCommerce payment processing server at payments.bigcommerce.com.

get_order_status — v2 REST

curl -X GET \
  "https://api.bigcommerce.com/stores/{store_hash}/v2/orders/{order_id}" \
  -H "X-Auth-Token: $BC_API_TOKEN" \
  -H "Accept: application/json"

Key response fields: id, status, status_id, subtotal_inc_tax, total_inc_tax, payment_method, payment_status, shipping_cost_inc_tax, date_created, date_modified, billing_address, items_total, items_shipped.

BigCommerce order status_id map

IDStatusIDStatus
0Incomplete7Awaiting Payment
1Pending8Awaiting Pickup
2Shipped9Awaiting Shipment
3Partially Shipped10Completed
4Refunded11Awaiting Fulfillment
5Cancelled12Manual Verification Required
6Declined13 / 14Disputed / Partially Refunded

process_refund — v3 two-step

Step 1 — Create the refund quote
curl -X POST \
  "https://api.bigcommerce.com/stores/{store_hash}/v3/orders/{order_id}/payment_actions/refund_quotes" \
  -H "X-Auth-Token: $BC_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      { "item_id": 1, "item_type": "PRODUCT", "quantity": 1 }
    ]
  }'
Step 2 — Execute the refund using the quote
curl -X POST \
  "https://api.bigcommerce.com/stores/{store_hash}/v3/orders/{order_id}/payment_actions/refunds" \
  -H "X-Auth-Token: $BC_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      { "item_id": 1, "item_type": "PRODUCT", "quantity": 1, "reason": "Agent-initiated return per customer request" }
    ],
    "payments": [
      { "provider_id": "stripe", "amount": 59.99, "offline": false }
    ]
  }'

GraphQL Storefront — a real agent query

For headless storefronts on Catalyst, or for browser-class agents that read directly from the storefront:

query AgentProductQuery($productId: Int!, $namespace: String!) {
  site {
    product(entityId: $productId) {
      entityId
      name
      sku
      mpn
      upc
      condition
      availabilityV2 { status description }
      prices {
        price       { value currencyCode }
        salePrice   { value currencyCode }
        retailPrice { value currencyCode }
      }
      inventory {
        isInStock
        aggregated { availableToSell warningLevel }
      }
      brand { name }
      images(first: 5) {
        edges { node { url(width: 800) altText isDefault } }
      }
      variants(first: 25) {
        edges {
          node {
            entityId sku isPurchasable
            prices { price { value currencyCode } }
            inventory { isInStock aggregated { availableToSell } }
          }
        }
      }
      metafields(namespace: $namespace, first: 10) {
        edges { node { key value } }
      }
      reviewSummary { summationOfRatings numberOfReviews }
      weight { value unit }
    }
  }
}

Variables: {"productId": 118, "namespace": "agent_commerce"}. Authorization header: Authorization: Bearer {storefront_api_token} — and only from browser/Catalyst contexts (see the GraphQL Storefront deprecation callout above).

Tip · Always Include redirect_urls

The ?include=redirect_urls query param on POST /v3/carts is the single most important quality-of-life change you can make in your MCP server. Without it, you get a cart ID but no checkout URL — and have to call a second endpoint to build the redirect. With it, every cart response includes cart_url, checkout_url, and embedded_checkout_url in one round trip. Agents that surface checkout URLs in chat (the default UCP requires_escalation pattern) can hand off in a single tool call.

For the full eight-endpoint pattern and the framework-agnostic OpenAPI spec, see the API Endpoint spoke.

The 30-Day AgentMall Newsletter

One operator note per week. The weekend build in your inbox.

Field-tested patterns, real failure modes, and the next platform spoke as it ships. No fluff. Cancel any time.

Layer 3 · MCP

Native MCP is in beta. Ship a Python FastMCP wrapper today.

In September 2025, BigCommerce announced the BigCommerce Storefront MCP and opened an AI Labs Developer Beta for approved developers — early access to connect storefront data with AI tools and prototype agent commerce experiences. As of this spoke's publication, that native MCP is not generally available; production agent-commerce features should not depend on its availability (re-verify GA status before launch). Until GA, the move is to ship your own Python MCP server that wraps the eight v3 endpoints — one weekend of work, full operator control over the tool surface, and a clean migration path to the native MCP later.

Critical · Native MCP Is Beta, Not GA

Do not publish any claim that BigCommerce's native MCP is generally available. It is in AI Labs Developer Beta as announced September 2025. Production agent integrations that rely on a native endpoint will break or fail validation. Build the Python wrapper now; track BigCommerce's MCP blog post and AI Labs program for GA timing.

Native · Beta

BigCommerce Storefront MCP

Announced September 2025. AI Labs Developer Beta — request access via the BigCommerce dev portal. Not yet GA; do not gate production launches on its availability.

Your Server · Custom

Python FastMCP Wrapper

The recommended path today. Eight tools wired to v3 REST under X-Auth-Token. Stdio for Claude Desktop, streamable-http for Fly.io/Vercel. Full source in this section.

Channel · Attribution

Agent Commerce Channel

Register a dedicated channel via POST /v3/channels with platform: "custom", then pass channel_id in every cart. Every agent-originated order is segmented forever.

The Python FastMCP server — full source

Eight tools, one file. Wraps v3 REST under X-Auth-Token, fetches agent_commerce metafields in get_product, handles variant-tracked inventory in check_inventory, and returns a clean checkout_url from create_cart. Save as server.py, set BC_STORE_HASH and BC_API_TOKEN in .env, and run with uv run server.py.

"""
BigCommerce MCP Server — Agent Commerce Layer 3
Wraps BigCommerce v3 REST API as MCP tools.
Requires: uv add "mcp[cli]>=1.2.0" httpx python-dotenv
Run: uv run server.py
"""

import sys
import os
import json
import logging
from typing import Any, Optional
from dotenv import load_dotenv

import httpx
from mcp.server.fastmcp import FastMCP

load_dotenv()

# ─── Configuration ────────────────────────────────────────────────────────────
STORE_HASH = os.environ["BC_STORE_HASH"]          # e.g. "abc123def"
API_TOKEN  = os.environ["BC_API_TOKEN"]            # X-Auth-Token value
BASE_URL   = f"https://api.bigcommerce.com/stores/{STORE_HASH}/v3"
V2_BASE    = f"https://api.bigcommerce.com/stores/{STORE_HASH}/v2"

HEADERS = {
    "X-Auth-Token": API_TOKEN,
    "Accept": "application/json",
    "Content-Type": "application/json",
}

logging.basicConfig(stream=sys.stderr, level=logging.INFO)
logger = logging.getLogger("bigcommerce-mcp")

mcp = FastMCP("bigcommerce-store")

# ─── HTTP helpers with 429 backoff ────────────────────────────────────────────
import asyncio

async def bc_get(path: str, params: dict = None, v2: bool = False, max_retries: int = 3) -> dict:
    base = V2_BASE if v2 else BASE_URL
    for attempt in range(max_retries):
        async with httpx.AsyncClient(timeout=30.0) as client:
            response = await client.get(f"{base}{path}", headers=HEADERS, params=params)
            if response.status_code == 429:
                wait_ms = int(response.headers.get("X-Rate-Limit-Time-Reset-Ms", 30000))
                logger.warning(f"429 backoff {wait_ms}ms (attempt {attempt+1})")
                await asyncio.sleep(wait_ms / 1000)
                continue
            response.raise_for_status()
            return response.json()
    raise RuntimeError(f"Rate limit exceeded after {max_retries} retries on GET {path}")

async def bc_post(path: str, body: dict, v2: bool = False, max_retries: int = 3) -> dict:
    base = V2_BASE if v2 else BASE_URL
    for attempt in range(max_retries):
        async with httpx.AsyncClient(timeout=30.0) as client:
            response = await client.post(f"{base}{path}", headers=HEADERS, json=body)
            if response.status_code == 429:
                wait_ms = int(response.headers.get("X-Rate-Limit-Time-Reset-Ms", 30000))
                await asyncio.sleep(wait_ms / 1000)
                continue
            response.raise_for_status()
            return response.json()
    raise RuntimeError(f"Rate limit exceeded after {max_retries} retries on POST {path}")

# ─── Tool 1: List Products ────────────────────────────────────────────────────
@mcp.tool()
async def list_products(
    limit: int = 20,
    page: int = 1,
    is_featured: Optional[bool] = None,
    availability: Optional[str] = None,
) -> str:
    """List products from the BigCommerce catalog.

    Args:
        limit: Number of products to return (max 250)
        page: Page number for pagination
        is_featured: Filter to featured products only
        availability: 'available', 'disabled', or 'preorder'
    """
    params = {
        "include": "images,variants",
        "include_fields": "name,sku,price,sale_price,calculated_price,inventory_level,availability,gtin,mpn,brand_id,categories,condition,custom_url",
        "limit": min(limit, 250),
        "page": page,
        "is_visible": True,
    }
    if is_featured is not None: params["is_featured"] = is_featured
    if availability: params["availability"] = availability

    data = await bc_get("/catalog/products", params=params)
    products = data.get("data", [])
    result = [{
        "id": p["id"],
        "name": p["name"],
        "sku": p.get("sku", ""),
        "price": p.get("calculated_price", p.get("price", 0)),
        "availability": p.get("availability", "available"),
        "inventory_level": p.get("inventory_level", 0),
        "gtin": p.get("gtin", ""),
        "url": p.get("custom_url", {}).get("url", ""),
    } for p in products]
    return json.dumps({"products": result, "total": data.get("meta", {}).get("pagination", {}).get("total", len(result))}, indent=2)

# ─── Tool 2: Get Product (merges native fields + agent_commerce metafields) ───
@mcp.tool()
async def get_product(product_id: int) -> str:
    """Get full details for a BigCommerce product including variants, images, custom fields, and agent_commerce metafields.

    Args:
        product_id: The BigCommerce product entity ID
    """
    data = await bc_get(
        f"/catalog/products/{product_id}",
        params={"include": "images,variants,custom_fields"}
    )
    product = data.get("data", {})

    # Also fetch agent_commerce metafields
    try:
        meta_data = await bc_get(
            f"/catalog/products/{product_id}/metafields",
            params={"namespace": "agent_commerce"}
        )
        metafields = {m["key"]: m["value"] for m in meta_data.get("data", [])}
    except Exception:
        metafields = {}

    result = {
        "id": product.get("id"),
        "name": product.get("name"),
        "sku": product.get("sku"),
        "mpn": product.get("mpn"),
        "gtin": metafields.get("gtin") or product.get("gtin"),
        "description": product.get("description", "")[:500],
        "price": product.get("calculated_price", product.get("price")),
        "sale_price": product.get("sale_price"),
        "retail_price": product.get("retail_price"),
        "availability": product.get("availability"),
        "inventory_level": product.get("inventory_level"),
        "inventory_tracking": product.get("inventory_tracking"),
        "condition": product.get("condition"),
        "weight": product.get("weight"),
        "brand_id": product.get("brand_id"),
        "categories": product.get("categories"),
        "images": [img.get("url_standard") for img in product.get("images", [])[:3]],
        "variants_count": len(product.get("variants", [])),
        "return_policy": metafields.get("return_policy"),
        "trust_score": metafields.get("trust_score"),
        "custom_fields": {cf["name"]: cf["value"] for cf in product.get("custom_fields", [])},
    }
    return json.dumps(result, indent=2)

# ─── Tool 3: Search Products ──────────────────────────────────────────────────
@mcp.tool()
async def search_products(
    keyword: str,
    price_min: Optional[float] = None,
    price_max: Optional[float] = None,
    limit: int = 10,
) -> str:
    """Search the BigCommerce catalog by keyword, optionally filtered by price range.

    Args:
        keyword: Search term (matches name, description, sku, search_keywords)
        price_min: Minimum price filter (USD)
        price_max: Maximum price filter (USD)
        limit: Number of results (max 50)
    """
    params = {
        "keyword": keyword,
        "include": "images",
        "include_fields": "name,sku,price,calculated_price,sale_price,inventory_level,availability,custom_url",
        "is_visible": True,
        "limit": min(limit, 50),
    }
    if price_min is not None: params["price_min"] = price_min
    if price_max is not None: params["price_max"] = price_max

    data = await bc_get("/catalog/products", params=params)
    products = data.get("data", [])
    result = [{
        "id": p["id"],
        "name": p["name"],
        "sku": p.get("sku"),
        "price": p.get("calculated_price", p.get("price")),
        "sale_price": p.get("sale_price"),
        "availability": p.get("availability"),
        "in_stock": p.get("inventory_level", 1) > 0,
        "image": p.get("images", [{}])[0].get("url_thumbnail", "") if p.get("images") else "",
        "url": p.get("custom_url", {}).get("url", ""),
    } for p in products]
    return json.dumps({"query": keyword, "results": result, "count": len(result)}, indent=2)

# ─── Tool 4: Check Inventory (handles variant-tracked products) ───────────────
@mcp.tool()
async def check_inventory(product_id: int, variant_id: Optional[int] = None) -> str:
    """Check inventory level and availability for a product or specific variant.

    Args:
        product_id: The BigCommerce product entity ID
        variant_id: Optional variant entity ID for variant-level inventory
    """
    if variant_id:
        data = await bc_get(
            f"/catalog/products/{product_id}/variants/{variant_id}",
            params={"include_fields": "inventory_level,purchasing_disabled,availability"}
        )
        variant = data.get("data", {})
        return json.dumps({
            "product_id": product_id,
            "variant_id": variant_id,
            "inventory_level": variant.get("inventory_level", 0),
            "purchasing_disabled": variant.get("purchasing_disabled", False),
            "in_stock": variant.get("inventory_level", 0) > 0,
        }, indent=2)

    data = await bc_get(
        f"/catalog/products/{product_id}",
        params={"include_fields": "inventory_level,inventory_tracking,availability,inventory_warning_level"}
    )
    product = data.get("data", {})
    return json.dumps({
        "product_id": product_id,
        "inventory_level": product.get("inventory_level", 0),
        "inventory_tracking": product.get("inventory_tracking", "none"),
        "availability": product.get("availability", "available"),
        "in_stock": product.get("availability") == "available" and product.get("inventory_level", 1) > 0,
        "warning_level": product.get("inventory_warning_level", 0),
    }, indent=2)

# ─── Tool 5: Create Cart (always includes channel_id and redirect_urls) ───────
@mcp.tool()
async def create_cart(
    product_id: int,
    quantity: int,
    variant_id: Optional[int] = None,
    channel_id: int = 1,
) -> str:
    """Create a cart with a single line item. Returns cart ID, total, and checkout URL.

    Args:
        product_id: BigCommerce product ID to add
        quantity: Number of units
        variant_id: Optional variant ID if product has variants
        channel_id: BigCommerce channel ID (default 1; pass your registered agent channel)
    """
    line_item: dict = {"product_id": product_id, "quantity": quantity}
    if variant_id: line_item["variant_id"] = variant_id

    body = {
        "customer_id": 0,
        "channel_id": channel_id,
        "line_items": [line_item],
        "currency": {"code": "USD"},
        "locale": "en-US",
    }

    data = await bc_post("/carts?include=redirect_urls", body)
    cart = data.get("data", {})
    redirect_urls = cart.get("redirect_urls", {})

    return json.dumps({
        "cart_id": cart.get("id"),
        "cart_amount": cart.get("cartAmount"),
        "base_amount": cart.get("baseAmount"),
        "discount_amount": cart.get("discountAmount"),
        "currency": cart.get("currency", {}).get("code"),
        "checkout_url": redirect_urls.get("checkout_url"),
        "cart_url": redirect_urls.get("cart_url"),
        "embedded_checkout_url": redirect_urls.get("embedded_checkout_url"),
    }, indent=2)

# ─── Tool 6: Get Checkout (cart ID = checkout ID) ─────────────────────────────
@mcp.tool()
async def get_checkout(cart_id: str) -> str:
    """Retrieve the current checkout state for a cart, including shipping options.

    Args:
        cart_id: The cart ID returned from create_cart (same value as checkout ID)
    """
    data = await bc_get(
        f"/checkouts/{cart_id}",
        params={"include": "consignments.available_shipping_options,promotions.banners"}
    )
    checkout = data.get("data", {})
    return json.dumps({
        "checkout_id": checkout.get("id"),
        "cart_amount": checkout.get("cart", {}).get("cartAmount"),
        "grand_total": checkout.get("grandTotal"),
        "taxes": checkout.get("taxes"),
        "coupons": checkout.get("coupons"),
        "consignments": checkout.get("consignments", []),
        "billing_address": checkout.get("billingAddress"),
        "order_id": checkout.get("orderId"),
    }, indent=2)

# ─── Tool 7: Get Order Status (v2 REST) ───────────────────────────────────────
@mcp.tool()
async def get_order_status(order_id: int) -> str:
    """Retrieve the status and summary of a BigCommerce order.

    Args:
        order_id: The BigCommerce order ID
    """
    data = await bc_get(f"/orders/{order_id}", v2=True)
    status_map = {
        0: "Incomplete", 1: "Pending", 2: "Shipped",
        3: "Partially Shipped", 4: "Refunded", 5: "Cancelled",
        6: "Declined", 7: "Awaiting Payment", 8: "Awaiting Pickup",
        9: "Awaiting Shipment", 10: "Completed", 11: "Awaiting Fulfillment",
        12: "Manual Verification Required", 13: "Disputed", 14: "Partially Refunded",
    }
    status_id = data.get("status_id", 0)
    return json.dumps({
        "order_id": data.get("id"),
        "status": data.get("status", status_map.get(status_id, "Unknown")),
        "status_id": status_id,
        "total_inc_tax": data.get("total_inc_tax"),
        "payment_method": data.get("payment_method"),
        "payment_status": data.get("payment_status"),
        "date_created": data.get("date_created"),
        "date_modified": data.get("date_modified"),
        "items_total": data.get("items_total"),
        "items_shipped": data.get("items_shipped"),
        "shipping_cost_inc_tax": data.get("shipping_cost_inc_tax"),
        "tracking_numbers": data.get("tracking_numbers", []),
    }, indent=2)

# ─── Tool 8: Initiate Return (v3 refund quote → refund) ───────────────────────
@mcp.tool()
async def initiate_return(order_id: int, item_id: int, quantity: int) -> str:
    """Create a refund quote for an order item. Returns the quote for merchant review.

    Args:
        order_id: The BigCommerce order ID
        item_id: The order line item ID
        quantity: Number of units to refund
    """
    body = {"items": [{"item_id": item_id, "item_type": "PRODUCT", "quantity": quantity}]}
    try:
        quote = await bc_post(f"/orders/{order_id}/payment_actions/refund_quotes", body)
        q = quote.get("data", {})
        return json.dumps({
            "action": "refund_quote_created",
            "order_id": order_id,
            "refund_amount": q.get("total_refund_amount"),
            "tax_amount": q.get("total_refund_tax_amount"),
            "payment_options": q.get("payment_methods", []),
            "note": "Refund quote created. Execute via POST /v3/orders/{id}/payment_actions/refunds.",
        }, indent=2)
    except Exception as e:
        return json.dumps({"error": str(e), "order_id": order_id}, indent=2)

# ─── Entry Point ──────────────────────────────────────────────────────────────
def main():
    mcp.run(transport="stdio")  # switch to "streamable-http" for Fly.io/Vercel

if __name__ == "__main__":
    main()

Project files

.env
BC_STORE_HASH=abc123def456
BC_API_TOKEN=your_x_auth_token_here
pyproject.toml
[project]
name = "bigcommerce-mcp"
version = "0.1.0"
requires-python = ">=3.10"
dependencies = [
  "mcp[cli]>=1.2.0",
  "httpx>=0.27.0",
  "python-dotenv>=1.0.0",
]
Run locally
uv sync
uv run server.py

Wire it into Claude Desktop

Edit ~/Library/Application Support/Claude/claude_desktop_config.json on macOS (or %APPDATA%\Claude\claude_desktop_config.json on Windows).

{
  "mcpServers": {
    "bigcommerce": {
      "command": "uv",
      "args": [
        "--directory",
        "/absolute/path/to/bigcommerce-mcp",
        "run",
        "server.py"
      ],
      "env": {
        "BC_STORE_HASH": "abc123def456",
        "BC_API_TOKEN": "your_x_auth_token_here"
      }
    }
  }
}

Register an Agent Commerce channel

BigCommerce's Channels API lets you register any new commerce surface — including an agent channel. Use type: "storefront" with platform: "custom". The returned channel_id goes into every cart your MCP creates.

curl -X POST \
  "https://api.bigcommerce.com/stores/{store_hash}/v3/channels" \
  -H "X-Auth-Token: $BC_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Agent Commerce Channel",
    "type": "storefront",
    "platform": "custom",
    "status": "active",
    "is_listable_from_ui": true,
    "is_visible": true,
    "config_meta": { "app": { "id": 1 } }
  }'

Every order generated with that channel_id is attributed to the Agent Commerce channel in BigCommerce Analytics and in any BI tool pulling from the v2 Orders API. This is your first-90-days agent revenue baseline.

Deploy to Fly.io or Vercel

For HTTP transport (multi-user agent deployments), change the entry point to mcp.run(transport="streamable-http", host="0.0.0.0", port=8000) and ship the Dockerfile below.

Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY pyproject.toml .
RUN pip install uv && uv sync --no-dev
COPY server.py .
CMD ["uv", "run", "server.py"]
Fly.io deploy
fly launch --name bigcommerce-mcp --dockerfile Dockerfile
fly secrets set BC_STORE_HASH=abc123 BC_API_TOKEN=your_token
fly deploy
Why Ship a Custom Wrapper Now

The native BigCommerce Storefront MCP will land — but it will land with a fixed tool surface. Shipping a custom wrapper today gives you (1) production agent commerce while you wait for GA, (2) operator control over the eight tools — you can add get_size_chart, check_buyable, get_bundle_price for free, (3) a clean migration path when native MCP ships: keep the custom wrapper for store-specific tools, point Claude Desktop at both, and let the native server cover the long-tail catalog and policy reads.

For the MCP protocol primer (JSON-RPC envelope, tool schemas, transport options) see the MCP spoke.

Layer 4 · UCP Compatibility

checkout-js is open source. Stripe SPT is the autonomous path.

The Universal Commerce Protocol (UCP) pattern requires that an agent can drive a complete purchase from product selection through payment receipt without forced human handoff. BigCommerce gives you three mechanisms — and the right combination depends on your plan tier and how aggressive you want the autonomy to be.

Option A · Hosted

checkout_url Handoff

The default flow. Cart returns checkout_url; agent surfaces it; buyer pays on BigCommerce-hosted checkout. UCP requires_escalation with continue_url. Works on every plan, every payment method.

Option B · Custom

Fork checkout-js

Open source on GitHub. Fork it, modify the payment flow, host as Custom Checkout (Plus+). Inject Stripe SPT handling or strip UI elements that break programmatic flows.

Option C · Autonomous

Stripe Agentic Commerce Suite

BigCommerce named partner. Shared Payment Tokens (SPTs) — time-bounded, seller-scoped — let agents trigger payments with no raw card data. Cleanest autonomous path on BigCommerce today.

BigCommerce-only · Stripe SPT Partnership

Stripe's Agentic Commerce Suite names BigCommerce as a partner platform alongside WooCommerce, Wix, Squarespace, and commercetools. The mechanism is Shared Payment Tokens (SPTs) — short-lived, seller-scoped payment tokens an agent can use to trigger a charge without accessing raw card data. For agent commerce, this is the cleanest end-to-end autonomy story on BigCommerce: the agent calls create_cart, drives the eight-step checkout, and uses an SPT in place of card capture. No buyer hand-off required (re-verify partner program eligibility and rollout status before launch).

The eight-step UCP checkout state machine on BigCommerce

UCP normalizes the agent purchase flow into eight discrete states. BigCommerce backs each one through v3 REST plus the payment processing host at payments.bigcommerce.com. You do not implement the state machine yourself — but you must understand it so your custom tools and your error messages slot in cleanly.

#StateBigCommerce BackingAgent Action
1discoverGET /v3/catalog/productsFind candidate products
2inspectGET /v3/catalog/products/{id}Read details, variants, metafields
3build_intent (cart)POST /v3/carts?include=redirect_urlsCreate cart with line items + channel_id
4shippingPOST /v3/checkouts/{cartId}/consignmentsAdd address, fetch shipping options
5quote (taxes)PUT /v3/checkouts/{cartId}/consignments/{id} then GET /v3/checkouts/{cartId}Select shipping option, read grandTotal with tax
6confirm (PAT)POST /v3/checkouts/{cartId}/paymentsObtain Payment Access Token
7execute (payment)POST payments.bigcommerce.com/stores/{hash}/payments with PATSubmit payment instrument (or Stripe SPT)
8track (receipt)GET /v2/orders/{orderId}Read order status and tracking

Step 7 in detail — submit payment to the payment host

Payment execution does not run on api.bigcommerce.com. It runs on a separate payment processing server at payments.bigcommerce.com with the Payment Access Token in the Authorization header.

curl -X POST \
  "https://payments.bigcommerce.com/stores/{store_hash}/payments" \
  -H "Authorization: PAT {paymentAccessToken}" \
  -H "Content-Type: application/vnd.bc.v1+json" \
  -d '{
    "payment": {
      "instrument": {
        "type": "card",
        "number": "4111111111111111",
        "cardholder_name": "Agent User",
        "expiry_month": 12,
        "expiry_year": 2027,
        "verification_value": "900"
      },
      "payment_method_id": "stripe.card",
      "save_instrument": false
    }
  }'

For Stripe SPT flows, the instrument payload is replaced by the Stripe payment method token issued under the merchant's Agentic Commerce Suite configuration — the agent never holds raw card data.

Embedded checkout for headless storefronts

For a Catalyst or custom Next.js storefront, use the @bigcommerce/checkout-sdk JavaScript library to drive checkout programmatically without iframe dependencies.

// npm install @bigcommerce/checkout-sdk
import { createCheckoutService } from '@bigcommerce/checkout-sdk';

const service = createCheckoutService();

await service.loadCheckout(checkoutId, {
  params: {
    include: [
      'cart.lineItems.physicalItems.options',
      'consignments.availableShippingOptions',
    ]
  }
});

const state = service.getState();
const checkout = state.data.getCheckout();

await service.selectConsignmentShippingOption(consignmentId, shippingOptionId);
await service.loadPaymentMethods();
const paymentMethods = state.data.getPaymentMethods();

await service.submitOrder({
  payment: {
    methodId: 'stripe',
    paymentData: { nonce: stripePaymentMethodNonce }
  }
});

const order = state.data.getOrder();
console.log('Order ID:', order.orderId);

Custom Checkout — when to fork checkout-js

The checkout-js repository is BigCommerce's Optimized One-Page Checkout — the React app the platform calls "the recommended checkout option for all BigCommerce stores." You fork it, modify the payment branch (Stripe SPT, custom autonomous flow, agent-attribution headers), build the hosted auto-loader URL, and set it in Store Settings → Checkout. Custom Checkout hosting requires Plus or higher; re-verify plan eligibility before launch.

Critical · Payment Host Is a Different URL

Step 7 of the UCP flow does not POST to api.bigcommerce.com. It posts to payments.bigcommerce.com with the PAT in the Authorization header and the content type application/vnd.bc.v1+json. New developers routinely target the wrong host and get cryptic 401s. Encode this in your MCP server's payment-submission helper and document it in your runbook.

For the full UCP state machine, agent profile schema, and the cross-platform protocol detail see the UCP spoke.

§7 · Honest Trade-offs

What BigCommerce makes easy. What BigCommerce makes hard.

Easy

CapabilityWhy It Is Easy
Native gtin fieldFirst-class product attribute — no metafield workaround, no theme hack
Generous v3 rate limitsPro at 450 req/30s handles dozens of concurrent agent sessions comfortably
Native multi-storefront via Channels APIPOST /v3/channels + channel_id in carts = clean agent-revenue segmentation
Headless-first orientationChannels API, Catalyst, GraphQL Storefront, open checkout-js all designed for API-first
Open Checkout / checkout-jsMIT-adjacent fork-and-host model; no platform app submission required
No transaction feesUnlike Shopify Plus, BigCommerce charges no per-transaction fees on any plan with embedded payments
Stripe Agentic Commerce Suite partnerSPTs give merchants a head start on autonomous agent payments
B2B EditionCompany hierarchies, buyer roles, spend limits, POs all API-accessible — ideal for procurement agents

Hard

CapabilityWhy It Is Hard
Native MCP not yet GAStorefront MCP is AI Labs Developer Beta (Sept 2025) — must ship a custom wrapper today
Smaller app marketplace~1,000 apps vs Shopify's 8,000+ — less agent-specific middleware coverage
Stencil → Catalyst migrationMoving to Catalyst (Next.js) is a platform-level rebuild, not an upgrade button
Plan-gated multi-storefront and Custom CheckoutMSF needs Pro+; Custom Checkout hosting needs Plus+
v2/v3 Orders API splitOrder reads on v2, payment actions on v3 — two different code paths in your MCP server
GraphQL Storefront token deprecationTokens after June 30, 2026 lose server-to-server; sunset for legacy by March 31, 2027
Plan-name churnCore/Growth/Scale/Performance in some markets vs Standard/Plus/Pro/Enterprise — re-verify rate limits map to current plan names
Payment host is separateStep 7 POSTs to payments.bigcommerce.com, not api.bigcommerce.com — easy to miss
§8 · Why Mid-Market Picks BigCommerce

The mid-market case for agent-ready BigCommerce.

Mid-market merchants (typically $2M–$50M GMV) face a specific tension: they need the flexibility of enterprise commerce without the total cost of Salesforce Commerce Cloud or Adobe Commerce. BigCommerce's sweet spot — and the reason Etsy graduates and Shopify Plus churners benchmark against it — is programmable commerce at mid-market price. For agent commerce specifically, four facts compound:

Tip · Tag Agent-Originated Orders

When you register the Agent Commerce channel (Layer 3) and pass the channel_id in every cart, every resulting order is automatically attributed to that channel in BigCommerce Analytics. Add an order tag like agent-test during your first 90 days and you can also filter by tag for finer-grained reporting — agent-by-agent, prompt-by-prompt — and split-test agent prompts against organic conversion.

§9 · End-to-End Verification

Test it with Claude Desktop. Real cart, real checkout URL.

You have a v3 API token, an extended Stencil schema partial, a Python MCP wrapper, and a registered Agent Commerce channel. The last hour of the build is the end-to-end test: a real agent, a real BigCommerce sandbox store, a real checkout_url that opens in a real browser. The prompts below walk Claude through the canonical eight-step UCP flow and exercise every layer you built.

Setup

  1. Spin up a BigCommerce sandbox via a dev/partner account at developer.bigcommerce.com.
  2. Add 3–5 test products with at least one variant, images, populated gtin, and at least one agent_commerce.return_policy metafield.
  3. Confirm claude_desktop_config.json contains the bigcommerce MCP entry (see Layer 3).
  4. Quit Claude Desktop fully (menu bar quit, not window close) and restart.
  5. Open a new chat and verify the eight tool icons appear.

The eight-step prompt walkthrough

#Prompt to ClaudeWhat Should Happen
1"Search my BigCommerce store for products under $80 related to {your category}."Claude calls search_products, returns a list with id, name, price, in_stock.
2"Show me the full details for the first result, including the gtin and return policy."Claude calls get_product, returns native fields + agent_commerce metafields merged.
3"Confirm variant {variant_id} is in stock using check_inventory."Claude calls check_inventory with the variant_id. Returns variant-level inventory_level and in_stock boolean.
4"Create a cart with that variant and quantity 1, attributed to my agent channel."Claude calls create_cart with your channel_id. Returns cart_id, cart_amount, and a real checkout_url.
5"Open that checkout URL in my browser." (manual)BigCommerce-hosted checkout loads with the line item and accurate total.
6"Get the current checkout state for that cart, including shipping options."Claude calls get_checkout. Returns consignments, taxes, grand_total.
7"Look up the order status for order {order_id} after I complete checkout."Claude calls get_order_status (v2). Returns status, status_id, tracking_numbers.
8"Initiate a refund for line item {item_id} on order {order_id}, quantity 1."Claude calls initiate_return. Returns refund_quote with refund_amount and payment_options.

Programmatic walkthrough — without an agent

If you want to verify the underlying API path before connecting an agent:

import asyncio
import httpx

STORE_HASH = "abc123"
TOKEN = "your_token"
HEADERS = {"X-Auth-Token": TOKEN, "Content-Type": "application/json", "Accept": "application/json"}
BASE = f"https://api.bigcommerce.com/stores/{STORE_HASH}/v3"

async def agent_purchase():
    async with httpx.AsyncClient() as client:
        # 1. Create cart
        cart_resp = await client.post(
            f"{BASE}/carts?include=redirect_urls",
            headers=HEADERS,
            json={
                "customer_id": 0,
                "channel_id": 1,
                "line_items": [{"product_id": 118, "quantity": 1, "variant_id": 140}],
            }
        )
        cart = cart_resp.json()["data"]
        cart_id = cart["id"]
        checkout_url = cart["redirect_urls"]["checkout_url"]
        print(f"Cart created: {cart_id}, total: ${cart['cartAmount']}")
        print(f"Checkout URL: {checkout_url}")

        # 2. Get checkout state
        co_resp = await client.get(f"{BASE}/checkouts/{cart_id}", headers=HEADERS)
        checkout = co_resp.json()["data"]
        print(f"Grand total with taxes: ${checkout.get('grandTotal')}")
        return checkout_url

asyncio.run(agent_purchase())

What to log

§10 · Comparison Tables

The platform at a glance.

4-Layer × BigCommerce capability

LayerWhat's RequiredNative SupportGap to Close
Structured DataSchema.org JSON-LD with 20-field MVPCornerstone emits Product + Offer + BreadcrumbListDefault is thin (7–8 fields); extend schema.html
API Endpoints8 canonical commerce endpointsv3 REST + GraphQL Storefront cover all 8; v2 still primary for order readsCode splits across v2/v3 paths
MCP Tool DescriptionMCP server wrapping the API surfaceBigCommerce Storefront MCP in AI Labs Developer Beta (Sept 2025, re-verify before launch)Native MCP not GA; self-host the Python wrapper today
UCP CompatibilityProgrammable cart → payment → orderOpen checkout-js, Checkout SDK, Stripe ACS named partnerSPT availability and partner enrollment (re-verify before launch)

BigCommerce vs Shopify vs WooCommerce

CapabilityBigCommerceShopifyWooCommerce
Native GTIN fieldYes — product.gtinNo — uses variant.barcodeNo — uses global_unique_id
API rate limit (top tier)450 req/30s (Pro)Bucket-based, Plus higherSelf-hosted — depends on host
Native MCP serverBeta (Sept 2025)GA — /api/mcpNone native
Checkout extensibilityOpen-source checkout-js (fork; host on Plus+)Checkout Extensibility (Plus)WP hooks + plugins
Stripe ACS partnerNamed partner — SPT pathShop Pay firstStripe plugin path
UCP co-launchCo-developed with Google (Jan 11, 2026, re-verify)Co-launched with Google (Jan 11, 2026, re-verify)Community-driven

Why the gtin row matters most for agents. Google AI Overviews and the major agent runtimes use GTIN as a primary disambiguator. BigCommerce is the only one of the three platforms where the field is named what schema.org calls it — no field-name translation, no metafield extension, no plugin. Catalog you already have ships agent-ready on this one field.

§11 · Common Mistakes

Eight ways BigCommerce agent integrations break in production.

1. Treating the Cornerstone schema partial as sufficient

The default templates/components/products/schema.html emits a thin Product + Offer + BreadcrumbList. Agents and Google AI Overviews need the 20-field MVP — gtin, mpn, hasMerchantReturnPolicy, shippingDetails, aggregateRating. Extend the partial before launch; validate every change at Google's Rich Results Test.

2. Calling v2 for refunds or v3 for order reads

v2 Orders remains the primary read path; v3 owns payment actions (refunds, captures, voids). Mixing the two ends with refunds that 404 against v2 or order reads that miss fields against v3. Split your MCP tools cleanly: get_order_status → v2; refund_order → v3 payment_actions two-step quote-then-execute.

3. Forgetting ?include=redirect_urls on cart create

By default, POST /v3/carts returns the cart object without the checkout_url. Without that URL, the agent has nothing to hand back to the buyer. Always append ?include=redirect_urls and confirm the redirect_urls.checkout_url field is present in your response handler.

4. Assuming the native Storefront MCP is GA

The BigCommerce Storefront MCP announced in September 2025 is in the AI Labs Developer Beta — approved developers only. Building a production agent integration on the assumption it ships in the next quarter is a roadmap risk. Ship the Python FastMCP wrapper from Layer 3 today; treat the native MCP as future migration, not current dependency. Re-verify status before launch.

5. Burning the Standard/Core rate limit budget on full-catalog reads

150 requests per 30 seconds sounds generous until an agent paginates through 8,000 products at 250 per page across multiple parallel sessions. Cache catalog snapshots, page in the background, and never let an agent's search_products call trigger a fresh full-catalog fetch. Watch the X-Rate-Limit-Requests-Left header in every response.

6. Storing agent-only metafields without read_and_sf_access

Metafields default to a restrictive permission set. Without permission_set: "read_and_sf_access", your agent_commerce namespace fields surface in v3 REST but not in GraphQL Storefront queries — and a headless agent storefront sees nothing. Set the permission on creation and audit every existing metafield definition you intend agents to read.

7. Skipping the channel_id on agent carts

Every cart without an explicit channel_id defaults to channel 1 — your main storefront — and the order is unattributable. Register a dedicated Agent Commerce channel via POST /v3/channels, record the channel_id, and pass it on every cart and checkout. Without it, you lose agent-segmented revenue and conversion data forever.

8. Forking checkout-js without the Plus plan check

The github.com/bigcommerce/checkout-js repo is open source, but hosting a Custom Checkout (your fork as the live storefront checkout) requires Plus or higher. Teams burn a sprint on a custom-checkout fork before discovering the deployment gate. Confirm plan eligibility before you cut the branch. Re-verify plan-to-tier mapping before launch.

§12 · FAQ

Frequently asked questions.

Does BigCommerce have a native MCP server I can just install?

Not as a generally available product yet. In September 2025, BigCommerce announced a BigCommerce Storefront MCP and opened an AI Labs Developer Beta — approved developers get early access to connect storefront data with AI tools. Until the native MCP reaches GA, ship the Python FastMCP wrapper in Layer 3 of this spoke; it wraps the eight canonical v3 endpoints and runs on stdio for Claude Desktop or streamable-http for Vercel and Fly.io. Re-verify BigCommerce native MCP GA status before launching any production agent commerce feature.

What BigCommerce plan do I need to run an agent commerce integration?

Every plan supports the v3 REST API and the GraphQL Storefront API. Standard/Core gets 150 requests per 30 seconds (about 20,000 per hour) — adequate for low-traffic agent testing. For production multi-agent traffic, Pro at 450 requests per 30 seconds (about 60,000 per hour) is the comfortable floor. Multi-Storefront with a dedicated agent channel running its own catalog and pricing requires Pro or higher with the MSF feature enabled. Custom Checkout — a fork of checkout-js hosted as the merchant's storefront checkout — requires Plus or higher. Re-verify plan-name-to-tier mapping (Core/Growth/Scale/Performance vs Standard/Plus/Pro/Enterprise) before launch.

Can an AI agent complete a purchase on BigCommerce without any human interaction?

Yes, through the eight-step headless checkout flow in Layer 4 — the agent creates a cart, adds a shipping consignment, selects a shipping option, obtains a Payment Access Token, and submits payment to the BigCommerce payment processing server at payments.bigcommerce.com. The order is created automatically on successful payment. The practical barrier is the payment method. Stripe's Agentic Commerce Suite, with BigCommerce as a named partner, addresses this with Shared Payment Tokens — time-bounded, seller-scoped tokens that let agents trigger payments without ever touching raw card data. SPT availability on BigCommerce is the cleanest autonomous-checkout path on the platform today; re-verify partner program enrollment before launch.

How do I expose GTIN and return policy to agents via BigCommerce?

BigCommerce has a native gtin product field — unlike Shopify (which stores it in variant.barcode) or WooCommerce (global_unique_id) — so you read it directly from product.gtin in Stencil templates and in the v3 product object. For return policy and other agent-only fields, create v3 product metafields in the agent_commerce namespace with permission_set: read_and_sf_access; this surfaces them both in the REST API and in GraphQL Storefront metafields queries. The get_product MCP tool in Layer 3 merges native product fields and agent_commerce metafields into a single agent-facing payload.

What is the GraphQL Storefront API complexity limit and how does it affect agent queries?

Every GraphQL Storefront query has a maximum complexity score of 10,000 (returned in the X-Bc-Graphql-Complexity response header) and a maximum query depth of 16. Deep queries that fetch a product with every variant, every option, every image, every metafield, and a full reviewSummary in a single request can exceed both limits. The two safe patterns: break multi-entity reads into parallel queries (one for product detail, one for metafields, one for inventory), or run server-to-server reads against the v3 REST API from your MCP server, where there is no per-query complexity ceiling — only the request-rate envelope.

How does the BigCommerce Channels API help with agent commerce attribution?

Register a dedicated Agent Commerce channel via POST /v3/channels with type: storefront and platform: custom, then record the returned channel_id and pass it in every cart you create from the MCP server. Every cart with that channel_id produces an order attributed to that channel, so you can segment agent-driven revenue, conversion rate, average order value, and refund rate separately from human-browsed orders in BigCommerce Analytics and in any BI tool pulling from the v2 Orders API. Without channel_id, all agent carts default to channel 1 (your main storefront) and you lose the segmentation forever.

Is BigCommerce's checkout-js really open source and can I modify it for agent flows?

Yes. The repository at github.com/bigcommerce/checkout-js is BigCommerce's Optimized One-Page Checkout — the React app described as the recommended checkout option for all BigCommerce stores. You fork it, modify the payment flow (e.g., add Stripe Shared Payment Token handling or strip UI elements that block programmatic flows), build a hosted auto-loader URL, and set it in Store Settings → Checkout as your Custom Checkout. Custom checkout hosting requires Plus or higher. This is the structural difference from Shopify, where the checkout is locked unless you are on Plus with the Checkout Extensibility framework.

What is the difference between BigCommerce's v2 and v3 Orders API, and which should my MCP server use?

The v2 Orders API at /v2/orders is the primary path for reading and managing order records — status, status_id, line items, shipping and billing addresses, payment method, payment status, tracking numbers. The v3 Management API covers orders-adjacent features: payment actions (refunds, captures, voids at /v3/orders/{id}/payment_actions/) and currency-aware operations. Your MCP get_order_status tool should call v2 for the order read and v3 for refund quotes and execution. Re-verify whether BigCommerce has reached full v3 orders parity before retiring any v2 paths in your code.

§13 · Step-by-Step

The weekend build, in five steps.

Each step mirrors the HowTo JSON-LD at the top of this page word for word. Execute in order. Plan for one extended weekend on Stencil + MCP; budget a second weekend if you are also forking checkout-js.

Step 1 — Extend Stencil schema.html with the 20-field MVP JSON-LD and create agent_commerce metafields

Open your active Stencil theme via the BigCommerce control panel Theme Editor or Stencil CLI and navigate to templates/components/products/schema.html. Replace the default Cornerstone JSON-LD with the 20-field MVP Handlebars template from Layer 1 — adding gtin, mpn, hasMerchantReturnPolicy, shippingDetails, aggregateRating, weight, and dimensions. Push the updated theme and validate every change at Google's Rich Results Test. Then, for each agent-facing field that does not live in Stencil's context object (return_policy JSON blob, trust_score, agent_tags), create v3 product metafields in the agent_commerce namespace with permission_set: read_and_sf_access so they surface in both REST and GraphQL Storefront queries.

Step 2 — Create API credentials and test the 8 endpoints

In the BigCommerce control panel, go to Settings → Store-level API accounts → Create API Account. Name it Agent Commerce MCP and enable the scopes Catalog (read), Orders (read+modify), Checkouts (modify), and Carts (modify). Copy the store_hash and X-Auth-Token. Run each of the eight curl commands from Layer 2 against your live store and confirm correct responses. Pay particular attention to the inventory endpoint (check the inventory_tracking field — variant-tracked products always return 0 at the product level) and to cart creation (confirm the redirect_urls object appears in the response when you append ?include=redirect_urls).

Step 3 — Deploy the Python MCP server

Copy the FastMCP server.py from Layer 3 and create a .env file with your BC_STORE_HASH and BC_API_TOKEN. Install dependencies with uv sync (mcp[cli]>=1.2.0, httpx, python-dotenv). Run uv run server.py locally and verify the stdio transport boots cleanly. Wire it into ~/Library/Application Support/Claude/claude_desktop_config.json under mcpServers.bigcommerce, restart Claude Desktop fully, and confirm all eight tools appear in a new chat. For production, switch transport=stdio to transport=streamable-http and deploy to Fly.io or Vercel with the Dockerfile in Layer 3 — set BC_STORE_HASH and BC_API_TOKEN as platform secrets.

Step 4 — Register an Agent Commerce channel and configure headless checkout

Create a dedicated agent channel via POST /v3/channels with type: storefront and platform: custom; record the returned channel_id. Update your MCP create_cart tool so every cart includes that channel_id. For the checkout flow, choose one of two paths: use the checkout_url from the cart's redirect_urls (sends the buyer to BigCommerce-hosted checkout), or implement the full headless eight-step flow from Layer 4 using @bigcommerce/checkout-sdk and — where eligible — Stripe Shared Payment Tokens for fully autonomous payment. If you are on Plus or higher, you can also fork github.com/bigcommerce/checkout-js and host a Custom Checkout with the agent-specific payment branch baked in.

Step 5 — Test end-to-end with Claude Desktop + BigCommerce Sandbox

Spin up a BigCommerce sandbox store from a dev/partner account, add 3–5 test products with variants, images, and metafields, and point the MCP server at it. In Claude Desktop, prompt the agent with realistic purchase scenarios — Find a [category] under $X, what's the return policy on product Y, check if variant Z is in stock, build a cart and return the checkout URL. Observe the tool-call sequence, log every JSON response, and identify gaps in data (missing metafields, incorrect inventory reporting, missing gtin). Fix the gaps by updating metafields or the schema.html partial, register for the BigCommerce AI Labs Developer Beta to track native Storefront MCP GA, and tag agent-originated orders so you can measure agent-commerce revenue separately in admin analytics.

§14 · Continue the Guide

Next stops in the AgentMall guide.

Sibling Spoke

On Shopify?

The Shopify edition of this playbook — native /api/mcp, the Cart API, Checkout MCP preview, and the Liquid schema snippet you can paste tonight.

Sibling Spoke

On WooCommerce?

The WooCommerce edition — wp-json REST, the global_unique_id GTIN field, AutomateWoo-class MCP wrappers, and the realities of self-hosted rate limits.

Pillar

The Full AgentMall Roadmap

The pillar page that ties the four layers and every platform spoke together into one 30-day operator plan.

Layer 1 · Reference

Product Data — The 20-Field MVP

Field-by-field reference for the Schema.org block, with mapping tables for BigCommerce, Shopify, and WooCommerce.

Layer 2 · Build

API Endpoint — The Eight-Endpoint Surface

The framework-agnostic, OpenAPI-driven endpoint pattern. FastAPI + Vercel reference implementation.

Layer 3 · Protocol

MCP — Model Context Protocol

Tool schemas, JSON-RPC envelope, transports, and the framework you implement once and reuse across Claude, ChatGPT, Cursor, and any future agent runtime.

Layer 4 · Protocol

UCP — Universal Commerce Protocol

The eight-step state machine, agent profile schema, and the cross-platform contract that powers ChatGPT, Copilot, and Google AI Mode.

Stack

Free vs Paid Stack Choices

Where the free tiers run out and which paid services are worth the upgrade for a real production agent integration.

Stack

The Agent-Commerce Stack

End-to-end reference stack — storefront, schema, API, MCP, UCP, observability — for operators building greenfield.

The Window

The window for agent-ready BigCommerce stores is now.

BigCommerce co-developed UCP with Google on January 11, 2026 (re-verify). The Storefront MCP beta is open to developers. Stripe named BigCommerce as a partner in the Agentic Commerce Suite. checkout-js has been open source on GitHub for years. The four facts that distinguish BigCommerce from the other two open platforms — native gtin, generous Pro rate limits, MCP beta access, and the Stripe SPT path — are all present today. The merchants who close all four layers this month get the compounding catalog placement, the trusted-store status, and the operator-class agent telemetry. The merchants who wait will spend the back half of 2026 catching up.

Open the AgentMall Roadmap →

One AgentMall note per week.

Platform-specific weekend builds, real failure modes from operator logs, and the next spoke the morning it ships. No fluff. Cancel any time.