REST API
OpenAPI-backed REST surface, API keys, and CLI — for integrations outside the monorepo.
Zero To Shipped exposes one tRPC router (@zts/trpc) through several transports. This page covers REST and the CLI. For typed clients see SDK. For IDE agents see MCP.
| Surface | URL | Auth | Best for |
|---|---|---|---|
| tRPC | /api/trpc | Session cookie / Better Auth | Web, mobile, extension (first-party) |
| REST | /api/rest | x-api-key: zts_… | Integrations, webhooks, scripts |
| OpenAPI | /api/openapi.json | Spec only | SDK generation, API explorers |
| Swagger UI | /api/docs | Browser | Interactive REST docs |
| MCP | /api/mcp | OAuth + API keys | Cursor and other MCP hosts |
What is exposed
Only procedures tagged with apiExposure() in packages/trpc/src/openapi-meta.ts appear on REST, in packages/sdk/openapi.json, and as MCP tools. Today that covers user profile, user preferences, and utImage.delete (Images tag).
Not exposed (app-internal, session-only tRPC): admin.*, auth.changePassword, polar.*, and other routers without apiExposure().
REST and OpenAPI
REST routes come from tRPC procedures that use apiExposure() (sets both OpenAPI and MCP meta):
| Resource | Location |
|---|---|
| REST handler | apps/web/src/app/api/rest/[...path]/route.ts |
| Live spec | /api/openapi.json (REST base {NEXT_PUBLIC_APP_URL}/api/rest) |
| Swagger UI | /api/docs (Authorize with your zts_ key as x-api-key) |
| Committed spec | packages/sdk/openapi.json (regenerated by @zts/sdk build) |
API keys
REST authenticates with the x-api-key header. Keys are issued via the Better Auth API key plugin (zts_ prefix, configured in packages/auth/src/index.ts).
Create keys in the app UI or through Better Auth’s API key endpoints after migrations are applied (pnpm db:migrate).
Most exposed POST endpoints expect an empty JSON body {} when there is no input.
CLI (zts)
packages/cli publishes the zts binary for terminal access to the same REST surface.
Build:
| Variable | Purpose |
|---|---|
ZTS_API_KEY | zts_… API key (required) |
ZTS_BASE_URL | REST base URL (default http://localhost:3000/api/rest) |
From the monorepo without linking: pnpm --filter @zts/cli run dev me.
Boundaries (what to use when)
- Inside the monorepo UI apps → tRPC + shared
@zts/trpctypes. - Partner integrations, cron scripts, serverless workers → REST + SDK or CLI + API key.
- IDE agents (Cursor) → MCP + OAuth/API keys.
Adding a new public endpoint
- Implement the procedure in
packages/trpc/src/routers/. - Add
.meta(apiExposure({ … }))with Zod v4 inputs (useemptyInputfor no-body POSTs). - Use
protectedProceduresoctx.sessionorctx.apiKeyis required. - Regenerate:
pnpm --filter @zts/trpc run generate:openapithenpnpm sdk:build.
See Better Auth for session-based access on tRPC and Database for migrations when auth tables change.