API Reference

Connect Tracklyst to Zapier and other tools — read your playlists, comments, and track approvals programmatically.

API access is part of the Enterprise plan, which isn't publicly available yet. If you're interested, reach out at support@tracklyst.app and we'll be in touch as it opens up.

Authentication

Every request needs an API key, generated from Settings → API Access once your account is on the Enterprise plan. Send it as a Bearer token:

Authorization: Bearer tlk_your_key_here

Keys are shown in full exactly once, at creation time — Tracklyst only ever stores a hash of it. If you lose a key, generate a new one and revoke the old one from Settings.

A request with a missing, invalid, or revoked key returns 401. A request from a key whose account isn't on the Enterprise plan returns 403 — this is checked on every request, not just when the key was created.

Base URL

https://tracklyst.app/api/v1

If you're on a branded subdomain (e.g. yourname.tracklyst.app), the API is available there too — either works.

Endpoints

GET/playlists

Lists your playlists.

curl https://tracklyst.app/api/v1/playlists \
  -H "Authorization: Bearer tlk_your_key_here"
{
  "playlists": [
    {
      "id": "697a5814-fd28-432c-85af-eb67b484db7f",
      "name": "Band Reeves playlist",
      "status": "active",
      "createdAt": "2026-08-13T00:00:00.000Z",
      "liveUrl": "https://you.tracklyst.app/?live=61e00d75c90369d3",
      "frozenUrl": "https://you.tracklyst.app/?id=d4e1c80658414816"
    }
  ]
}

status is "active" or "done" (set manually from the dashboard). liveUrl always points at the playlist's latest Save; frozenUrl is a snapshot that never changes — either can be null if that link hasn't been created yet.

GET/playlists/:id

Full detail for one playlist — description, track list, and settings, none of which are in the list response above. :id is the id field from /playlists.

curl https://tracklyst.app/api/v1/playlists/697a5814-fd28-432c-85af-eb67b484db7f \
  -H "Authorization: Bearer tlk_your_key_here"
{
  "id": "697a5814-fd28-432c-85af-eb67b484db7f",
  "name": "Band Reeves playlist",
  "status": "active",
  "createdAt": "2026-05-30T04:19:13.745Z",
  "liveUrl": "https://you.tracklyst.app/?live=61e00d75c90369d3",
  "frozenUrl": "https://you.tracklyst.app/?id=d4e1c80658414816",
  "description": null,
  "trackNames": ["Honest pt 1", "Honest pt 2", "Honest pt 3"],
  "settings": {
    "downloadMode": "none",
    "allowEmailFeedback": true,
    "seamlessPlayback": true,
    "lufsTarget": -14,
    "themeBg": "default",
    "themeAccent": "lime"
  }
}

Reflects the playlist's latest Save, not a stale snapshot — trackNames and settings update every time the creator saves. A playlist that's never had a Live Link generated (rare — only very old or virtual-folder playlists) returns settings: null and an empty trackNames.

GET/comments

Lists listener comments across all your playlists, newest first.

ParamDescription
playlistIdOptional — limit to one playlist's id from /playlists.
sinceOptional — ISO 8601 timestamp; only returns comments created after it. Useful for polling for what's new since your last check.
curl "https://tracklyst.app/api/v1/comments?since=2026-09-01T00:00:00Z" \
  -H "Authorization: Bearer tlk_your_key_here"
{
  "comments": [
    {
      "id": "a1b2c3d4-...",
      "playlistId": "697a5814-fd28-432c-85af-eb67b484db7f",
      "playlistName": "Band Reeves playlist",
      "listenerName": "Sydney",
      "text": "I love the beat you added Aaron!",
      "createdAt": "2026-07-21T10:12:00.000Z",
      "resolvedAt": null
    }
  ]
}

GET/approvals

Lists listener track approvals across all your playlists, newest first. Same playlistId and since params as /comments.

curl https://tracklyst.app/api/v1/approvals \
  -H "Authorization: Bearer tlk_your_key_here"
{
  "approvals": [
    {
      "id": "e5f6...",
      "playlistId": "697a5814-fd28-432c-85af-eb67b484db7f",
      "playlistName": "Band Reeves playlist",
      "trackName": "Big Shoes V2",
      "approvedBy": "Sydney",
      "approverEmail": "sydney@example.com",
      "createdAt": "2026-08-01T18:30:00.000Z"
    }
  ]
}

Errors

Errors are always JSON with an error field:

{ "error": "Invalid or missing API key" }
StatusMeaning
401Missing, invalid, or revoked API key.
403Valid key, but the account isn't on the Enterprise plan.
405Wrong HTTP method — all current endpoints are GET.
429Rate limit exceeded — see below. Check the Retry-After header for how many seconds to wait.
500Something went wrong on our end — safe to retry.

Rate limits

Each API key is limited to 60 requests per minute. This applies per key, not per account — if you need more, generate a separate key for each integration rather than sharing one.

Exceeding it returns 429 with a Retry-After header (seconds until the window resets).

GET/usage

Reports the calling key's remaining quota. Counts against the same limit as any other request — checking usage isn't free.

curl https://tracklyst.app/api/v1/usage \
  -H "Authorization: Bearer tlk_your_key_here"
{ "limit": 60, "remaining": 57, "resetsAt": "2026-09-11T22:03:50.419Z" }

Webhooks

Instead of polling /comments or /approvals, register a URL from Settings → API Access and Tracklyst will POST to it the moment a new comment or approval comes in.

Each webhook fires on comment.created, approval.created, or all, whichever you chose when creating it. A delivery looks like:

{
  "event": "comment.created",
  "timestamp": "2026-09-11T18:04:00.000Z",
  "data": {
    "playlistId": "697a5814-fd28-432c-85af-eb67b484db7f",
    "playlistName": "Band Reeves playlist",
    "listenerName": "Sydney",
    "text": "I love the beat you added Aaron!",
    "createdAt": "2026-09-11T18:04:00.000Z"
  }
}

approval.created payloads use trackName, approvedBy, and approverEmail instead of listenerName/text — see the /approvals example above for the field shapes.

Slack & Discord

Set format to slack or discord when creating a webhook (default is generic, the raw payload above) and point the URL at a Slack or Discord Incoming Webhook — created from that channel's own integration settings, no Tracklyst-side app install needed. Deliveries become a short plain-text message instead of the JSON envelope:

💬 Sydney commented on "Band Reeves playlist": I love the beat you added Aaron!

Slack/Discord format deliveries aren't signed — the webhook URL itself is the credential those platforms expect, and they don't check an X-Tracklyst-Signature header anyway.

Verifying a delivery

Every request carries an X-Tracklyst-Signature header in the form t=<unix timestamp>,v1=<hex signature>. The signature is an HMAC-SHA256 of {timestamp}.{raw body}, keyed with the webhook's signing secret (shown in Settings when you create it, and always visible there afterward). Recompute it yourself and compare — and reject anything with a timestamp more than a few minutes old, to guard against replay.

Delivery is best-effort: one attempt, no retries yet. Your endpoint has 3 seconds to respond for comment.created, or 2 seconds for approval.created — after that we give up and move on. Check Settings → API Access to see each webhook's last delivery status if something doesn't show up.

Webhook URLs must be https and can't point at localhost or private/internal network addresses.

SoundFlow

Tracklyst's API works both directions with SoundFlow scripts, using the same key and endpoints described above — nothing SoundFlow-specific to set up on Tracklyst's side.

Calling Tracklyst from a Soundflow

A Soundflow script makes requests with sf.net.httpRequest(), same as any other endpoint on this page — just set the Bearer header:

var response = sf.net.httpRequest({
  url: 'https://tracklyst.app/api/v1/approvals?playlistId=' + playlistId,
  method: 'GET',
  headers: { Authorization: 'Bearer tlk_your_key_here' },
}).asJson();

if (response.approvals.length) {
  sf.ui.notify('✅ ' + response.approvals[0].trackName + ' approved by ' + response.approvals[0].approvedBy);
}

Useful triggers: a hotkey that checks approval status before you bounce a deliverable, or that pulls unresolved comments for the session you're mixing and shows them in a SoundFlow prompt instead of switching to a browser tab.

Reacting to Tracklyst from SoundFlow

SoundFlow doesn't expose an inbound webhook endpoint of its own, so instead of pushing to it, poll /comments or /approvals with since set to the last time you checked — the same parameter documented under Endpoints above. Store the cursor in Soundflow's globalState:

var since = globalState.tracklystLastCheck || new Date(Date.now() - 24*60*60*1000).toISOString();

var comments = sf.net.httpRequest({
  url: 'https://tracklyst.app/api/v1/comments?since=' + since,
  method: 'GET',
  headers: { Authorization: 'Bearer tlk_your_key_here' },
}).asJson().comments;

comments.filter(c => !c.resolvedAt).forEach(c =>
  sf.ui.notify('💬 ' + c.listenerName + ' on ' + c.playlistName + ': ' + c.text)
);

globalState.tracklystLastCheck = new Date().toISOString();

globalState only lasts for the current SoundFlow session — it resets when SoundFlow restarts, so the first check after a restart falls back to the last 24 hours rather than replaying your whole history. Bind this to a hotkey ("check Tracklyst") to pull on demand; if your SoundFlow version has a scheduled/timer trigger it can run automatically, but check your own trigger list — we haven't been able to confirm that trigger type is available in all versions.

New approvals are a natural cue to fire a bounce/deliverable macro; new unresolved comments pair well with a notification or a studio-light cue, the same pattern as SoundFlow's own Home Assistant tutorial — Tracklyst just replaces Home Assistant as the thing being polled.

Roadmap

Writing data (creating playlists, sending recipient links) and a hosted Zapier app are planned but not built yet.