Litestore · Developer guide
API

REST

This page helps you tell which REST routes outside callers can rely on and how each group of routes checks who is calling.

Route handlers under app/api serve callers that can't use a server action or an oRPC procedure. A payment provider posting a webhook, a browser uploading a file and an AI agent reading the catalog all reach Litestore this way.

Litestore publishes an OpenAPI document at app/api/openapi.json that describes some of these routes. We wrote it for AI agents and outside integrations, and it deliberately covers fewer routes than the folder contains.

Keep this difference in mind. A route under app/api is not public just because it is there. The contract lists the routes we invite outside callers to depend on. Every other route is internal code that you can still reach over HTTP.

The published contract

app/api/openapi.json/route.ts builds the spec inside its GET handler instead of serving a static file.

It does this so the servers entry can use the deployment's own base URL, which it reads from env.NEXT_PUBLIC_SITE_URL. A static file would need a hardcoded host, and that host would be wrong in every environment but one.

The document calls itself the AI Commerce API:

app/api/openapi.json/route.ts
const spec = {
  openapi: "3.0.3",
  info: {
    title: `${config.site.name} AI Commerce API`,
    version: "1.0.0",
  },
  servers: [{ url: baseUrl, description: "Production server" }],
  tags: [
    { name: "Discovery", description: "API discovery and capabilities" },
    { name: "Products", description: "Product catalog operations" },
    { name: "Recommendations", description: "Product recommendations" },
    { name: "Tracking", description: "Event tracking" },
    { name: "AI", description: "AI-powered content generation" },
  ],
  // …
}

These five tags cover everything the document advertises:

  • Discovery for API discovery and capabilities
  • Products for product catalog operations
  • Recommendations for product recommendations
  • Tracking for event tracking
  • AI for AI-powered content generation

The document currently describes these paths:

/.well-known/ai-commerce
/api/capabilities
/api/products
/api/products/feed
/api/products/{id}
/api/recommendations
/api/track
/ai/v1/suggest-categories

Request

GET/api/products?q=linen&limit=12
AccessNo key needed
NotesDescribed by /api/openapi.json
A call to /api/products changes as you add or remove query parameters such as q, category and limit.

The spec is hand-written

The document is a literal inside the route handler. Nothing generates it from the handlers it describes, and only a comment asks you to keep it in sync. A new endpoint won't appear here until someone adds it.

Discovery

We want an agent to arrive at your domain and work out the API by itself, without a person handing it a URL.

/.well-known/ai-commerce lists the endpoints, the capabilities and what authentication each one needs. An agent should try it first, and it links on to the OpenAPI document.

/api/capabilities gives the detailed picture. It reports whether the platform is ready, which AI providers are configured, which features are on and which currencies the store uses.

/api/capabilities needs a signed-in admin session. The spec lists it under Discovery, but it is the one discovery route that isn't open, because it shows how the operator configured the store and shoppers don't need that.

Route groups

The route tree splits into six groups. They differ mostly in who may call them and how the caller proves it.

Commerce for agents

products
recommendations
cart
track

Callers either authenticate with a service key or read these routes publicly. We wrote the OpenAPI document for these routes.

Discovery

.well-known/ai-commerce
capabilities
openapi.json

These routes are public, except capabilities, which needs an admin session.

MCP

mcp
mcp/admin

Callers authenticate with a service key sent as a Bearer token. The admin route also needs the admin:mcp scope.

Inbound webhooks

webhooks/stripe
webhooks/resend

These routes check the provider's signature. No Litestore credential is involved. Stripe or Resend calls the route, and the signature they put on the request body proves who sent it.

Platform

inngest
health
upload
media
locale
unsubscribe

Each of these routes handles auth differently, so read the handler instead of assuming a rule for the group. They exist because the platform needs an HTTP endpoint, not because an integrator asked for one.

Admin and AI

admin
ai

These routes need an admin session.

Surfaces that sit outside the contract

The MCP routes and the inbound provider webhooks appear in neither the OpenAPI contract nor the oRPC router.

We left them out on purpose. Each one has its own kind of authentication, and putting them in a shared contract would describe them wrongly.

Integrators don't call a webhook route. A specific provider posts to it, Litestore checks that provider's signature, and the provider decides the shape of the request.

The MCP routes speak JSON-RPC 2.0 instead of REST. An MCP client finds their tools through tools/list, not through an OpenAPI document, so an OpenAPI description of them would be a document no MCP client reads.

Where a new route belongs

Use a server action when Litestore's own admin or storefront UI is the caller.

Use an oRPC procedure when a service-key caller fits the existing router.

Use a REST route handler when the caller can use neither. That covers a provider posting a signed webhook, a browser uploading a multipart form and an agent reading the catalog.

If you want outside integrators to depend on the new route, writing the handler is only half the work. The hand-written spec won't pick it up by itself:

A route becomes part of the published contract when someone adds it to app/api/openapi.json/route.ts, and not before.

On this page