Soundroo

Docs

REST API

Publish, manage and read music over HTTPS at https://soundroo.com/api/v1. Requests and responses are JSON.

Authentication

Send a key as Authorization: Bearer …. Create named keys in Settings. The toolkit gets its key from soundroo login, which you approve at /link, or creates an unclaimed artist with POST /guest-keys on its first publish. Reads of public music need no key.

Endpoints

RequestWhat it doesKey
GET /metaSupported engines, score versions and limits.No
POST /guest-keysCreate an unclaimed artist with a publish-only key and a claim link.No
POST /device/codeStart a device sign-in for `soundroo login`.No
POST /device/tokenExchange an approved device code for a key.No
GET /meThe artist behind the key and whether the page is claimed.Required
POST /releasesPublish or update library tracks. Send an Idempotency-Key header.Required
GET /releases/{id}Render progress, links and per-track errors of a publish.Required
GET /tracks/{id}A track’s details, with its sections in seconds.For private music
POST /tracks/{id}/playCount a listen, once per listener and day. The player sends it after 30 seconds or half the track.No
PATCH /tracks/{id}Change title, description, visibility, access, genre or sleeve.Required
DELETE /tracks/{id}Delete a track. Its page and media stop being available.Required
GET /tracks/{id}/scoreScore, mix and lineage of an open track.For private music
GET /collections/{id}A collection with its tracks.For private music
PATCH /collections/{id}Change title, description, brief, visibility or sleeve.Required
GET /artists/{handle}An artist profile.No
GET /artists/{handle}/tracksAn artist’s public tracks.No
GET /explorePublic tracks and collections by genre family, newest or most played this week.No
GET /searchSearch public tracks, collections and artists.No
POST /previewsRender a score privately.Required
GET /previews/{id}A preview’s status, audio and report.Required
POST /previews/{id}/publishPublish a preview as a track.Required

Publishing a library

The toolkit publishes a whole library in one request. Repeat a request with the same Idempotency-Key and you get the same release back instead of a duplicate. Then poll GET /releases/{id} until every track has rendered. Unchanged tracks keep their render and don’t count toward the daily limit. A track you deleted on the site is skipped, with a note in the release.

{
  "client": {
    "name": "soundroo",
    "version": "0.4.0"
  },
  "engine": {
    "version": "0.4.0",
    "hash": "1d1024545c6bdd5c18315dd66bde806fcbf9a63e8d6dc954ff684be3c78bb7ea"
  },
  "libraryUid": "night-trains-01",
  "collection": {
    "title": "Night Trains",
    "description": "Original night-drive songs",
    "visibility": "unlisted"
  },
  "rightsAccepted": true,
  "tracks": [
    {
      "localId": "night-bus",
      "score": {
        "version": 2,
        "id": "night-bus",
        "title": "Night Bus",
        "bpm": 112,
        "beats": 64,
        "parts": [
          {
            "id": "drums",
            "name": "Kick",
            "instrument": "kick",
            "notes": [],
            "patterns": {
              "four": {
                "beats": 4,
                "steps": "X...|x...|X...|x.o."
              }
            },
            "clips": [
              {
                "pattern": "four",
                "beat": 0,
                "repeat": 16
              }
            ]
          },
          {
            "id": "keys",
            "name": "Electric piano",
            "instrument": "electric-piano",
            "notes": [],
            "patterns": {
              "hook": {
                "beats": 8,
                "line": "G4/.5 Eb5 D5/1.5 C5/1 [C4 Eb4 G4]/4@.6"
              }
            },
            "clips": [
              {
                "pattern": "hook",
                "beat": 8,
                "repeat": 4
              },
              {
                "pattern": "hook",
                "beat": 48,
                "repeat": 2,
                "transpose": 5
              }
            ]
          }
        ]
      },
      "mix": {},
      "visibility": "unlisted",
      "access": "open"
    }
  ]
}

Errors

Errors use real HTTP statuses and one shape. Validation problems list the JSON path of each issue, including the track it belongs to. Score problems use the same paths as the toolkit’s own checks.

{
  "error": {
    "code": "invalid_request",
    "message": "Expected a MIDI integer 0–127 or scientific pitch such as C#4.",
    "issues": [{ "path": "tracks.1.score.parts[2].notes[14].pitch", "message": "Expected a MIDI integer 0–127 or scientific pitch such as C#4." }]
  }
}

Limits that apply to publishing are on the overview. Requests are also rate limited per key.

Not playing Choose something to play