Litestore · Developer guide
API

Keys

Create, scope and revoke the service API keys that let integrations and AI agents call your store.

A service API key lets a program call Litestore when there is no signed-in person behind the request. You create one when you connect an integration, an AI agent or an outside assistant over MCP.

In the code, this key is a ServiceApiKey. The caller sends it as a Bearer token. Every key starts with lsk_, so you can recognise a leaked key when it turns up in a log or a paste.

Litestore stores a SHA-256 hash of the key, not the key itself. You can read a key exactly once, when you create it. There is no way to recover it later, because the database holds nothing it could be recovered from.

Scopes

Litestore has six scopes, and a real request path checks each one.

The constants file explains why the list only contains scopes that code enforces:

lib/api-keys/constants.ts
/** Available scopes for service API keys. Only scopes that are actually ENFORCED by a
 *  request path belong here — advertising a scope no consumer checks (formerly
 *  `write:catalog`/`write:users`/`admin:delete`) lets operators grant phantom power. */
export const API_SCOPES = [
  "read",
  "read:cart",
  "write:cart",
  "write:orders",
  "write:webhooks",
  "admin:mcp",
] as const

Each scope allows the following:

  • read lets the key call read-only oRPC procedures, including listing and reading webhooks.
  • read:cart lets the key read a cart through the cart endpoints.
  • write:cart lets the key create and change a cart.
  • write:orders lets the key write orders through the service surface.
  • write:webhooks lets the key create, update, delete and rotate webhook endpoints.
  • admin:mcp lets the key use the operator MCP endpoint at app/api/mcp/admin.

Why the list is short

Litestore removed three scopes: write:catalog, write:users and admin:delete.

Nothing in the codebase checked them. A request with write:catalog was treated exactly like a request without it.

An unchecked scope is worse than no scope. If you give a key read plus write:catalog, you think you have drawn a boundary, but the key can do nothing more or less than before. The source comment calls this phantom power.

So the list only contains scopes that are real. A scope belongs on the list only if some request path refuses callers that lack it.

Creating and revoking keys

You create keys under Settings → Developer. Only a super-admin can create them.

Revoking a key sets a flag instead of deleting the row. Litestore reads isActive again on every call instead of caching it with the key. When you deactivate a key, the very next request with it fails.

This matters when a key has leaked. If Litestore cached the decision, a revoked key would keep working until a session or cache expired. Here you don't have to wait.

An admin:mcp key reaches the operator tool kit

Treat a key with admin:mcp like an admin credential, because it can use the admin's AI tools. Its read tools answer directly. Its change tools only create approval cards that an operator must approve in the admin, so the key cannot move money on its own.

Rate limiting

Litestore applies rateLimits.publicApi to service endpoints in addition to checking the key. Both MCP routes are rate limited.

The two checks answer different questions. The key check decides whether a caller may make the request at all. The rate limiter decides how often an allowed caller may make it.

If Redis is unreachable, the limiter lets requests through. A Redis outage weakens the protection, but the store keeps serving requests it can no longer count.

Litestore makes this trade on purpose. If the limiter blocked requests instead, a cache outage would take down the whole service surface.

On this page