casset/docs
FeaturesOpen app
docs indexreference
00Overview01Thesis02Architecture03System reality04Roadmap05Investor brief06Technical brief07Full tech HTML08API reference09Playback10Audio pipeline11Commerce12Base anchoring13Hook system14Music video15Theming16Creator guide17Glossary
for developers

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-effort code key 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-store for permission, access, license, and write paths.

Auth flow

Casset auth is cookie-session, not bearer token. The flow:

  • Sign in at /login with email/password, Spotify OAuth, Apple Sign-In, or Google OAuth. Auth routes set a signed casset_session cookie, HttpOnly and SameSite=Lax.
  • Subsequent API calls just include the cookie — noAuthorization header needed for browser-owned product routes.
  • Owner-only routes additionally look up the Artist.userId on 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 to MediaRecorder without leaking the session cookie.
  • Agent write routes require an Authorization bearer token matching AGENT_API_SECRET and 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 with Retry-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 now

Handles + discovery

GET/api/handles/[handle]/availablepublic

Is this handle free?

Used by the claim form on the landing page for live availability checks.

{ "available": true }
GET/api/cassets/recent?limit=5public

Recent 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

GET/api/casset/[slug]/mediapublic

Full 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.

PATCH/api/studio/casset/[id]owner only

Update 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.

POST/api/casset/update-priceowner only

Shortcut for the inline price editor.

Agent-readable release layer

GET/api/agents/releases/[releaseId]/manifestpublic

Machine-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.

GET/api/agents/releases/[releaseId]/dnapublic

Release DNA payload for agents.

Includes manifest status, contributors, rights scopes, agent access policies, permission policies, anchors, and lineage for published canonical releases.

GET/api/agents/releases/[releaseId]/provenancepublic

Append-only provenance events for a release.

Events are ordered oldest to newest and include previousEventHash/eventHash fields for deterministic provenance traversal.

GET/api/agents/releases/[releaseId]/lineagepublic

Source 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.

POST/api/agents/releases/[releaseId]/permission-checkpublic

Evaluate 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 }
POST/api/agents/releases/[releaseId]/license-quotepublic

Prepare 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.

POST/api/agents/releases/[releaseId]/accesspublic

Request 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.

POST/api/agents/releases/[releaseId]/derivativesagent secret

Register 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

GET/api/internal/releases/[releaseId]/dnaowner only

Owner-only Release DNA inspection.

Backs the internal dossier surface with manifest, contributor, permission, provenance, anchor, and lineage state.

GET/api/internal/releases/[releaseId]/manifest-previewowner only

Owner-only canonical manifest preview.

GET/api/internal/releases/[releaseId]/provenance-previewowner only

Owner-only provenance preview.

PATCH/api/internal/releases/[releaseId]/permissionsowner only

Update release permission policy for a scope.

Supports ALLOW, DENY, REQUIRE_LICENSE, and CONTACT_OWNER decisions.

POST/api/internal/releases/[releaseId]/publishowner only

Publish a release version and queue canonical manifest work.

GET/api/releases/[releaseId]/dossierpublic

Public release dossier payload when available.

A restrained public dossier payload. The full internal Release DNA surface remains owner-only.

Audio streaming

GET/api/audio/[trackId]session cookie

Signed 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.

GET/api/audio/waveform/[trackId]public

Pre-computed waveform peaks for a track.

Used by the preview scrubber. Returns a JSON array of normalized floats.

POST/api/audio/tokensession cookie

Mint a one-shot audio token (used by the TikTok video exporter).

Hooks + sharing

POST/api/casset/[slug]/sharesession cookie

Record a share event + return the canonical share URL.

POST/api/casset/[slug]/referral-linksession cookie

Generate a unique referral URL tied to the current user.

Whoever lands on this link and collects gives referral credit to the generator.

POST/api/hooks/submissionssession cookie

Attach a user-created clip to a Hook Object (rewards eligibility).

POST/api/hooks/[hookId]/likesession cookie

Like/unlike a Hook Object.

GET/api/hooks/[hookId]/commentspublic

List comments for a Hook Object.

Commerce

POST/api/checkout/payment-intentsession cookie

Create a Stripe Payment Intent for a casset.

POST/api/checkout/verifysession cookie

Verify a completed payment and grant entitlement.

GET/api/purchases/minesession cookie

List cassets the caller has purchased (drives the Collection page).

Listening Room (Side B)

GET/api/casset/[slug]/sidebpublic

Server-Sent Events stream: comments, activity, presence.

Long-lived response with text/event-stream. The client reconnects with exponential backoff if the connection drops.

POST/api/casset/[slug]/commentsession cookie

Post a comment on the casset page.

POST/api/casset/[slug]/tipsession cookie

Send a tip (one-off payment) to the artist.

POST/api/casset/[slug]/emoji/purchasesession cookie

Buy a custom emoji the artist has listed.

POST/api/casset/[slug]/activitysession cookie

Emit an activity event (used by the follow/like actions).

Release quests / campaigns

POST/api/campaign/[id]/fundowner only

Fund a drop's prize pool. Stripe holds the funds until close.

POST/api/campaign/[id]/launchowner only

Open the drop for submissions.

POST/api/campaign/[id]/select-winnerowner only

Close the drop, snapshot scores, queue payouts.

POST/api/campaign/[id]/payoutowner only

Release the prize pool via Stripe Connect transfers.

Co-Casset

POST/api/co-cassetssession cookie

Create a shared collaborative casset.

GET/api/co-cassets/[slug]/roomsession cookie

Read room messages for a co-casset.

POST/api/co-cassets/[slug]/trackssession cookie

Add a track to a co-casset.

Profile identity

POST/api/auth/update-profilesession cookie

Update profile fields, social links, artist details, and AI/No-AI profile badges.

PATCH/api/studio/casset/[id]owner only

Persist Profile World theme, profilePatternId texture, cover, footer, price, privacy, and publish state.

Notifications

GET/api/notifications/unread-countsession cookie

Unread bell-icon count. Polled periodically by the client.

POST/api/notifications/prefssession cookie

Update per-channel notification preferences.

Body keys: collects, shares, comments, dropJoins, rewards. Booleans.

POST/api/notifications/subscribesession cookie

Register a Web Push subscription (PWA only).

Webhooks

POST/api/webhooks/stripestripe signature

Platform-level Stripe events (payments, payouts).

Signed with STRIPE_WEBHOOK_SECRET. See the Stripe webhooks doc in the repo for the full event routing table.

POST/api/studio/stripe/webhookstripe signature

Connected-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.

← How hooks work→ Full technical overview ↗
© Casset 2026
PrivacyTrustTerms