Track Resources
Everything that hangs off a single track — tags, peaks, lyrics, stems, versions,
artwork and documents, the split sheet, share links, processing status, and
metadata edits. All routes are owner‑scoped to the track’s owner; a track
that isn’t yours returns 404 track_not_found. See Authentication.
Base path: /api/swayzio/v1. Runtime: native→proxy.
Sub‑resources are reached two ways:
- A generic dispatcher at
/v1/tracks/:trackId/:resourcethat handlesGET,PUT, andPATCHfor a fixed set of resource names. - Dedicated paths for actions that don’t fit the generic shape (signed URLs, uploads, version promotion, share links, processing).
The :resource dispatcher
GET /v1/tracks/:trackId/:resource reads a sub‑resource. Supported :resource
values:
:resource | Returns | Notes |
|---|---|---|
tags | TrackTagDetailResponse | ?includeHidden=true to include hidden tags |
peaks | TrackPeaksResponse | 404 peaks_not_found until a waveform exists |
rights | { entries: [], status: { isComplete: false } } | Stub — always empty (see below) |
lyrics | ClientTrackLyricsResponse | provider/model fields redacted |
stems | ClientTrackStemsResponse | storageUri + playbackUrl stripped |
versions | ClientTrackVersionsResponse | playbackUrl stripped per version |
media-assets | artwork + documents | — |
split-sheet | PublicTrackSplitSheetPayload | ownerId omitted throughout |
Writes go through the same dispatcher but only for specific resources:
| Method | :resource | Purpose | Request | Response |
|---|---|---|---|---|
PUT | lyrics | Replace lyric text | updateTrackLyricsRequestSchema | ClientTrackLyricsResponse |
PUT | split-sheet | Replace the split sheet | replaceTrackSplitSheetRequestSchema | PublicTrackSplitSheetPayload |
PATCH | metadata | Edit core track fields | updateTrackMetadataRequestSchema | Track |
An unknown :resource returns 404 track_resource_not_found. A supported
resource with an unsupported method returns 405 method_not_allowed. A
PUT split-sheet whose entries don’t balance returns
422 split_sheet_structural_validation_failed.
GET …/rights is a placeholder. It always returns
{ entries: [], status: { isComplete: false, validationErrors: [], validatedAt } }
regardless of the track. The legacy per‑entry rights model
(trackRightsEntrySchema) is not the live ownership surface —
real rights data lives in the split sheet (GET/PUT …/split-sheet). See
Two rights models.
PATCH /v1/tracks/:trackId/metadata
Edits the track’s user‑facing metadata. At least one field must be present.
Auth: Clerk actor.
Request: updateTrackMetadataRequestSchema — any of title,
artist, isrc, iswc (nullable), releaseDate (YYYY-MM-DD, nullable). An
empty body is rejected with 400.
Response: Track (the updated client DTO).
curl -s -X PATCH https://app.swayzio.com/api/swayzio/v1/tracks/trk_123/metadata \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"Night Drive","artist":"AVR","releaseDate":"2026-05-01"}'PUT /v1/tracks/:trackId/split-sheet
Replaces the track’s split sheet wholesale. The payload is a structured
ownership document — master and writers are required (at least one each),
publishers optional with nested sub‑publishers and collection splits. Shares
are validated for structural balance server‑side.
Auth: Clerk actor.
Request: replaceTrackSplitSheetRequestSchema.
Response: PublicTrackSplitSheetPayload (owner ids stripped at
every level). On a balance failure:
422 { "error": "split_sheet_structural_validation_failed", "issues": [...] }.
curl -s -X PUT https://app.swayzio.com/api/swayzio/v1/tracks/trk_123/split-sheet \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"address": "…",
"intendedUse": "Sync licensing",
"master": [{ "collaboratorId": "col_1", "percentage": 100 }],
"writers": [{ "collaboratorId": "col_1", "percentage": 100 }],
"publishers": []
}'Signed URLs & processing
| Method | Path | Purpose | Auth | Request | Response |
|---|---|---|---|---|---|
GET | /v1/tracks/:trackId/playback-url | Short‑lived signed stream URL | Clerk actor | — | ClientPlaybackUrlResponse |
GET | /v1/tracks/:trackId/download-url | Signed download URL; records a track.downloaded event | Clerk actor | ?assetId= (optional) | downloadUrlResponseSchema |
GET | /v1/tracks/:trackId/processing-status | Per‑lane readiness | Clerk actor | — | ClientTrackProcessingStatus |
POST | /v1/tracks/:trackId/processing/media-intelligence/retry | Re‑dispatch media intelligence | Clerk actor | — | 202 / 200 / 404 |
playback-url strips the internal storageUri from the response;
processing-status reports readiness lanes for playback, waveform, tags,
stems, lyrics, embeddings so a client can poll until a track is fully usable.
retry re‑queues the media‑intelligence pipeline (returns 202 when newly
dispatched, 200 when already running, 404 if the track is unknown).
GET /v1/tracks/:trackId/processing-status
Returns the processing state for every lane plus an asset summary and readiness roll‑up — the canonical thing to poll after a finalize. Internal storage URIs are stripped from asset entries.
Auth: Clerk actor.
Response: clientTrackProcessingStatusSchema — { trackId, stages, assets, remoteDispatches, ingestionRun?, readiness }.
curl -s https://app.swayzio.com/api/swayzio/v1/tracks/trk_123/processing-status \
-H "Authorization: Bearer $TOKEN"Versions
A track can carry multiple audio versions; one is current. Promoting a version swaps which audio plays everywhere the track is referenced.
| Method | Path | Purpose | Auth | Request | Response |
|---|---|---|---|---|---|
POST | /v1/tracks/:trackId/versions/uploads | Create a version upload intent (audio only) | Clerk actor | createTrackVersionUploadRequestSchema | 201 clientCreateUploadResponseSchema |
POST | /v1/tracks/:trackId/versions/:versionId/promote | Promote a version to current | Clerk actor | — | ClientTrackVersionsResponse |
DELETE | /v1/tracks/:trackId/versions/:versionId | Delete a version | Clerk actor | — | ClientTrackVersionsResponse |
versions/uploads returns a signed‑PUT upload intent (same shape as
Uploads); finalize it the same way. Deleting the original
version returns 409 original_version_cannot_be_deleted.
POST /v1/tracks/:trackId/versions/uploads
Creates a signed upload intent for a new audio version of an existing track. Audio only — non‑audio content types are rejected at validation.
Auth: Clerk actor.
Request: createTrackVersionUploadRequestSchema —
{ fileName, contentType, byteSize }.
Response: 201 clientCreateUploadResponseSchema — { uploadId, trackId, assetId, signedUrl, method: "PUT", expiresAt, requiredHeaders, finalizeUrl }. PUT the bytes, then call the finalizeUrl. See
the upload flow.
curl -s -X POST https://app.swayzio.com/api/swayzio/v1/tracks/trk_123/versions/uploads \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"fileName":"night-drive-v2.wav","contentType":"audio/wav","byteSize":48211200}'Artwork & documents
| Method | Path | Purpose | Auth | Request | Response |
|---|---|---|---|---|---|
POST | /v1/tracks/:trackId/artwork/uploads | Cover‑art upload intent (image only) | Clerk actor | createTrackArtworkUploadRequestSchema | 201 clientCreateUploadResponseSchema |
POST | /v1/tracks/:trackId/documents/uploads | Document upload intent (PDF/office/text/image) | Clerk actor | createTrackDocumentUploadRequestSchema | 201 clientCreateUploadResponseSchema |
Both return a signed‑PUT intent finalized the same way as audio uploads. Reads
of the resulting assets come back through GET …/media-assets.
Share links
Private, tokenized links that grant playback of a single track without an
account. Creating a link requires the tracks.share entitlement.
| Method | Path | Purpose | Auth | Request | Response |
|---|---|---|---|---|---|
GET | /v1/tracks/:trackId/share-links | List links (redacted) | Clerk actor | — | { records: ClientTrackShareLink[] } |
POST | /v1/tracks/:trackId/share-links | Create a link | Clerk actor + tracks.share | createTrackShareLinkRequestSchema | 201 TrackShareLinkCreateResponse |
POST | /v1/tracks/:trackId/share-links/:linkId/reset | Rotate the token | Clerk actor + tracks.share | — | link + new token |
DELETE | /v1/tracks/:trackId/share-links/:linkId | Revoke a link | Clerk actor | — | 204 |
The plaintext token is only ever returned once — at create and reset.
Listing returns the redacted ClientTrackShareLink (no raw token,
no Dub provider internals). See Public Share Links for the
unauthenticated consumer side.
POST /v1/tracks/:trackId/share-links
Mints a private playback link. Returns the link record plus the one‑time
plaintext token and a sharePath you can render directly.
Auth: Clerk actor + tracks.share entitlement (else 403 entitlement_required).
Request: createTrackShareLinkRequestSchema — { name?, expiresAt? } (expiresAt must be in the future).
Response: 201 trackShareLinkCreateResponseSchema — the link
fields plus token and sharePath.
curl -s -X POST https://app.swayzio.com/api/swayzio/v1/tracks/trk_123/share-links \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"For the sync brief","expiresAt":"2026-12-31T00:00:00.000Z"}'Split‑sheet share links
| Method | Path | Purpose | Auth | Request | Response |
|---|---|---|---|---|---|
GET | /v1/tracks/:trackId/split-sheet/share-links | List split‑sheet review links | Clerk actor | — | { records: [] } (stub natively) |
POST | /v1/tracks/:trackId/split-sheet/share-links | Create a review link | Clerk actor | createTrackSplitSheetShareLinkRequestSchema | token + sharePath (proxy‑only) |
DELETE | /v1/tracks/:trackId/split-sheet/share-links/:linkId | Revoke a link | Clerk actor | — | revoked (proxy‑only) |
Split‑sheet share links are not fully native yet. The native web surface
serves GET as a stub that always returns { "records": [] }. Create and
delete are proxy‑only — they run only against the Fastify Core API
(createTrackSplitSheetShareLinkRequestSchema →
token + sharePath; DELETE revokes). Don’t rely on these natively until the
flag flips.
Two rights models
There are two distinct ways rights show up, and only one is live:
- Legacy per‑entry rights —
trackRightsEntrySchema, a flat list of collaborator entries with mechanical/performance/sync splits. This backs theGET …/rightsroute, which is currently a stub that always returns empty. - Split sheet (live) — the structured, discriminated document under
GET/PUT …/split-sheet(replaceTrackSplitSheetRequestSchema/PublicTrackSplitSheetPayload). This is the authoritative ownership surface today.
When you need real ownership data, use the split sheet — not /rights.
Related
- Tracks · Uploads · Search
- Public Share Links — the unauthenticated consumer side.
- Conventions · Data Contracts