# cart.fun for agents cart.fun is on-chain commerce: stores sell for stablecoins through a CartCheckout contract, and every sale prints a receipt NFT (proof of purchase, warranty, refunds) plus a cart NFT holding any on-chain goods. Buyer agents discover stores, get signed quotes and pay on-chain. Merchant agents run a store's catalog, invites, sales log and webhooks with API keys. API base URL: `https://go.cart.fun`. Everything is JSON over HTTPS. | Network | Chain id | Slug for URLs | | --- | --- | --- | | Base Sepolia | 84532 | `base-sepolia` | | Robinhood Chain Testnet | 46630 | `robinhood-testnet` | | Arc Testnet | 5042002 | `arc-testnet` | - [OpenAPI 3.1 spec](https://cart.fun/openapi.json): every endpoint, auth, request and response schema - [Agent skill](https://cart.fun/skill.md): drop-in SKILL.md for Claude Code and other skill-aware agents - [Full guide](https://cart.fun/llms-full.txt): this whole document set as one file - [Example agent card](https://go.cart.fun/api/v1/stores/base-sepolia/3/agent): a live store's discovery document ## Workflows ### Buy something 1. **Discover the store.** `GET https://go.cart.fun/api/v1/stores/{chain}/{storeId}/agent` returns its agent card. Read `cartfun.commerce`: `orderable`, `payment` (token, symbol, decimals), `checkout` (contract), and for public stores `catalog.products` with `price` (decimal) and `priceUnits` (base units). Invite-only stores list no products; ask the merchant for an API key with the `orders` scope. Don't know the store id? `GET https://go.cart.fun/api/v1/stores/directory` lists stores that opted in to discovery, and `GET https://go.cart.fun/api/v1/handles/{handle}` resolves a `cart.fun/@handle` to its chain and store id. `GET …/catalog` returns the store's signed catalog snapshot if you want proof of the terms it sells under. 2. **Quote.** `POST https://go.cart.fun/api/v1/orders` with `{ chainId, storeId, buyer, lines: [{ id: sku, quantity }] }`. The server prices the lines from the catalog and returns an order signed by the store, valid for 10 minutes and fillable only by `buyer`. A product with limited stock answers 409 when too few units are left, and a quote holds its units for a few minutes. ERC-721 products pack specific token ids, chosen when the order is quoted. 3. **Approve.** From the buyer wallet, approve the checkout contract (`quote.checkout`) to spend the order total, `order.amount + order.serviceFee + order.relayFee`, of `order.paymentToken`. Tokens with EIP-2612 permit can use `checkoutWithPermit` instead. 4. **Pay.** Call `checkout(order, items, cartRecipient, signature)` on `quote.checkout` with the quote's `order`, `items` and `signature` exactly as returned (numbers as uint256). `quote.version` says which checkout it is: **3** (CartCheckoutV3) or **4** (CartCheckoutV4), whose `Order` struct adds a trailing `bytes32 linesHash` (present as `order.linesHash` in the quote). Use the ABI for that version, as in the example below. `cartRecipient` receives the cart NFT, usually the buyer. If `order.escrowHold` is non-zero, the store's payout is held in escrow until the order is fulfilled (or the hold ends), and a refund returns the money to the buyer. 5. **Confirm.** The `CheckoutCompleted` event carries the `receiptId`. `GET https://go.cart.fun/api/v1/receipts/{chain}/{receiptId}` shows the receipt; `GET …/order` with header `x-order-token: ` shows its line items. **Digital delivery.** `GET …/delivery` (same `x-order-token` header, or the buyer's session) returns what the purchase unlocked: per line, the product's instructions, link and codes. On-chain goods (NFTs, editions, tokens) are already in the cart the checkout packed. 6. **Verify (V4 orders).** `GET …/order` also returns `checkoutVersion`, the public `linesHash` and, to whoever may see the lines, `linesPreimage`: canonical JSON that must `keccak256` to `linesHash`. Its `catalog` names the signed catalog snapshot the lines were priced from (`GET …/catalog/{version}`), so a receipt leads to its lines and its lines to a catalog the store signed. ```ts import { createWalletClient, http, parseAbi, erc20Abi } from "viem"; // wallet: a viem WalletClient for the buyer's account on the store's chain const API = "https://go.cart.fun"; // V3 orders (quote.version 3). V4 orders (quote.version 4) end with "bytes32 linesHash" in the struct. const CHECKOUT_ABI = parseAbi([ "struct Order { uint16 storeId; address buyer; address paymentToken; uint256 amount; uint256 serviceFee; bytes32 itemsHash; uint256 nonce; uint256 deadline; uint32 escrowHold; uint256 relayFee; }", "struct Item { uint8 kind; address token; uint256 id; uint256 amount; }", "function checkout(Order order, Item[] items, address cartRecipient, bytes signature) returns (uint256 receiptId, uint256 cartId)", ]); const CHECKOUT_ABI_V4 = parseAbi([ "struct Order { uint16 storeId; address buyer; address paymentToken; uint256 amount; uint256 serviceFee; bytes32 itemsHash; uint256 nonce; uint256 deadline; uint32 escrowHold; uint256 relayFee; bytes32 linesHash; }", "struct Item { uint8 kind; address token; uint256 id; uint256 amount; }", "function checkout(Order order, Item[] items, address cartRecipient, bytes signature) returns (uint256 receiptId, uint256 cartId)", ]); const quote = await fetch(`${API}/api/v1/orders`, { method: "POST", headers: { "Content-Type": "application/json" }, // + Authorization: Bearer cf_sk_… for invite-only stores body: JSON.stringify({ chainId: 84532, storeId: 3, buyer: account.address, lines: [{ id: 1, quantity: 1 }] }), }).then((r) => r.json()); const o = quote.order; const order = { ...o, amount: BigInt(o.amount), serviceFee: BigInt(o.serviceFee), nonce: BigInt(o.nonce), deadline: BigInt(o.deadline), relayFee: BigInt(o.relayFee) }; const items = quote.items.map((i) => ({ ...i, id: BigInt(i.id), amount: BigInt(i.amount) })); await wallet.writeContract({ address: o.paymentToken, abi: erc20Abi, functionName: "approve", args: [quote.checkout, order.amount + order.serviceFee + order.relayFee] }); await wallet.writeContract({ address: quote.checkout, abi: quote.version === 4 ? CHECKOUT_ABI_V4 : CHECKOUT_ABI, functionName: "checkout", args: [order, items, account.address, quote.signature] }); ``` ### Open a store (no human needed) An agent with its own wallet can open and run a store end to end. Every step is a contract call or a wallet signature. 1. **Pick a network.** `GET https://go.cart.fun/api/v1/networks` lists each network's `storeRegistry`, `checkout` (address and version), `platformSigner`, `paymentToken`, `activationFee` (null = free) and `identityRegistry`. Use one whose `checkout` isn't null. 2. **Register.** From your wallet call `StoreRegistry.register(printer, signer, treasury, bps, allowWarrantyTransfer)` with `printer = checkout.address`, `signer = platformSigner` (cart.fun then prices and signs your orders from your catalog), `treasury` = where sales are paid and on-chain inventory sits (a dedicated wallet you control is safest), `bps = 0` and `allowWarrantyTransfer = false`. The `StoreRegistered(id, owner, printer)` event carries your store id. The calling wallet is the owner. 3. **Activate.** `GET https://go.cart.fun/api/v1/stores/{chain}/{storeId}/activation`. If `fee` is set, transfer `fee.amount` of `fee.token` to `fee.recipient` from the owner or treasury, then `POST …/activation` with `{ txHash }`. Free networks are active at once. 4. **Sign a session.** Sign this exact message (EIP-191 `personal_sign`) with the owner wallet, then send `Authorization: CartSig `. `Origin` must be the origin you call (https://go.cart.fun); a session lasts 12 hours. It's only needed for key management: use it once, below. ```text cart.fun session Sign in to cart.fun to manage your store or view your receipts. This does not send a transaction or cost gas. Wallet: Origin: https://go.cart.fun Issued: Expires: ``` 5. **Create an API key.** `POST https://go.cart.fun/api/v1/stores/{chain}/{storeId}/keys` with the session and `{ name, scopes: ["catalog", "sales", "webhooks", "invites", "orders"] }` (pick what you need). The response carries the secret once; keep it server-side. From here on use `Authorization: Bearer cf_sk_…`. 6. **Stock it.** Claim a handle with `PATCH …/profile`, add products (next section), and for digital goods attach delivery (`PUT …/products/{sku}/delivery`, `POST …/delivery/codes`). To sell NFTs or tokens, send them to the treasury and approve the `carts` contract (`setApprovalForAll` for ERC-721/1155, `approve` for ERC-20). `GET …/treasury-nfts` lists what the treasury holds. 7. **Be discoverable (optional).** Register as an ERC-8004 agent: `IdentityRegistry.register(agentURI, [{ metadataKey: "cartfun.store", metadataValue: abi.encode(storeRegistry, storeId) }])` with `agentURI = https://go.cart.fun/api/v1/stores/{chain}/{storeId}/agent`, then `POST …/agent` with `{ agentId, txHash }` to link it. `PATCH …/profile` with `listed: true` adds you to the directory. ```ts import { createWalletClient, createPublicClient, http, parseAbi, parseEventLogs } from "viem"; const API = "https://go.cart.fun"; const net = (await fetch(`${API}/api/v1/networks`).then((r) => r.json())).networks.find((n) => n.slug === "base-sepolia"); // account: your viem account; wallet: a WalletClient for it on net.chainId; pub: a PublicClient for that chain const REGISTRY_ABI = parseAbi([ "function register(address printer, address signer, address treasury, uint16 bps, bool allowWarrantyTransfer) returns (uint16)", "event StoreRegistered(uint16 indexed id, address indexed owner, address indexed printer)", ]); // 2. Register: cart.fun's checkout prints your receipts, its signer prices your orders const hash = await wallet.writeContract({ address: net.storeRegistry, abi: REGISTRY_ABI, functionName: "register", args: [net.checkout.address, net.platformSigner, account.address, 0, false], }); const receipt = await pub.waitForTransactionReceipt({ hash }); const [{ args }] = parseEventLogs({ abi: REGISTRY_ABI, eventName: "StoreRegistered", logs: receipt.logs }); const store = `${API}/api/v1/stores/${net.slug}/${args.id}`; // 4. Session: one signature, no gas const issued = new Date(); const message = [ "cart.fun session", "", "Sign in to cart.fun to manage your store or view your receipts. This does not send a transaction or cost gas.", "", `Wallet: ${account.address}`, `Origin: ${API}`, `Issued: ${issued.toISOString()}`, `Expires: ${new Date(issued.getTime() + 12 * 3600e3).toISOString()}`, ].join("\n"); const signature = await wallet.signMessage({ message }); const session = "CartSig " + Buffer.from(JSON.stringify({ message, signature })).toString("base64"); // 5. API key: the secret is returned this once; store it server-side const { secret } = await fetch(`${store}/keys`, { method: "POST", headers: { Authorization: session, "Content-Type": "application/json" }, body: JSON.stringify({ name: "my agent", scopes: ["catalog", "sales", "webhooks"] }), }).then((r) => r.json()); ``` ### Run a store 1. **Get a key.** Create your own (see Open a store above), or have the store owner create one in the cart.fun dashboard (Developers tab), choosing its scopes. Send it as `Authorization: Bearer cf_sk_…` from a server, never a browser. Keys are per store and stop working when revoked or when the store changes owner. 2. **Catalog.** `POST https://go.cart.fun/api/v1/stores/{chain}/{storeId}/products` with `{ products: [{ name, type, price, active, onchain?, description?, maxPerOrder? }] }`; `PATCH …/products/{sku}` (only the fields sent change); `DELETE …/products/{sku}`. Images: `PUT …/products/{sku}/image` with the file as the body. Order: `POST …/products/order` with every sku. Prices are decimal strings in the store's payment token. Optional per product: `stock` (units it may sell in all; `available` on reads counts what's left), `maxPerOrder`, and `description`. An `onchain` unit of kind 1 sells ERC-721s: list the token ids the treasury owns in `onchain.ids`. A signed catalog snapshot is published (see `GET …/catalog`, `…/catalog/versions`) whenever the public catalog changes. **Digital goods.** `PUT https://go.cart.fun/api/v1/stores/{chain}/{storeId}/products/{sku}/delivery` with `{ text?, url? }` sets instructions and a link every buyer unlocks after paying; `POST …/products/{sku}/delivery/codes` with `{ codes: [...] }` adds license keys or invite codes, one per unit sold (the product sells out when they run out). Buyers read theirs at `GET /api/v1/receipts/{chain}/{id}/delivery`. None of it is public. 3. **Webhooks.** `POST https://go.cart.fun/api/v1/stores/{chain}/{storeId}/webhooks` with `{ url, events? }` returns a signing secret once. Verify every delivery (below), dedupe on the event `id`, answer 2xx quickly. 4. **Sales.** `GET https://go.cart.fun/api/v1/stores/{chain}/{storeId}/sales` lists receipts. After sending a refund, void or redeem on-chain, log it with `POST …/actions` so the reason shows in the dashboard. 5. **Profile.** `PATCH https://go.cart.fun/api/v1/stores/{chain}/{storeId}/profile` with `{ handle, name, tagline, accent, listed }` claims the store's `cart.fun/@handle` (a key with the `catalog` scope works) and, with `listed: true`, lists it in `GET https://go.cart.fun/api/v1/stores/directory`. 6. **Access.** `POST https://go.cart.fun/api/v1/stores/{chain}/{storeId}/invites` makes the store invite-only (6-digit codes); deleting every code opens it again. Agents with an `orders` key get through regardless. ```bash curl https://go.cart.fun/api/v1/stores/base-sepolia/3/products \ -H "Authorization: Bearer cf_sk_…" ``` ## Auth Public reads need nothing. Store APIs take an API key (`Authorization: Bearer cf_sk_…`) with the right scope. Creating and revoking keys takes the store owner's wallet session (`Authorization: CartSig `), which agents rarely need. | Scope | Grants | | --- | --- | | `orders` | Get quotes from, and read the catalog of, this store even while it's invite-only (agents, checkout servers) | | `catalog` | Read every product (hidden ones too), create, edit and delete products, and edit the store's public profile and handle | | `sales` | Read the refund/void/redeem log, log new actions, and see receipts' line items | | `invites` | List, create, edit and delete invite codes | | `webhooks` | Manage webhook endpoints, send test events and see deliveries | Errors are JSON `{ "error": "…" }` with a meaningful status: 400 bad input, 401 no or bad credential, 402 store not activated, 403 wrong store or missing scope, 404 not found, 409 conflict, 429 rate limited (honour `Retry-After`). Each key gets 120 requests a minute. ## Webhooks cart.fun POSTs a JSON envelope `{ id, type, created, chainId, storeId, data }` to your endpoint. On-chain events fire once their block has a few confirmations; failed deliveries retry with backoff for about two days. The `cartfun-signature` header is `t=,v1=.")>`. | Event | When | | --- | --- | | `order.quoted` | cart.fun signed a quote from your catalog (before payment) | | `order.paid` | A receipt was printed: the order is paid. Includes the order's items when cart.fun quoted it | | `receipt.refunded` | A receipt was marked refunded | | `receipt.voided` | A receipt was voided | | `receipt.redeemed` | A receipt was redeemed (picked up or used) | | `receipt.transferred` | A receipt's warranty moved to a new holder | | `receipt.serviced` | A service record was added to a receipt | | `review.created` | A buyer reviewed your store (ERC-8004), with whether it checked out against their receipt | | `review.replied` | Your store replied to a review | ```js // Node: verify a cart.fun webhook before trusting it import { createHmac, timingSafeEqual } from "node:crypto"; export function verifyCartfun(rawBody, header, secret, toleranceSec = 300) { const parts = Object.fromEntries(header.split(",").map((p) => p.split("="))); const t = Number(parts.t); if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false; // stale: possible replay const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex"); const given = Buffer.from(parts.v1 ?? "", "hex"); return given.length === 32 && timingSafeEqual(given, Buffer.from(expected, "hex")); } // verifyCartfun(await req.text(), req.headers.get("cartfun-signature"), process.env.CARTFUN_WEBHOOK_SECRET) // Events can arrive more than once: dedupe on the body's "id" (also in the cartfun-event-id header). ``` ## Endpoints ### Discover - `GET https://go.cart.fun/api/v1/stores/{chain}/{storeId}/agent` (No auth): The store's ERC-8004 agent card. cartfun.commerce says whether it takes orders, what it's paid in, how to quote and pay, and (public stores) every orderable product with prices in base units. - `GET https://go.cart.fun/api/v1/stores/{chain}/{storeId}/products` (Optional API key (orders)): The store's catalog. Invite-only stores need an API key with the orders scope (or a browser pass). A key with the catalog scope also sees hidden products. - `GET https://go.cart.fun/api/v1/stores/{chain}/{storeId}/catalog` (Optional API key (orders)): The store's latest signed catalog snapshot: its on-sale products and the terms they sell under, as canonical JSON (keys sorted, no whitespace). contentHash = keccak256 of that JSON; signature is an EIP-712 Catalog { storeId uint16, version uint64, issuedAt uint64, contentHash bytes32 } over domain { name: "cart.fun Catalog", version: "1", chainId, verifyingContract: storeRegistry }, by the store's registered order signer (StoreRegistry.getStore(storeId).signer). A new version is published whenever the public catalog changes. - `GET https://go.cart.fun/api/v1/stores/{chain}/{storeId}/catalog/{version}` (Optional API key (orders)): One published catalog version. Versions never change once published. - `GET https://go.cart.fun/api/v1/stores/{chain}/{storeId}/catalog/versions` (Optional API key (orders)): Every published catalog version, newest first (up to 100): version, contentHash, signed, cid, product count, time. - `GET https://go.cart.fun/api/v1/stores/directory` (No auth): Stores that opted in to discovery, busiest first, with their handle, products on sale, lowest price and 30-day sales. Invite-only stores are listed with `gated: true`; their catalogs stay behind their codes. - `GET https://go.cart.fun/api/v1/handles/{ref}` (No auth): The store behind cart.fun/@ref: a store handle, or a "base-12" style chain-and-id fallback for stores without one. Returns its chainId, storeId and profile. - `GET https://go.cart.fun/api/v1/stores/{chain}/{storeId}/profile` (No auth): The store's public profile (handle, name, tagline, accent, directory listing), or null when it hasn't claimed a handle. - `GET https://go.cart.fun/api/v1/stores/{chain}/{storeId}/reviews` (No auth): ERC-8004 reviews, each checked against the receipt it names, and the verified score. - `GET https://go.cart.fun/api/v1/networks` (No auth): Every network's contracts and terms for opening a store: storeRegistry, checkout (address, version, escrow), platformSigner, paymentToken, activationFee (null = free), identityRegistry, plus receipts and carts. Everything an agent needs to register a store itself. - `GET https://go.cart.fun/api/v1/signer` (No auth): The platform order signer. A store must register this address as its signer to get quotes. - `GET https://go.cart.fun/api/v1/service-fee` (No auth): The buyer service-fee policy on a network, to preview fees before quoting. Null where the checkout can't charge one. - `GET https://go.cart.fun/api/v1/stores/{chain}/summary` (No auth): Sales totals per store on a network, from the public receipt index. ### Buy - `POST https://go.cart.fun/api/v1/orders` (Optional API key (orders)): Prices the lines from the catalog and returns an order signed by the store. The buyer then pays it on-chain (see the checkout flow). Quotes expire after 10 minutes and only `buyer` can fill them. ### Receipts & reviews - `GET https://go.cart.fun/api/v1/receipts/{chain}/{id}` (No auth): A receipt NFT's on-chain record: store, purchaser, holder, amount paid and lifecycle state. - `GET https://go.cart.fun/api/v1/receipts/{chain}/{id}/order` (Optional API key (sales)): The order behind a receipt, proven by its on-chain commitment. Everyone gets the money breakdown; line items need the quote's x-order-token, the buyer's or holder's session, or an API key with the sales scope. - `GET https://go.cart.fun/api/v1/receipts/{chain}/{id}/delivery` (Optional API key (sales)): What the receipt's buyer unlocked: per line, the product's instructions, link and codes (each paid unit of a code product gets its own, assigned on first read and kept). Same access as line items: the quote's x-order-token, the buyer's or holder's session, or an API key with the sales scope. Refunded and voided receipts unlock nothing. - `GET https://go.cart.fun/api/v1/receipts/{chain}/{id}/cart` (No auth): The cart a receipt paid for, as it stands: its holder (and whether that's still the buyer), its ERC-6551 account, whether it's locked, and every on-chain item checkout packed into it with how much is still inside. - `GET https://go.cart.fun/api/v1/receipts/{chain}/{id}/svg` (No auth): The receipt's rendered image (SVG). - `GET https://go.cart.fun/api/v1/reviews/comment` (No auth): How long a review comment may be, and whether long ones can be pinned to IPFS here. - `POST https://go.cart.fun/api/v1/reviews/comment` (No auth): Pins a long review comment to IPFS and returns its ipfs:// URI and keccak256 hash for the review's feedback file. ### Catalog - `POST https://go.cart.fun/api/v1/stores/{chain}/{storeId}/products` (API key or owner session (catalog), activated store): Creates products. Rejects the whole batch if any sku is taken. - `PATCH https://go.cart.fun/api/v1/stores/{chain}/{storeId}/products/{sku}` (API key or owner session (catalog), activated store): Updates the fields sent; omitted fields (and the sku) stay. - `POST https://go.cart.fun/api/v1/stores/{chain}/{storeId}/products/order` (API key or owner session (catalog), activated store): Sets the catalog's display order. List every sku once; the vending machine stocks the first 12 on sale. - `GET https://go.cart.fun/api/v1/stores/{chain}/{storeId}/products/{sku}/image` (No auth, activated store): Returns the product's image bytes. Public stores cache forever (immutable); invite-only stores require the browser's pass cookie and use a private 24-hour cache. - `PUT https://go.cart.fun/api/v1/stores/{chain}/{storeId}/products/{sku}/image` (API key or owner session (catalog), activated store): Sets a product's image. Send the file itself as the body (WebP, JPEG or PNG, up to 512 KB) with its Content-Type. - `DELETE https://go.cart.fun/api/v1/stores/{chain}/{storeId}/products/{sku}/image` (API key or owner session (catalog), activated store): Removes a product's image. - `GET https://go.cart.fun/api/v1/stores/{chain}/{storeId}/products/{sku}/delivery` (API key or owner session (catalog)): The product's digital delivery: instructions (text) and a link every buyer unlocks after paying, and its code pool's counts. Private to the store: never part of the catalog, its snapshots or the order lines. - `PUT https://go.cart.fun/api/v1/stores/{chain}/{storeId}/products/{sku}/delivery` (API key or owner session (catalog), activated store): Sets the product's delivery instructions and/or link (fields sent; an empty string clears one). Links must be http(s). - `GET https://go.cart.fun/api/v1/stores/{chain}/{storeId}/products/{sku}/delivery/codes` (API key or owner session (catalog)): The product's code pool, newest first, with the receipt each assigned code went to. - `POST https://go.cart.fun/api/v1/stores/{chain}/{storeId}/products/{sku}/delivery/codes` (API key or owner session (catalog), activated store): Adds codes (license keys, invite codes…) to the product's pool, up to 1000 per call; ones already there are skipped. Each unit sold gets its own code, and while a product has a pool it sells only as many units as there are free codes. - `DELETE https://go.cart.fun/api/v1/stores/{chain}/{storeId}/products/{sku}/delivery/codes` (API key or owner session (catalog), activated store): Removes unassigned codes: the ones listed, or every unassigned one with { all: true }. Assigned codes belong to their buyers and stay. - `DELETE https://go.cart.fun/api/v1/stores/{chain}/{storeId}/products/{sku}` (API key or owner session (catalog), activated store): Deletes a product. - `PATCH https://go.cart.fun/api/v1/stores/{chain}/{storeId}/profile` (API key or owner session (catalog), activated store): Claims or updates the store's handle (its cart.fun/@handle address), name, tagline, accent and directory listing. Send every field. - `GET https://go.cart.fun/api/v1/stores/{chain}/{storeId}/treasury-nfts` (No auth): The ERC-721 and ERC-1155 tokens the store's treasury holds, grouped by collection, from the network's block explorer. For picking what to list; listing still checks holdings on-chain. cart.fun receipts, carts and the store's agent identity are left out. Public: holdings are on-chain. ### Sales - `GET https://go.cart.fun/api/v1/stores/{chain}/{storeId}/sales` (No auth): Every receipt the store has printed, newest first. Public: receipts are on-chain. - `POST https://go.cart.fun/api/v1/stores/{chain}/{storeId}/sales/refresh` (No auth): Re-reads up to 50 of the store's receipts from chain now, after a redeem, refund or void lands. - `GET https://go.cart.fun/api/v1/stores/{chain}/{storeId}/actions` (API key or owner session (sales)): The store's refund, void and redeem log, with reasons and notes. - `POST https://go.cart.fun/api/v1/stores/{chain}/{storeId}/actions` (API key or owner session (sales), activated store): Logs refunds, voids or redemptions you just sent on-chain, attributed to your key. ### Invites - `GET https://go.cart.fun/api/v1/stores/{chain}/{storeId}/invites` (API key or owner session (invites)): The store's invite codes. While a store has any, it's invite-only. - `POST https://go.cart.fun/api/v1/stores/{chain}/{storeId}/invites` (API key or owner session (invites), activated store): Creates an invite code (generated when `code` is omitted). - `PATCH https://go.cart.fun/api/v1/stores/{chain}/{storeId}/invites/{code}` (API key or owner session (invites), activated store): Changes an invite's label, use limit, expiry or active flag. - `DELETE https://go.cart.fun/api/v1/stores/{chain}/{storeId}/invites/{code}` (API key or owner session (invites), activated store): Deletes an invite code. Deleting every code makes the store public. - `GET https://go.cart.fun/api/v1/stores/{chain}/{storeId}/access` (No auth): Returns whether this browser holds a valid pass for the store (`ok`) and whether the store is invite-only (`gated`). Use before showing the code prompt. - `POST https://go.cart.fun/api/v1/stores/{chain}/{storeId}/access` (No auth): Checks an invite code for a browser and sets a 30-day pass cookie. Agents should use an API key with the orders scope instead. ### Webhooks - `GET https://go.cart.fun/api/v1/stores/{chain}/{storeId}/webhooks` (API key or owner session (webhooks)): The store's webhook endpoints and its 50 latest deliveries. - `POST https://go.cart.fun/api/v1/stores/{chain}/{storeId}/webhooks` (API key or owner session (webhooks), activated store): Adds an endpoint. The response carries its signing secret, shown this once. - `GET https://go.cart.fun/api/v1/stores/{chain}/{storeId}/webhooks/{id}` (API key or owner session (webhooks)): One endpoint's 50 latest deliveries. - `PATCH https://go.cart.fun/api/v1/stores/{chain}/{storeId}/webhooks/{id}` (API key or owner session (webhooks)): Changes an endpoint's URL, description, events or active flag, or rotates its secret (the new one comes back once). - `DELETE https://go.cart.fun/api/v1/stores/{chain}/{storeId}/webhooks/{id}` (API key or owner session (webhooks)): Deletes an endpoint and its delivery history. - `POST https://go.cart.fun/api/v1/stores/{chain}/{storeId}/webhooks/{id}/test` (API key or owner session (webhooks)): Sends a `ping` event to the endpoint now. - `POST https://go.cart.fun/api/v1/stores/{chain}/{storeId}/webhooks/deliveries/{deliveryId}/retry` (API key or owner session (webhooks)): Sends a delivery again now, whatever happened to it before. ### Keys & activation - `GET https://go.cart.fun/api/v1/stores/{chain}/{storeId}/keys` (Owner wallet session): The store's API keys (never their secrets). Key management always takes the owner's wallet session. - `POST https://go.cart.fun/api/v1/stores/{chain}/{storeId}/keys` (Owner wallet session, activated store): Creates a key. The response carries the secret, the only time it's returned. - `DELETE https://go.cart.fun/api/v1/stores/{chain}/{storeId}/keys/{id}` (Owner wallet session): Revokes a key at once. - `GET https://go.cart.fun/api/v1/stores/{chain}/{storeId}/activation` (No auth): Whether the store is activated for cart.fun orders, and the fee to activate it. - `POST https://go.cart.fun/api/v1/stores/{chain}/{storeId}/activation` (No auth): Activates the store from its fee payment. The payment must come from the store's owner or treasury. - `POST https://go.cart.fun/api/v1/stores/{chain}/{storeId}/agent` (No auth): Links a registered ERC-8004 agent to the store. Checked on-chain: the agent's cartfun.store metadata must name the store, and the store's owner must own the agent.