BazaarOn Developers
Live spec Get a key Quickstart

Developer docs

Build an agent that shops.

BazaarOn speaks the open agentic-commerce protocols: UCP (Universal Commerce Protocol) and ACP (Agentic Commerce Protocol). Point ChatGPT, Gemini, OpenClaw, or your own code at us to discover the catalog, build a cart, and check out, programmatically.

Start building View the live spec

Overview

BazaarOn is an international-grocery marketplace with a first-class agentic interface. Two things matter before you write any code:

  • Discovery is open. Browsing the catalog, searching, matching recipe ingredients, reading the product feed, and looking up an order need no key.
  • Buying needs a key. Creating carts and checking out require an agent API key (bzk_…), so any agent can evaluate the catalog, but only an authorized one can transact.

Base URL for every example on this page: https://bazaaron.ai

Quickstart: your first shopping agent

From zero to a placed order in three steps.

1 Get an API key

Sign in as a shopper at /shop → open your account → Your shopping agent → Create key. You'll get a secret like bzk_a1b2c3…. Copy it once; it's never shown again. (Store operators can also issue keys from the admin.) Send it on write requests as a bearer token:

Authorization: Bearer bzk_your_key_here

Discovery calls below need no key. Try them right now.

2 Discover products

POST https://bazaaron.ai/ucp/v1/catalog/search Content-Type: application/json { "query": "basmati rice" }

Response (trimmed). Note amount is in integer cents and id is the product id you'll add to a cart:

{ "capability": "dev.ucp.shopping.catalog", "query": "basmati rice", "results": [ { "id": "prod_8f3…", "title": "Basmati Rice", "brand": "Royal", "price": { "currency": "USD", "amount": 999 }, "inventory": { "available": true, "quantity": 100 }, "seller": { "id": "store_1a…", "name": "Test Bazaar" }, "attributes": { "category": "Rice", "size": "5 lb", "tags": ["rice"] } } ] }

3 Build a cart & check out

Two ways to finish. Pick by who pays:

ACP, fully agentic (the agent supplies a delegated payment and completes the order):

# 1) create a session POST https://bazaaron.ai/acp/v1/checkout_sessions Authorization: Bearer bzk_your_key_here Content-Type: application/json Idempotency-Key: 7b1f… # safe retries { "items": [{ "product_id": "prod_8f3…", "quantity": 2 }], "buyer": { "name": "Ada", "email": "[email protected]" }, "fulfillment_option_id": "pickup" } # → { "id": "acp_checkout_…", "status": "ready_for_payment", "totals": [...] } # 2) complete it (charges the delegated payment, places the order) POST https://bazaaron.ai/acp/v1/checkout_sessions/acp_checkout_…/complete Authorization: Bearer bzk_your_key_here Content-Type: application/json { "payment_data": { "token": "pm_card_visa" } } # → { "status": "completed", "order": { "id": "order_…", "permalink_url": "…" } }

In test mode (no Stripe key configured) payment_data is optional and payments return mock_authorized, so you can complete an order end-to-end without a real card.

UCP, hand off to a human (build the cart, then a person pays in the browser):

POST https://bazaaron.ai/ucp/v1/carts Authorization: Bearer bzk_your_key_here Content-Type: application/json { "items": [{ "product_id": "prod_8f3…", "quantity": 2 }] } # → { "cart": { "id": "cart_…", "subtotalCents": 1998, … } } POST https://bazaaron.ai/ucp/v1/checkout-sessions Authorization: Bearer bzk_your_key_here Content-Type: application/json { "cart_id": "cart_…" } # → { "checkout_session": { "checkout_url": "https://bazaaron.ai/checkout?cart=cart_…", "amount": { "subtotal": 1598, "fulfillment": 499, "card_processing": 94, "tax": 0, "total": 2191 } } } # hand checkout_url to your user to pay

Payment tokens for the ACP flow

The payment_data.token you pass to /complete is a Stripe PaymentMethod id: BazaarOn charges it directly. BazaarOn never stores a shopper's card; the agent presents payment per order. How you get a token depends on the mode:

  • Omit it: the order completes as mock_authorized (no charge). Best while you're wiring up the flow.
  • Test mode: use one of Stripe's built-in test PaymentMethods; no setup, they exist on every Stripe test account: pm_card_visa (succeeds), pm_card_mastercard, or pm_card_chargeDeclined (forces a 402 to test declines).
  • Mint your own test token: create a PaymentMethod from a test card and pass the returned pm_… id:
# Using your Stripe TEST secret key (sk_test_…) POST https://api.stripe.com/v1/payment_methods Authorization: Bearer sk_test_your_stripe_key Content-Type: application/x-www-form-urlencoded type=card&card[token]=tok_visa # → { "id": "pm_1abc…" } ← pass this as payment_data.token

Live cards are out of scope here. A real charge needs a PaymentMethod valid on BazaarOn's own Stripe account, i.e. a delegated / "shared" payment token from the shopper's wallet (the model ChatGPT and agent wallets use), not a card you tokenize yourself. BazaarOn runs in Stripe test mode, so use the test tokens above, no real money moves.

Try it live no key needed

These call the real, open discovery endpoints on this site. Type a product and search:

Behind the scenes this is POST /ucp/v1/catalog/search and GET /acp/v1/products, the same calls your agent makes.

UCP vs ACP: which do I use?

UCP

Cart + human handoff

Your agent assembles a cart and gets a checkout_url. A human finishes payment in the browser. Best when a person is in the loop and you don't hold payment credentials.

ACP

Fully agentic checkout

Your agent supplies a delegated payment token and calls /complete and the order is placed without a browser. Best for autonomous, end-to-end purchasing.

Both share the same catalog and product ids. You can start with discovery (open), then choose a checkout path per use case.

Authentication

Discovery is open. Cart and checkout require one of:

1 · Agent API key (most agents)

Send your key as a bearer token (or the X-API-Key header):

Authorization: Bearer bzk_your_key_here # or X-API-Key: bzk_your_key_here
  • Shoppers self-issue keys at /shop → account → Your shopping agent. A shopper's key shops "for them": the order links to their account, and buyer details, name, email, phone, and the saved delivery address: prefill from their profile, so delivery is hands-off. Your agent can still pass buyer / fulfillment_address in the ACP session to override.
  • Store operators issue keys from the admin for partner agents.
  • Keys are shown once and stored only as a hash. Revoke anytime and access stops immediately. Carts/sessions are private to the key that created them (cross-key access is 403; buyer PII is redacted from non-owners).

2 · Partner signature (server-to-server)

For platform partners, ACP write requests can be signed instead. When the merchant sets ACP_SIGNING_SECRET, send an HMAC-SHA256 of {timestamp}.{rawBody} with a fresh timestamp (5-minute window):

Timestamp: 1718830000 Signature: <hex hmac-sha256( "{timestamp}.{rawBody}", ACP_SIGNING_SECRET )>

The machine-readable auth descriptor lives in the UCP profile under ucp.auth.

Connect OpenClaw (or any agent)

OpenClaw and other AI shopping agents speak plain HTTPS through our open protocols (UCP + ACP). No SDK required. To let an agent shop on its owner's behalf, give it three things: the base URL, an API key the owner issued, and (optionally) the discovery URL. Discovery is open; only cart & checkout use the key.

Teaching your agent the flow? Point it at the hosted skill file, a portable, copy-paste playbook of the full order flow: https://bazaaron.ai/skills/order-on-bazaaron.md

1 The owner issues a key

The shopper signs in at /shop → account → Your shopping agent → Create key. The key is bound to that account, so orders the agent places link back to the owner and their saved buyer details + delivery address fill in automatically.

2 Configure the agent

Point OpenClaw at BazaarOn with two settings (name them however your agent expects):

BAZAARON_BASE_URL = https://bazaaron.ai # discovery: GET {BASE_URL}/.well-known/ucp BAZAARON_API_KEY = bzk_your_key_here # send as: Authorization: Bearer {API_KEY} on cart/checkout

If your agent is LLM-driven, this system-prompt line is usually enough:

You can shop for the user at BazaarOn (https://bazaaron.ai). Search the catalog at /ucp/v1/catalog/search, then create and complete an ACP checkout session (/acp/v1/checkout_sessions [+ /complete]) using BAZAARON_API_KEY as a Bearer token. The user's saved name, email and delivery address are applied automatically; only pass buyer/fulfillment_address if you need to override them.

3 Shop on the owner's behalf

A full run: discover (no key), build the cart, and complete the purchase. Note the agent sends no buyer or address: both come from the owner's account.

# 1) find a product (open, no key) POST https://bazaaron.ai/ucp/v1/catalog/search Content-Type: application/json { "query": "basmati rice" } # → results[].id e.g. "prod_8f3…" # 2) create an ACP checkout session with the owner's key, buyer + delivery # address are auto-filled from the owner's saved profile POST https://bazaaron.ai/acp/v1/checkout_sessions Authorization: Bearer bzk_your_key_here Content-Type: application/json Idempotency-Key: 7b1f… { "items": [{ "product_id": "prod_8f3…", "quantity": 2 }], "fulfillment_option_id": "local_delivery" } # → { "id": "acp_checkout_…", "fulfillment_address": { …owner's saved address… }, # "buyer": { "name": "…", "email": "…" }, "status": "ready_for_payment" } # 3) complete it (test mode: payment_data optional → mock_authorized) POST https://bazaaron.ai/acp/v1/checkout_sessions/acp_checkout_…/complete Authorization: Bearer bzk_your_key_here Content-Type: application/json { "payment_data": { "token": "pm_card_visa" } } # → { "status": "completed", "order": { "id": "order_…", "permalink_url": "…" } } # the order shows up in the owner's "My orders".

Pickup needs no address; delivery uses the owner's saved one. The agent can always pass its own buyer or fulfillment_address to override, and an explicit payment_data.token to charge a real card.

  • Idempotency: send an Idempotency-Key on session creation so retries don't double-order.
  • Limits: per-IP rate limits apply; back off on 429 (honor Retry-After).
  • Control: the owner can revoke the key anytime from their account, and the agent's access stops immediately.

Endpoint reference

Discovery open

GET/.well-known/ucpCapabilities + auth descriptor
POST/ucp/v1/catalog/searchSearch products by text
POST/ucp/v1/recipe-matchMap recipe ingredients → products
GET/ucp/v1/orders/:idPublic order status
GET/acp/feed.jsonlProduct feed (JSONL; .gz variant)
GET/acp/v1/productsProduct list (JSON)
GET/schemas/recipe-ingredient-match.jsonJSON Schema for recipe match

UCP: cart & checkout key

POST/ucp/v1/cartsCreate a cart from line items
GET/ucp/v1/carts/:idRead a cart (owner only)
PATCH/ucp/v1/carts/:idUpdate items / fulfillment
DELETE/ucp/v1/carts/:idCancel a cart
POST/ucp/v1/checkout-sessionsGet a checkout_url for handoff

ACP: agentic checkout key

POST/acp/v1/checkout_sessionsCreate a session (supports Idempotency-Key)
GET/acp/v1/checkout_sessions/:idRead a session
PATCH/acp/v1/checkout_sessions/:idUpdate items / buyer / fulfillment
POST/acp/v1/checkout_sessions/:id/completeCharge + place the order
POST/acp/v1/checkout_sessions/:id/cancelCancel a session

Full request/response field shapes are in the live spec and the JSON schemas.

Conventions & gotchas

  • Line items are flexible. Send items (with product_id or id + quantity) or a bare product_ids array, duplicates are summed server-side.
  • Money is integer cents. amount/subtotalCents/total are whole cents (USD).
  • Weight-sold items. Products have a unit of each, lb, or kg; weight items accept fractional quantity snapped to a step.
  • Idempotency. Send an Idempotency-Key header on ACP session creation to make retries safe.
  • Rate limits. ~240 reads and ~40 writes per minute per IP. Over the limit returns 429 with a Retry-After header.
  • Privacy. Buyer email/phone on a session are visible only to the owning key; others see them redacted.
  • CORS. Allowed request headers: Content-Type, Authorization, X-API-Key, Signature, Timestamp, Idempotency-Key, Request-Id, API-Version.
  • Errors. JSON body with an error/code + message; status codes you'll see: 400 bad request · 401 missing/invalid key · 402 payment declined · 403 not your cart/session · 404 not found · 409 inventory conflict · 429 rate limited.

Next steps