Headless API v1 reference.
Two unauthenticated GET routes: one public Artist and one public Catalog.
These routes are deployed, but they are not currently available for supported production use. Requests may intentionally fail closed with 503 ResourceUnavailable. No uptime, availability, or production-use commitment is offered.
Endpoints
GET /api/v1/artists/{handle}
GET /api/v1/artists/{handle}/catalogBefore you call the API
| Concern | v1 behavior |
|---|---|
| Base URL | The deployed /api/v1 route family is unsupported for production use and may fail closed with 503. Use exact mocks or a local Casset origin for reliable evaluation. |
| Method | GET only. The SDK exposes no write operation. |
| Authentication | None on /api/v1. A Bearer credential is required only on /api/sandbox/v1 counterparts. |
| Handle | 3–30 lowercase letters, digits, underscores, or hyphens: ^[a-z0-9_-]{3,30}$. |
| Content type | application/json |
| Success cache | public, max-age=0, must-revalidate |
| Error cache | private, no-store |
| Rate limit | 60 requests per IP per 60 seconds. The check runs before handle validation, so 429—or a production limiter 503—can preempt 400. 429 includes Retry-After. |
| Correlation | Send x-request-id. Casset mirrors a valid value or generates one. |
Get public artist
GET /api/v1/artists/{handle}Returns bounded public identity for one published, non-private Profile World. It never returns an internal artist or user ID.
curl
curl --include \
--header "Accept: application/json" \
--header "X-Request-Id: reference-artist-001" \
http://127.0.0.1:3000/api/v1/artists/connorTypeScript
const artist = await casset.getArtist("connor", {
requestId: "reference-artist-001",
})
console.log(artist.artist.displayName)
console.log(artist.links.catalog)200 response
HTTP/1.1 200 OK
Cache-Control: public, max-age=0, must-revalidate
Content-Type: application/json
X-Request-Id: reference-artist-001
{
"schema": "casset.public-artist.v1",
"artist": {
"handle": "connor",
"displayName": "Connor James",
"bio": "Multi-instrumentalist, singer/songwriter, and producer.",
"verified": true
},
"links": {
"profile": "http://127.0.0.1:3000/connor",
"catalog": "http://127.0.0.1:3000/api/v1/artists/connor/catalog"
}
}Empty response
Fields
| Field | Type | Meaning | Limit |
|---|---|---|---|
schema | literal | casset.public-artist.v1 | Exact |
artist.handle | string | Canonical public handle | 3–30 |
artist.displayName | string | Public display name | 160 |
artist.bio | string | null | Public biography when present | 2,000 |
artist.verified | boolean | Public verified state | Exact |
links.profile | HTTPS, loopback HTTP, or root-relative link | Canonical Profile World | 2,048 |
links.catalog | HTTPS, loopback HTTP, or root-relative link | Canonical v1 Catalog read | 2,048 |
Get public Catalog
GET /api/v1/artists/{handle}/catalogReturns one bounded page of active public Track metadata. It contains no cursor, filter, audio, artwork, lyric, storage, or playback field.
curl
curl --include \
--header "Accept: application/json" \
--header "X-Request-Id: reference-catalog-001" \
http://127.0.0.1:3000/api/v1/artists/connor/catalogTypeScript
const catalog = await casset.getCatalog("connor", {
requestId: "reference-catalog-001",
})
for (const track of catalog.tracks) {
console.log(track.title, track.kind, track.durationSec)
}200 response
HTTP/1.1 200 OK
Cache-Control: public, max-age=0, must-revalidate
Content-Type: application/json
X-Request-Id: reference-catalog-001
{
"schema": "casset.public-catalog.v1",
"artist": {
"handle": "connor",
"displayName": "Connor James"
},
"tracks": [
{
"title": "Baby Blue",
"kind": "ORIGINAL",
"durationSec": 213
}
],
"page": { "count": 1 }
}Empty 200 response
HTTP/1.1 200 OK
Cache-Control: public, max-age=0, must-revalidate
Content-Type: application/json
X-Request-Id: reference-catalog-empty-001
{
"schema": "casset.public-catalog.v1",
"artist": {
"handle": "connor",
"displayName": "Connor James"
},
"tracks": [],
"page": { "count": 0 }
}Fields
| Field | Type | Meaning | Limit |
|---|---|---|---|
schema | literal | casset.public-catalog.v1 | Exact |
artist.handle | string | Canonical public handle | 3–30 |
artist.displayName | string | Public display name | 160 |
tracks | array | Active public Track metadata | 0–500 |
tracks[].title | string | Public Track title | 240 |
tracks[].kind | ORIGINAL | GENERATION | Public provenance kind | Exact |
tracks[].durationSec | number | null | Duration in whole or fractional seconds when valid | 0–86,400 |
page.count | number | Must equal tracks.length | 0–500 |
Failure matrix for both endpoints
The following responses apply to both public paths. Their sandbox read counterparts add credential failure and return the same error schema; ownership failures belong to the separate sandbox console.
| Status | Public /api/v1 | Local /api/sandbox/v1 | Retry |
|---|---|---|---|
| 400 | Malformed handle | Malformed handle or request | No |
| 401 | Not emitted; public v1 has no credential | Missing, invalid, or revoked sandbox credential | No |
| 403 | Not emitted by current public reads | Not emitted by the two sandbox reads; authenticated console ownership/session actions can emit it | No |
| 404 | Unknown, private, or unpublished artist | Unavailable sandbox or missing public artist | No |
| 429 | Per-IP public rate limit | Not emitted by the two sandbox reads | Yes when the envelope says retryable |
| 502 | Not emitted | Sandbox integration failure | Follow envelope.retryable |
| 503 | Public data could not be prepared, or the production rate limiter is unavailable | Not emitted by the two sandbox reads | Yes when the envelope says retryable |
| 5xx other | Not currently emitted by these public routes | Not currently emitted by these sandbox reads | SDK retries only 500–599 when retryable is true or no valid envelope exists |
400 — invalid handle
HTTP/1.1 400 Bad Request
Cache-Control: private, no-store
Content-Type: application/json
X-Request-Id: reference-invalid-001
{
"schema": "casset.error.v1",
"error": {
"code": "INVALID_REQUEST",
"message": "A valid artist handle is required.",
"requestId": "reference-invalid-001",
"retryable": false
}
}404 — unknown, private, or unpublished
HTTP/1.1 404 Not Found
Cache-Control: private, no-store
Content-Type: application/json
X-Request-Id: reference-not-found-001
{
"schema": "casset.error.v1",
"error": {
"code": "RESOURCE_UNAVAILABLE",
"message": "Artist not found.",
"requestId": "reference-not-found-001",
"retryable": false
}
}401 — local sandbox only
HTTP/1.1 401 Unauthorized
Cache-Control: no-store, private
Content-Type: application/json
X-Request-Id: sandbox-auth-001
{
"schema": "casset.error.v1",
"error": {
"code": "INVALID_CREDENTIAL",
"message": "A valid Bearer sandbox credential is required.",
"requestId": "sandbox-auth-001",
"retryable": false
}
}403 — local sandbox console permission failure only
HTTP/1.1 403 Forbidden
Cache-Control: no-store, private
Content-Type: application/json
X-Request-Id: sandbox-permission-001
{
"schema": "casset.error.v1",
"error": {
"code": "PERMISSION_DENIED",
"message": "The app belongs to a different sandbox developer.",
"requestId": "sandbox-permission-001",
"retryable": false
}
}429 — public rate limit
HTTP/1.1 429 Too Many Requests
Cache-Control: private, no-store
Content-Type: application/json
Retry-After: 17
X-Request-Id: reference-rate-001
{
"schema": "casset.error.v1",
"error": {
"code": "RATE_LIMITED",
"message": "Too many requests. Try again after the retry window.",
"requestId": "reference-rate-001",
"retryable": true
}
}503 — public service failure
HTTP/1.1 503 Service Unavailable
Cache-Control: private, no-store
Content-Type: application/json
X-Request-Id: reference-service-001
{
"schema": "casset.error.v1",
"error": {
"code": "INTEGRATION_FAILURE",
"message": "The public catalog service is temporarily unavailable.",
"requestId": "reference-service-001",
"retryable": true
}
}Privacy behavior
- Private, unpublished, and unknown artists are indistinguishable at the HTTP boundary.
- Catalog reads select only active Track title, kind, and duration.
- Strict SDK parsers reject unknown response fields instead of silently accepting data expansion.
- Error responses use
private, no-store; sandbox responses useno-store, private.
Read Errors for the full typed-error matrix and Retries before implementing custom transport behavior.