API reference

The Cadence backend is an ASP.NET Core minimal API (src/Cadence.Api). It publishes a generated OpenAPI document and ships an interactive Scalar reference UI rendered over it, so the API always travels with its own reference.

Reaching the reference

RouteServes
/openapi/v1.jsonThe generated OpenAPI document
/scalarThe Scalar interactive API reference UI

Both are gated by a single configuration flag, ApiDocs:Enabled (default true), so they are available in every environment out of the box. To hide the reference — for example on a hardened public deployment — set ApiDocs__Enabled=false (environment variable) or "ApiDocs": { "Enabled": false } (configuration). Because the spec is generated from the endpoints, it never drifts from the running API; a hand-maintained spec is therefore not a future enhancement here.

Base URL and conventions

  • Base path: every route is under /api. In local development the SPA reaches it same-origin through the Vite dev proxy; in production the API runs as an Azure Container App with external ingress, and browser origins are gated by CORS (Cors:AllowedOrigins). See Self-hosting & deploy.
  • Auth: session-cookie based (cadence.auth, HttpOnly). Endpoints marked Auth below require a signed-in session; unauthenticated calls get 401. See Authentication for the full sign-in flow.
  • Ownership: projects, stem jobs, and share links are owner-scoped. Accessing another user’s resource returns 404 (not 403), so the API never reveals that an id exists.
  • Errors: failures use RFC 9457 application/problem+json. A paid-only action on the free tier returns 402 Payment Required with the problem type https://cadence.app/problems/upgrade-required.

Endpoint groups

Auth — /api/auth

Local password, passwordless magic link, and GitHub/Google/Microsoft OAuth. The login and magic-link routes are rate-limited.

MethodRouteAuthPurpose
POST/api/auth/register—Create an account (sends a verification email)
GET/api/auth/register/verify—Confirm a registration from the emailed link
POST/api/auth/login—Sign in with email + password (rate-limited)
POST/api/auth/logoutAuthSign out and clear the session cookie
GET/api/auth/meAuthThe current user and subscription tier
POST/api/auth/magic-link—Request a passwordless sign-in link (rate-limited)
GET/api/auth/magic-link/verify—Complete a magic-link sign-in (rate-limited)
GET/api/auth/external/{provider}—Begin an OAuth challenge for a provider
GET/api/auth/external/callback—OAuth return endpoint
GET/api/auth/providers—List the OAuth providers that are configured

Profile — /api/profile

MethodRouteAuthPurpose
GET/api/profileAuthRead the current user’s profile
PUT/api/profileAuthUpdate the current user’s profile

Projects — /api/projects

Owner-scoped CRUD. Creating past the tier’s project cap (free = 10) returns 402.

MethodRouteAuthPurpose
GET/api/projectsAuthList the caller’s projects
POST/api/projectsAuthCreate a project (cap-gated → 402)
GET/api/projects/{id}AuthFetch one project (non-owner → 404)
PUT/api/projects/{id}AuthUpdate a project
DELETE/api/projects/{id}AuthDelete a project

Collaboration — /api/projects/{projectId}/shares and /api/collab

Owner-only share-link management plus the real-time relay. The relay is an in-process WebSocket endpoint that fans out Yjs updates; the connection is authorized against the session cookie and the share-link role, and viewer writes are dropped server-side.

MethodRouteAuthPurpose
GET/api/projects/{projectId}/sharesAuth (owner)List a project’s share links
POST/api/projects/{projectId}/sharesAuth (owner)Create a share link with an owner/editor/viewer role
DELETE/api/projects/{projectId}/shares/{token}Auth (owner)Revoke a share link
GET (WebSocket)/api/collab/{projectId}AuthJoin the project’s real-time collaboration room

Stems — /api/stems

An authenticated, owner-scoped async job pipeline. Creating a job requires the paid stem-separation entitlement (free → 402).

MethodRouteAuthPurpose
POST/api/stems/jobsAuthUpload a mix and queue a separation job (entitlement-gated → 402)
GET/api/stems/jobsAuthList the caller’s separation jobs
GET/api/stems/jobs/{id}AuthPoll a job’s status
GET/api/stems/jobs/{id}/stems/{label}AuthDownload a finished stem (bass, drums, vocals, guitar, keys, synth, other)

Billing & entitlements

Stripe-backed checkout and billing portal, plus the entitlement view the SPA reads to gate features. The webhook is anonymous but verified against the Stripe signature.

MethodRouteAuthPurpose
GET/api/entitlementsAuthThe caller’s resolved entitlement set (tier, caps, flags)
POST/api/billing/checkoutAuthStart a Stripe Checkout session for the paid plan
POST/api/billing/portalAuthOpen the Stripe billing portal (402 if never subscribed)
POST/api/billing/webhook—Stripe webhook (signature-verified, not cookie-authed)

Meta

MethodRouteAuthPurpose
GET/api/info—Service name and version (liveness/build check)

For request and response shapes, browse the live Scalar UI at /scalar or the raw document at /openapi/v1.json.