API reference.
The endpoints the casset.fm client speaks to. Most return JSON; the audio route returns a binary stream.
Auth is cookie-based — sign in at /login and the browser keeps the casset_session cookie for you. Endpoints marked owner require the caller to own the resource. Webhook endpoints verify Stripe signatures. Agent-readable release endpoints are rate-limited and expose published manifest, permission, provenance, and lineage state without turning the public product into protocol UI.
Conventions
- All request + response bodies are JSON unless noted.
Content-Type: application/json. - Errors are
{ "error": "..." }with a 4xx/5xx status. A best-effortcodekey is present on structured errors (e.g.{ "error": "Rate limited", "code": "RATE_LIMIT" }). - Rate limits apply per session and per IP. Most endpoints comfortably accept dozens of requests/minute; audio token minting is tighter.
- Agent-readable release endpoints use short edge caches for read paths and
no-storefor permission, access, license, and write paths.
Auth flow
Casset auth is cookie-session, not bearer token. The flow:
- Sign in at
/loginwith email/password, Spotify OAuth, Apple Sign-In, or Google OAuth. Auth routes set a signedcasset_sessioncookie,HttpOnlyandSameSite=Lax. - Subsequent API calls just include the cookie — no
Authorizationheader needed for browser-owned product routes. - Owner-only routes additionally look up the
Artist.userIdon the resource and require it to match the session user. - Audio streaming uses its own short-lived HMAC token (signed with
AUDIO_TOKEN_SECRET) attached as a query param, so the audio URL can be safely passed toMediaRecorderwithout leaking the session cookie. - Agent write routes require an
Authorizationbearer token matchingAGENT_API_SECRETand remain disabled when that secret is not configured.
Rate limits
Rate limiting lives in lib/rate-limit.ts — a token-bucket per actor, where the actor is usually the session user id, or the IP for unauthenticated routes. A few representative limits:
POST /api/audio/token— 10/min per session. Video export only needs one per share.POST /api/casset/[slug]/comment— 30/min per session with a burst of 10. Aggressive spammers get a 429 withRetry-After.GET /api/handles/[handle]/available— 60/min per IP. The claim form debounces on the client, so this is mostly a scraper deterrent.
429 responses always include a Retry-After header in seconds. The client-side fetch wrapper respects it automatically.
Error shape
Every non-2xx response is JSON and safe to parse. Known codes:
{
"error": "Human-readable message",
"code": "UPPER_SNAKE", // optional but common
"field": "handle", // optional, for validation errors
"hint": "Try a shorter one" // optional, safe to surface in UI
}
// Common codes:
UNAUTHENTICATED — no / invalid session cookie
FORBIDDEN — authenticated but not the owner
NOT_FOUND — resource absent
VALIDATION — body failed zod parse (look at .field)
RATE_LIMIT — back off, Retry-After tells you how long
BAD_STATE — resource exists but can't be changed right nowHandles + discovery
/api/handles/[handle]/availablepublicIs this handle free?
Used by the claim form on the landing page for live availability checks.
{ "available": true }/api/cassets/recent?limit=5publicRecent public cassets, newest first.
Drives the "N artists shaped hooks this week" pill. limit is clamped to 25.
{ "cassets": [
{ "id": "ckabc…", "handle": "connor", "displayName": "Connor James", "pfp": "https://…" }
] }Profile World / casset data
/api/casset/[slug]/mediapublicFull Profile World payload — tracks, cover, socials, theme, provenance.
The preview page hydrates from this, with owner-only fields stripped out when there's no session cookie. Includes AI/No-AI profile flags and profile texture state.
/api/studio/casset/[id]owner onlyUpdate casset metadata (name, price, theme, cover, texture).
Partial update — send only the keys you're changing. Supports theme tokens, cassetBackgroundSource, profilePatternId (none, soft-grain, paper-fiber, halftone, scanlines, paint-fog), footerTheme, privacy/publish fields, and cover visual assets.
/api/casset/update-priceowner onlyShortcut for the inline price editor.
Agent-readable release layer
/api/agents/releases/[releaseId]/manifestpublicMachine-readable canonical release manifest.
Returns published release identity, canonical version, manifest JSON, canonical hash, signature metadata, and anchor status. Agents consume this; humans should still see the cinematic Profile World.
/api/agents/releases/[releaseId]/dnapublicRelease DNA payload for agents.
Includes manifest status, contributors, rights scopes, agent access policies, permission policies, anchors, and lineage for published canonical releases.
/api/agents/releases/[releaseId]/provenancepublicAppend-only provenance events for a release.
Events are ordered oldest to newest and include previousEventHash/eventHash fields for deterministic provenance traversal.
/api/agents/releases/[releaseId]/lineagepublicSource and derivative lineage.
Used by systems that need to trace remixes, alternate versions, samples, visual reinterpretations, and AI-assisted derivatives back to a source release.
/api/agents/releases/[releaseId]/permission-checkpublicEvaluate a requested use against release permissions.
Body requires scope and may include agentKey, intendedUse, commercial, and releaseVersionId. Returns allow, deny, contact owner, or license route semantics.
{ "scope": "ai_generation", "agentKey": "example-agent", "commercial": true }/api/agents/releases/[releaseId]/license-quotepublicPrepare a license route for scopes that require licensing.
Current quotes can return CONTACT_REQUIRED pricing state. This is a permission route, not a public marketplace.
/api/agents/releases/[releaseId]/accesspublicRequest permissioned resource access.
Evaluates release permission first. If a license is required, returns a 402 problem response with MPP challenge data and no-store cache headers.
/api/agents/releases/[releaseId]/derivativesagent secretRegister a derivative link.
Requires AGENT_API_SECRET authorization and is disabled when the secret is not configured. Used for controlled derivative registration, not open social graph posting.
Internal release dossier
/api/internal/releases/[releaseId]/dnaowner onlyOwner-only Release DNA inspection.
Backs the internal dossier surface with manifest, contributor, permission, provenance, anchor, and lineage state.
/api/internal/releases/[releaseId]/manifest-previewowner onlyOwner-only canonical manifest preview.
/api/internal/releases/[releaseId]/provenance-previewowner onlyOwner-only provenance preview.
/api/internal/releases/[releaseId]/permissionsowner onlyUpdate release permission policy for a scope.
Supports ALLOW, DENY, REQUIRE_LICENSE, and CONTACT_OWNER decisions.
/api/internal/releases/[releaseId]/publishowner onlyPublish a release version and queue canonical manifest work.
/api/releases/[releaseId]/dossierpublicPublic release dossier payload when available.
A restrained public dossier payload. The full internal Release DNA surface remains owner-only.
Audio streaming
/api/audio/[trackId]session cookieSigned stream URL for a track.
If the session cookie is missing or not entitled, the response truncates to the 30s hook window. Entitled users get the full file. Signed URLs expire in under a minute.
/api/audio/waveform/[trackId]publicPre-computed waveform peaks for a track.
Used by the preview scrubber. Returns a JSON array of normalized floats.
/api/audio/tokensession cookieMint a one-shot audio token (used by the TikTok video exporter).
Hooks + sharing
/api/casset/[slug]/sharesession cookieRecord a share event + return the canonical share URL.
/api/casset/[slug]/referral-linksession cookieGenerate a unique referral URL tied to the current user.
Whoever lands on this link and collects gives referral credit to the generator.
/api/hooks/submissionssession cookieAttach a user-created clip to a Hook Object (rewards eligibility).
/api/hooks/[hookId]/likesession cookieLike/unlike a Hook Object.
/api/hooks/[hookId]/commentspublicList comments for a Hook Object.
Commerce
/api/checkout/payment-intentsession cookieCreate a Stripe Payment Intent for a casset.
/api/checkout/verifysession cookieVerify a completed payment and grant entitlement.
/api/purchases/minesession cookieList cassets the caller has purchased (drives the Collection page).
Listening Room (Side B)
/api/casset/[slug]/sidebpublicServer-Sent Events stream: comments, activity, presence.
Long-lived response with text/event-stream. The client reconnects with exponential backoff if the connection drops.
/api/casset/[slug]/commentsession cookiePost a comment on the casset page.
/api/casset/[slug]/tipsession cookieSend a tip (one-off payment) to the artist.
/api/casset/[slug]/emoji/purchasesession cookieBuy a custom emoji the artist has listed.
/api/casset/[slug]/activitysession cookieEmit an activity event (used by the follow/like actions).
Release quests / campaigns
/api/campaign/[id]/fundowner onlyFund a drop's prize pool. Stripe holds the funds until close.
/api/campaign/[id]/launchowner onlyOpen the drop for submissions.
/api/campaign/[id]/select-winnerowner onlyClose the drop, snapshot scores, queue payouts.
/api/campaign/[id]/payoutowner onlyRelease the prize pool via Stripe Connect transfers.
Co-Casset
/api/co-cassetssession cookieCreate a shared collaborative casset.
/api/co-cassets/[slug]/roomsession cookieRead room messages for a co-casset.
/api/co-cassets/[slug]/trackssession cookieAdd a track to a co-casset.
Profile identity
/api/auth/update-profilesession cookieUpdate profile fields, social links, artist details, and AI/No-AI profile badges.
/api/studio/casset/[id]owner onlyPersist Profile World theme, profilePatternId texture, cover, footer, price, privacy, and publish state.
Notifications
/api/notifications/unread-countsession cookieUnread bell-icon count. Polled periodically by the client.
/api/notifications/prefssession cookieUpdate per-channel notification preferences.
Body keys: collects, shares, comments, dropJoins, rewards. Booleans.
/api/notifications/subscribesession cookieRegister a Web Push subscription (PWA only).
Webhooks
/api/webhooks/stripestripe signaturePlatform-level Stripe events (payments, payouts).
Signed with STRIPE_WEBHOOK_SECRET. See the Stripe webhooks doc in the repo for the full event routing table.
/api/studio/stripe/webhookstripe signatureConnected-account events (onboarding, capabilities).
Want more?
The full route list lives in app/api/**/route.ts. This page covers what’s stable enough to integrate against today; anything not listed is considered internal and subject to change without notice.