---
title: "Bulk resolve"
method: POST
path: "/v1/tracks/resolve"
tags: ["Tracks"]
---

# Bulk resolve

`POST /v1/tracks/resolve`

## Request

- Base URL: `https://api.sonovault.now`
- URL: `https://api.sonovault.now/v1/tracks/resolve`
- Auth: API key in header `x-api-key`

Resolve up to 100 inputs (track names, ISRCs, or platform IDs) in a single request to canonical Sonovault tracks plus their cross-platform links. One credit is charged per input line. If your monthly quota runs out mid-batch the response is partial: unresolved lines come back with status `skipped_no_credits` instead of an error.

**Response**

- `results` - one entry per input line, in input order: `{ input, status, track, links }`, where `status` is `matched`, `not_found`, or `skipped_no_credits`.

- `partial`, `processed`, `credits_used`, `credits_remaining`, `message` - the batch billing summary.

## Request body

- object
  - `input_type` string, required: one of `track_name`, `isrc`, `sonovault_id`, `spotify_id`, `applemusic_id`, `tidal_id`, `beatport_id`, `discogs_id`, `musicbrainz_id`.
  - `items` string, required: 1 to 100 entries. For `track_name`, each entry is an object `{ artist, title }`; for every other input type, each entry is a string.

## Response `200`

Successful response

- object
  - `results` ResolveResult[], required: One row per input line, in the order you sent them.
    - `input` string, required: The input value this row answers, echoed back. For `track_name` input this is the artist and title joined.
    - `status` 'matched' | 'not_found' | 'skipped_no_credits', required: `matched` when a track was resolved, `not_found` when nothing matched, `skipped_no_credits` when your monthly quota ran out mid-batch.
    - `track` Track, required: The public track shape, returned by search, ISRC/ID lookup, browse and resolve. Tempo (`bpm`) and musical key come from our own analysis of the audio; other audio features (energy, danceability, popularity) are not part of the public API.
      - `id` integer, required: Sonovault track ID. Stable, and the id every other endpoint takes.
      - `title` string, required: Track title, including any mix or version suffix.
      - `releases` TrackRelease[], required: The release we treat as representative for this recording, as a one-element array. We pick it by release type, then a title match, then earliest date, so a track that appeared on twenty compilations still reports the release it belongs to.
        - `id` integer, required: Release ID. Use it with `GET /v1/releases/:id`.
        - `title` string, required: Release title.
        - `artist` ArtistRef, required: A minimal artist reference. Artists are always nested objects on the public API, never a flat `artist_name` column.
          - `id` integer, required: Artist ID.
          - `name` string, required: Artist name.
        - `label` LabelRef, required: A minimal label reference.
          - `id` integer, required: Label ID.
          - `name` string, required: Label name.
        - `release_date` string, nullable, required: Release date, `YYYY-MM-DD`. `null` when unknown.
      - `artists` TrackArtist[], required: Artist credits, primary artists first.
        - `id` integer, required: Artist ID. Use it with `GET /v1/artists/:id`.
        - `name` string, required: Artist name as credited.
        - `is_primary` boolean, required: `true` for a main artist, `false` for a featured or supporting credit.
        - `is_remixer` boolean, required: `true` when the credit is for a remix of the track.
      - `isrc` string, nullable, required: One representative ISRC. A recording often has several (radio edit, reissue, regional release); look them all up with `GET /v1/tracks/isrc/:isrc`. `null` when no ISRC is known.
      - `duration` integer, nullable, required: Duration in seconds. `null` when unknown.
      - `bpm` number, nullable, required: Tempo in beats per minute, up to two decimals (e.g. `123`, `123.48`). Measured by the Lexicon DJ beat detector on the audio itself, and reported at full tempo: a drum & bass track reads `174`, not the half-time `87`. `null` when the track has not been analysed yet.
      - `key_alphanumeric` string, nullable, required: Musical key in alphanumeric notation: a number from 1 to 12 plus `A` for minor or `B` for major (e.g. `10B`). Keys one step apart on the wheel, or with the same number, mix harmonically. Our preferred key, measured by OpenKeyScan. `null` when the track has not been analysed yet.
      - `key_musical` string, nullable, required: The same key in standard musical notation (e.g. `D`, `Am`, `F#m`, `Ebm`, `Db`). A trailing `m` means minor. `null` when the track has not been analysed yet.
      - `key_open` string, nullable, required: The same key in Open Key notation, lowercase: a number from 1 to 12 plus `d` for major or `m` for minor (e.g. `3d`, `1m`). `null` when the track has not been analysed yet.
      - `keys` TrackKey[], required: Every key we hold for the track, one entry per source, each in all three notations. The single `key_*` fields carry the preferred entry. Empty array when the track has not been analysed yet.
        - `key_alphanumeric` string, required: Alphanumeric notation, e.g. `10B` (1-12, `A` minor, `B` major).
        - `key_musical` string, required: Standard musical notation, e.g. `D`, `F#m`.
        - `key_open` string, required: Open Key notation, lowercase, e.g. `3d` (major) or `1m` (minor).
        - `source` string, required: Who measured this key. Currently always `openkeyscan` (our own analysis with OpenKeyScan). More sources may be added, so treat unknown values as valid.
      - `genre` string[], required: Canonical genres. Empty array when the track is unclassified.
      - `subgenre` string[], required: Canonical subgenres. Empty array when none apply.
    - `links` PlatformLink[], required: Cross-platform links for the resolved track. Empty array when nothing matched.
      - `source` 'spotify' | 'beatport' | 'discogs' | 'musicbrainz' | 'applemusic' | 'tidal' | 'youtube', required: The platform this ID belongs to.
      - `external_id` string, required: The track's ID on that platform.
      - `url` string, nullable, required: Deep link to the track on the platform. `null` when the platform has no stable public URL for it.
  - `partial` boolean, required: `true` when your quota ran out mid-batch and some rows came back `skipped_no_credits`.
  - `processed` integer, required: How many input lines were actually resolved.
  - `credits_used` integer, required: Credits charged for this call, one per resolved line.
  - `credits_remaining` integer, required: Credits left in your monthly quota after this call.
  - `message` string, nullable, required: Explanation when the batch was cut short. `null` on a complete batch.

---

[API](https://skmtc.dev/sonovault/apis/sonovault-api.md) · [All operations](https://skmtc.dev/sonovault/apis/sonovault-api/llms.txt) · [OpenAPI document](https://skmtc.dev/sonovault/apis/sonovault-api/revisions/0152fff23f2c?raw)
