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.
| Param | Description |
|---|---|
| playlistId | Optional — limit to one playlist's id from /playlists. |
| since | Optional — 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" }
| Status | Meaning |
|---|---|
| 401 | Missing, invalid, or revoked API key. |
| 403 | Valid key, but the account isn't on the Enterprise plan. |
| 405 | Wrong HTTP method — all current endpoints are GET. |
| 429 | Rate limit exceeded — see below. Check the Retry-After header for how many seconds to wait. |
| 500 | Something 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.