Commerce API

Agent Auth

Register AI agents, approve capabilities, and call the Commerce API via the Agent Auth Protocol.

The Commerce API implements Better Auth Agent Auth on top of the same OpenAPI contract documented at Commerce API.

AI agents can discover, register, request capabilities, and call commerce operations with delegated user authority.

What the merchant decides

With Agent Auth, an AI agent starts with nothing until you approve it for your store. After that it keeps the public catalog, and anything else needs your approval. You see every capability the agent asks for and approve or deny the request as a whole. Approved access ends after an hour idle, or 24 hours at most. Then the agent asks again.

If the agent asks for anything that changes your store (an admin* operation that isn't a read, such as a refund, a cancellation or a price change), approving it needs a sign-in from the last 10 minutes. If yours is older, the approval page asks you to sign in again first.

You see every agent approved for your store under Settings → API keys, with what it can do and when it was last used, and you can revoke one there right away. The same page shows the store's recent agent activity.

An API key isn't Agent Auth: anything holding an admin key can do what the key allows, without asking.

Agent Auth is coming with Grow. Free keys reach the 21 storefront tools.

Discovery

Agents load the provider configuration from:

GET https://<api-host>/.well-known/agent-configuration

Response includes:

json
{
  "version": "1.0-draft",
  "provider_name": "Prood Commerce API",
  "description": "Multi-tenant commerce HTTP API. ...",
  "issuer": "http://localhost:3001/api/auth",
  "default_location": "http://localhost:3001/api/auth/capability/execute",
  "algorithms": ["Ed25519"],
  "modes": ["delegated", "autonomous"],
  "approval_methods": ["ciba", "device_authorization"],
  "endpoints": {
    "register": "http://localhost:3001/api/auth/agent/register",
    "capabilities": "http://localhost:3001/api/auth/capability/list",
    "describe_capability": "http://localhost:3001/api/auth/capability/describe",
    "execute": "http://localhost:3001/api/auth/capability/execute",
    "request_capability": "http://localhost:3001/api/auth/agent/request-capability",
    "status": "http://localhost:3001/api/auth/agent/status",
    "reactivate": "http://localhost:3001/api/auth/agent/reactivate",
    "revoke": "http://localhost:3001/api/auth/agent/revoke",
    "revoke_host": "http://localhost:3001/api/auth/host/revoke",
    "rotate_key": "http://localhost:3001/api/auth/agent/rotate-key",
    "rotate_host_key": "http://localhost:3001/api/auth/host/rotate-key",
    "introspect": "http://localhost:3001/api/auth/agent/introspect"
  }
}

Better Auth routes (registration, capability execute, device approval) are mounted at /api/auth/* on the API app (port 3005 in local dev). On prood.com the gateway serves them at https://prood.com/api/auth/*, so the addresses in the discovery document are API_PUBLIC_URL plus that path: http://localhost:3001 locally, https://prood.com in production.

Capabilities from OpenAPI

Every REST operation with an operationId in the OpenAPI spec becomes an agent capability:

CapabilityMethodScope required
listProductsGETstorefront (default, once the agent has a store)
getProductGETstorefront (default, once the agent has a store)
addCartItemPOSTstorefront (requires approval)
placeOrderPOSTstorefront (requires approval)
adminCreateProductPOSTadmin (requires approval)
adminRefundOrderPOSTadmin (requires approval)

An agent starts with nothing it can use. resolveAgentAccess refuses an agent with no store: one with no user behind it, or one whose user has several stores and hasn't approved it for one. Once the agent has a store it keeps the public catalog reads (listProducts, getProduct, getProductBySlug, listCategories, getStore, listCountries), the default grants for an agent host. Everything else, including other GET operations and every admin* operation, requires approval on the dashboard's device authorization page. All the capabilities in a request are approved or denied together. Only store owners and admins can approve a request that includes an admin* capability. A request that includes a capability that changes the store (changesStore in @prood/auth/agent-capabilities: every admin* operation except adminGet* and adminList*) also needs a session started in the last 10 minutes. Approving also binds the agent to the active store. On a Free store, Agent Auth is refused.

When the session ends, after an hour idle (agentSessionTTL: 3600) or 24 hours at most (agentMaxLifetime: 86400), it reactivates with the catalog defaults only, and the agent has to ask again.

Agent registration flow

Drag to pan · Scroll to zoom

Calling the REST API directly

When an agent calls /v1/* with an Authorization: Bearer agent JWT:

  1. API validates the JWT signature and expiry
  2. Resolves the store: the one the agent was approved for, or the user's only store. A user with several stores must approve the agent for one
  3. Checks the agent holds the capability for this exact operation. Holding one admin* capability doesn't unlock other admin routes
  4. Executes the operation scoped to that store
zsh
curl -H "Authorization: Bearer eyJ..." \
  "https://prood.com/v1/products?perPage=5"

OpenAPI proxy execution

When capabilities run through the default execute endpoint, the plugin proxies HTTP to the public API base URL. No API key is stored for this: the proxy checks the agent's store, plan and role, then sends a token signed with a key derived from BETTER_AUTH_SECRET. The token lasts a minute and names the store, the agent, the capabilities it holds and the one operation it may reach. /v1 refuses it on any other operation.

Drag to pan · Scroll to zoom

Required environment variables

VariablePurpose
API_PUBLIC_URLPublic API origin used in OpenAPI + proxy. Required
TRUST_PROXYSet true behind a reverse proxy for JWT aud validation

Database tables

The Agent Auth tables are defined in packages/auth/src/schema.ts and created by pnpm db:migrate:

TablePurpose
agentHostRegistered agent host applications
agentIndividual agent instances
agentCapabilityGrantApproved capabilities per agent
approvalRequestPending user approval requests
agent_eventAudit log per store: registrations, approvals, denials, revocations and calls. Never stores arguments or results

Audit log

Every Agent Auth event the plugin emits (onEvent) is written to agent_event, along with the approvals, denials and revocations made in the dashboard and admin, which don't go through the plugin. Calls through the execute endpoint are recorded as capability.executed with their outcome and duration. Calls an agent makes to /v1 with its own token are recorded as capability.called, and as failed if the agent lacks the capability. Updating an agent records that it changed, not the values sent. Arguments and results are never stored, because they can hold customer data.

Security considerations

  • A store's agents share one allowance of 600 requests a minute, the same size as an API key's, whether they call /v1 directly or through the execute endpoint
  • Agents operate with delegated user authority — they can only access data the approving user can access
  • An agent can do nothing until it's approved for a store. After that, everything past the six public catalog capabilities needs explicit approval on the device authorization page
  • Agent JWTs are short-lived and scoped to granted capabilities. Access ends after an hour idle, or 24 hours at most
  • Tenant isolation applies — agents cannot cross organization boundaries
  • Proxied capability execution requires agent metadata with organizationId, and /v1 only accepts the proxy's signed token for the one operation it names

Stability

@better-auth/agent-auth implements a protocol that's still a draft, and its API changes between releases. Its version is pinned exactly in pnpm-workspace.yaml, not with a range. Before upgrading, read its changelog, then run the API tests (agent-execute, resolve-caller, agent-store-changes) and walk through an approval in the dashboard.

Example: agent shopping assistant

An AI shopping assistant agent might request these capabilities:

CapabilityPurposeAuto-grant?
listProductsSearch catalogYes
getProductView product detailsYes
createCartStart a cartNo — requires approval
addCartItemAdd to cartNo — requires approval
placeOrderComplete purchaseNo — requires approval

The merchant sees all five on the device authorization page and approves or denies the request as a whole. The two catalog reads were already granted, so the agent cannot start a cart or place an order without that approval.