Expose enough context to build. Keep the artist boundary intact.
Headless exists so public music identity can travel into developer-owned software without turning Casset's database, playback engine, or private artist world into a general-purpose backend.
The API is intentionally smaller than the product. That is the feature: a public artist and Catalog contract that a developer can understand, validate, mock, and handle without inheriting Casset's internal runtime.
Principles
| Principle | What it means in the current implementation |
|---|---|
| Versioned | Routes and response bodies carry explicit v1 identifiers. |
| Minimal | Two reads expose only bounded public identity and Track metadata. |
| Explicit | Empty, unavailable, retryable, and terminal states are represented directly. |
| Read-first | The client and public routes are GET-only. No public write contract exists. |
| Privacy-preserving | Private, unpublished, and unknown artists are indistinguishable; internal IDs and raw media never serialize. |
| Deterministic | Strict parsers, exact mocks, fixed limits, and an immutable starter reduce ambiguity. |
| Typed | Responses, errors, client methods, and React query states are expressed in TypeScript. |
| Stable within a pin | One package/starter version is exact and reproducible. Compatibility across alpha bumps is not promised. |
| Framework-neutral | The core client has no React or application-framework dependency; React is a separate optional adapter. |
Why Headless exists
Native Casset Apps make a Profile World more expressive inside Casset. Headless makes a small amount of public Casset context useful outside it. The split prevents an external website from pretending to be an installed App, and prevents a native App from becoming a generic escape hatch around the Artist Runtime.
Why the boundary is read-only
- Publishing and privacy remain Casset decisions, not caller-supplied flags.
- Playback remains on the canonical Casset clock with one MediaFooter.
- Raw media and private state are not converted into durable external capabilities.
- Developers can own presentation without owning Casset's internal state transitions.
Why strict parsing
Accepting unknown fields would make accidental disclosure and silent contract drift harder to see. The SDK rejects extra nested fields, invalid links, mismatched counts, unknown error codes, and request-ID disagreement. A client either understands the entire response or fails closed.
Why REST, not GraphQL
The current product has two bounded public read shapes. Versioned REST routes make caching, privacy review, rate limiting, mocks, and strict parsing visible with little client machinery. This is a decision about the existing small surface, not a claim about every future Casset integration.
Honest alpha
The promise
Developers should be able to answer five questions from the contract alone: what data is public, what is absent, what failed, whether retrying is safe, and which request ID can correlate the result. Anything beyond that stays inside Casset until it has an equally explicit public boundary.