Trace
Datasets & Ingest
Upload your songs, group them into datasets, and ingest them. Ingestion analyses each song once and stores the result, so every later search only compares stored layers.
- Upload songs
- Create a dataset
- List and view datasets
- Dataset tracks
- Delete a dataset
- Ingest songs
- Ingestion status
- Legacy upload and library
Upload songs
Every Trace request identifies a song by the file_id of a file in your account. Upload each song once and keep its file_id. Uploading is free.
Getting a file_id
Upload the file via POST /v1/files — either {"source_url": "..."} if you already host it, or a multipart/form-data file part (up to 100 MiB) to upload bytes directly. Both return a file_id owned by your account.
curl -X POST https://apiv2.soundverse.ai/v1/files \
-H "Authorization: Bearer sksoundverse_..." \
-F "file=@/path/to/song.mp3"201 Created
{
"file_id": "018f0000-0000-7000-8000-000000000001",
"filename": "song.mp3",
"size_bytes": 2927399,
"mime_type": "audio/mpeg"
}Why file IDs
Trace uses the file_id to look up each song’s lyrics, translation and style tags, and to tell you which of your files a result refers to. The lyrics, translation and insights layers can only be produced for songs given by file_id.
Create a dataset
POST/trace/v3/datasetcreate a named collection of songs
A dataset is a named collection of songs that you search against. Datasets are private to your account, and every dataset endpoint is free.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| name | string | Yes | — | Unique within your account. You refer to the dataset by this name in ingest and search requests. |
| description | string | No | "" | A note for your own reference. |
curl -X POST https://apiv2.soundverse.ai/trace/v3/dataset \
-H "Authorization: Bearer sksoundverse_..." \
-H "Content-Type: application/json" \
-d '{"name": "reference-catalog", "description": "Our main catalog"}'201 Created
{
"dataset_id": "018f0000-0000-7000-8000-0000000000d1",
"user_id": "018f0000-0000-7000-8000-0000000000e1",
"name": "reference-catalog",
"description": "Our main catalog",
"created_at": "2026-10-15T18:24:27.512301",
"ingested_tasks": [],
"encoder_types": []
}Creating a second dataset with the same name returns 409 with a detail message.
List and view datasets
GET/trace/v3/datasetevery dataset in your account
GET/trace/v3/dataset/{dataset_id}one dataset
200 OK
[
{
"dataset_id": "018f0000-0000-7000-8000-0000000000d1",
"user_id": "018f0000-0000-7000-8000-0000000000e1",
"name": "reference-catalog",
"description": "Our main catalog",
"created_at": "2026-10-15T18:24:27.512301",
"ingested_tasks": ["full_audio_latent", "light_stem", "motif"],
"encoder_types": ["type3"]
}
]| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| ingested_tasks | string[] | No | — | The layers ingested into this dataset, by internal task name. See the depth-to-task table under Ingest songs. |
| encoder_types | string[] | No | — | The Trace model used. Currently always type3. |
GET /trace/v3/dataset/{dataset_id} returns one entry of that list, or 404 with "dataset not found" when the dataset does not exist or belongs to another account.
Dataset tracks
GET/trace/v3/dataset/{dataset_id}/tracksper-song ingestion state
Lists every song in a dataset and which of its layers are ready. Use it to confirm a dataset is ready before you search, and to map Trace’s audio IDs back to your own file IDs.
200 OK
{
"dataset_id": "018f0000-0000-7000-8000-0000000000d1",
"track_count": 2,
"tracks": [
{
"audio_id": "d79efad889c32e5537210f024e073632ec65fb9b5feb8576e91cad7c2bdc0466.mp3",
"source_ref": "018f0000-0000-7000-8000-000000000001",
"completed_tasks": ["full_audio_latent", "light_stem", "motif"],
"running_tasks": [],
"pending_tasks": []
},
{
"audio_id": "e4a4d5f567804d885eb41b56ad039079049f9f11a10ae743f397a42504ad6bea.mp3",
"source_ref": "018f0000-0000-7000-8000-000000000002",
"completed_tasks": ["full_audio_latent"],
"running_tasks": ["light_stem", "motif"],
"pending_tasks": []
}
]
}| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| track_count | integer | No | — | Songs with at least one finished layer. |
| audio_id | string | No | — | Trace's identifier for the song. Search results refer to songs by this ID. |
| source_ref | string | No | — | The file_id you ingested this song from. Empty for songs ingested from a legacy blob_name. |
| completed_tasks | string[] | No | — | Layers that are ready to search. |
| running_tasks | string[] | No | — | Layers being processed now. |
| pending_tasks | string[] | No | — | Layers not finished yet: queued, or failed in an earlier ingestion. Ingest the song again to retry them. |
Delete a dataset
DELETE/trace/v3/dataset/{dataset_id}delete the dataset and its analysis
Deletes the dataset and everything Trace derived from it. Your uploaded source files are not deleted.
200 OK
{
"message": "Dataset deleted",
"dataset_id": "018f0000-0000-7000-8000-0000000000d1",
"artifact_rows_deleted": 11,
"blobs_deleted": 4,
"vectors_deleted": 1
}| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| 404 | not found | No | — | The dataset does not exist or belongs to another account. |
| 409 | busy | No | — | An ingestion into this dataset is still running. Wait for it to finish, then retry. |
Deletion cannot be undone. Searches that name a deleted dataset will fail.
Ingest songs
POST/trace/v3/ingestanalyse songs and add them to a dataset
Analyses one or more songs and adds them to an existing dataset. The request returns a job_id immediately; poll it as shown under Ingestion status.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| dataset_name | string | Yes | — | Name of an existing dataset to add the songs to. |
| audio_file_ids | string[] | Yes | — | file_id values from POST /v1/files. Provide at least one song here or in audio_blobs. |
| depth | string | string[] | No | ["track", "light_stem", "motif"] | The layers to prepare. See the table below. |
| budget_tokens | integer | No | no cap | Optional cap on what this job may cost. See Results & Billing. |
| audio_blobs | string[] | No | — | Legacy alternative to audio_file_ids: blob_name values from POST /trace/v3/upload. |
| tasks | string[] | No | — | Legacy alternative to depth, using the internal task names below. |
Depths and what they prepare
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| track | full mix | No | — | Prepares full_audio_latent. |
| light_stem | vocals + accompaniment | No | — | Prepares light_stem. |
| stem | 4 instruments | No | — | Prepares stem_vocals, stem_bass, stem_drums and stem_other. |
| section | structure | No | — | Prepares section. |
| motif | melody | No | — | Prepares motif. |
| lyrics | text | No | — | Prepares lyrics, plus light_stem. |
| translation | text | No | — | Prepares translation, plus lyrics and light_stem. |
| insights | tags | No | — | Prepares audio_to_text. |
With no depth, Trace prepares track, light_stem and motif — everything the comprehensive search needs. For a use case, ingest the depths listed on Use Cases. Ingestion is incremental: layers a song already has are skipped and not recomputed.
curl -X POST https://apiv2.soundverse.ai/trace/v3/ingest \
-H "Authorization: Bearer sksoundverse_..." \
-H "Content-Type: application/json" \
-d '{
"dataset_name": "reference-catalog",
"audio_file_ids": [
"018f0000-0000-7000-8000-000000000001",
"018f0000-0000-7000-8000-000000000002"
],
"depth": ["track", "light_stem", "motif", "section"]
}'201 Created
{"job_id": "018f0000-0000-7000-8000-0000000000a1", "status": "queued"}lyrics and translation need vocals, so they cannot be produced for instrumental tracks. They also need file_id inputs.
Validation errors
These return 422 InvalidGenerationInput; nothing is queued or charged.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| dataset_name is required | 422 | No | — | dataset_name is missing. |
| audio_file_ids (or audio_blobs) must not be empty | 422 | No | — | No songs were given. |
| unknown depth 'x' | 422 | No | — | A depth value is not in the table above. |
| unknown task 'x' | 422 | No | — | A tasks value is not a known task name. |
| audio_blobs takes a blob_name …, not a url | 422 | No | — | A full URL was passed. Upload the file with POST /v1/files and pass its file_id instead. |
Ingestion status
GET/trace/v3/ingest/{job_id}same response as /trace/v3/jobs/{job_id}
Returns the job’s status and, once it has completed, the state of every layer in the dataset. Polling is free.
200 OK
{
"success": true,
"data": {
"job_id": "018f0000-0000-7000-8000-0000000000a1",
"status": "completed",
"error": null,
"results": {
"job_id": "5c1d8e2a-3f4b-4c6d-9e7f-0a1b2c3d4e5f",
"dataset_id": "018f0000-0000-7000-8000-0000000000d1",
"status": "completed",
"tasks_requested": ["full_audio_latent", "light_stem", "motif"],
"error": null,
"artifacts": [
{
"audio_id": "e4a4d5f567804d885eb41b56ad039079049f9f11a10ae743f397a42504ad6bea.mp3",
"artifact_type": "full_audio_latent",
"status": "complete"
}
]
}
}
}| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| data.status | string | No | — | pending (queued), processing, completed or failed. A failed job is not charged. |
| data.error | string | null | No | — | Why the job failed, when status is failed. |
| data.results.artifacts | object[] | No | — | One entry per song and layer, each with its own status: pending, running, complete or failed. |
| data.results.job_id | string | No | — | Trace's internal reference for the ingestion. Poll with data.job_id. |
A job can complete while one layer of one song failed (for example lyrics on an instrumental). Check Dataset tracks to see exactly which layers are searchable.
Legacy upload and library
POST/trace/v3/uploadupload into Trace storage, returns a blob_name
GET/trace/v3/librarylist legacy uploads
These endpoints remain for existing integrations. POST /trace/v3/upload takes one or more multipart/form-data files (.mp3, .wav, .flac or .m4a) and returns a blob_name you can pass as query_url, candidate_url or in audio_blobs. GET /trace/v3/library lists those uploads. Files uploaded with POST /v1/files do not appear there.
Prefer POST /v1/files
A blob_name has no file identity, so lyrics, translation and insights cannot be produced for it, and results cannot be mapped back to your files. New integrations should use POST /v1/files.