The core API is one Express 5 process in backend/apps/core-api. src/app.ts builds the app and src/modules/index.ts (buildV1Router) mounts every domain router under /v1. The same process also serves the better-auth handler and the oRPC API under /api, an MCP endpoint under /mcp, and three operational endpoints.

Base URLs

All examples in this reference use the production host. Paths are always shown in full, including the /v1 prefix and the lane prefix.

Versioning

There is one version, /v1. Nothing in the code negotiates a version through headers. Endpoints outside /v1 are not versioned: /healthz, /readyz, /metrics, /api/* and /mcp. The trainee app is shipped to stores, so old builds keep calling old shapes. The API handles that inside /v1 by keeping legacy fields on the wire instead of adding a /v2. Examples are called out on the pages where they matter, such as the retired POST /v1/trainee/health/samples and the null heart-rate keys on GET /v1/trainee/health/summary.

Lanes

A lane is a group of mounts that share one way of authenticating the caller. The lane decides which principal ends up on the request. How each credential is checked, with example requests, is on Authentication.
Older notes describe /v1/<module> as “the bearer lane for the mobile app”. That is no longer true. The mobile app only calls /v1/trainee/* with its own token. The bearer lane still exists in modules/index.ts but covers three routers only.

Mount map

Every router.use in buildV1Router, in registration order. Order matters in two places: the specific /trainee/<module> mounts come before the catch-all /trainee router, and /web/studios/current/api-keys comes before /web/studios.

Webhook, internal and admin

Trainee

Partner, automation and public

Web gateway

Every row below runs requireServiceAuth, then webUserContext, then the web rate limiter. Role guards inside each router are documented on that router’s page.

Bearer

Registered last, after router.use(replay). Replay protection therefore only applies to these three mounts.

Mounted outside /v1

These come from src/app.ts. None of the operational endpoints use the JSON envelope, and none of them are authenticated by the app itself.

Request pipeline

Every request passes through this chain before it reaches a router:
  1. helmet() and cors() with origins from CORS_ORIGIN (comma separated, or *).
  2. requestIdMiddleware, which sets req.requestId and the X-Request-Id response header.
  3. Body parsers. JSON up to 24mb by default, 48mb on /v1/web/plan-import/analyze and /v1/web/forms-ai/analyze, 4mb on /v1/public/sign. Raw application/octet-stream bodies up to 12mb. Each parser keeps the raw bytes on req.rawBody so signatures can be verified over them.
  4. cookieParser() and the HTTP logger.
  5. The route’s own rate limiter and lane middleware.
  6. notFoundMiddleware and errorMiddleware from @perform/errors.
app.set('trust proxy', 1) is set first, so req.ip is the client address forwarded by the one reverse proxy in front of the container. The rate limiters depend on that.

How to read the reference

Each page covers one router or one slice of a large router. It opens with the mount path, the router factory and the guards, then lists every endpoint in the routes file:
  • Heading: method and full path, for example GET /v1/trainee/workouts.
  • Auth: the lane and any extra guard.
  • Parameters: taken from the Zod schema in the module’s *.schema.ts, with types, defaults and limits.
  • Response: the HTTP status and a JSON example with the real field names. Ids and values in examples are invented.
  • Errors: the AppError codes the service throws. Every authenticated endpoint can also return the lane errors listed on Authentication and the generic ones on Conventions, so pages do not repeat those.
Three surfaces do not use the standard envelope. Each page says so at the top:

Authentication

Signing steps and example requests for every lane.

Conventions

Envelope, error codes, pagination, dates, ids and rate limits.

Trainee sign-in

The WhatsApp OTP flow and the trainee token.

Automation API

The studio API key lane used by Make.com.