Authentication
How to create, send and revoke an API key, and exchange one for a browser session.
A metered route takes an API key as a bearer token, a few routes take no credential, and the account routes also take a browser session or a Traktor sign-in.
API keys
Create keys on your profile's API tab, up to your plan's API keys limit (Plans and limits). Every key the tab makes starts tk_live_. There is no test mode: a tk_test_ key, which only Traktor issues, reads the same live data under the same limits. A key's last characters are a checksum, so a mistyped key is refused before it is looked up.
Revoke a key on the same tab, and requests with it are refused within seconds, or within 5 minutes when the revocation cannot reach the servers' shared cache. A stream open on it closes with 4003 at the first check after that, which runs every minute, and a webhook made with it, or with a browser session it opened, is posted nothing more. The routes that create and revoke keys take only your Traktor sign-in, so a key cannot make or revoke another.
Sending a key
Send Authorization: Bearer $TRAKTOR_API_KEY with every request. A request without it answers 401 missing_credentials.
Never put a key in a query string. A query parameter named key, apikey, api_key, token, access_token, auth or secret answers 400 key_in_query before the key is checked, on every metered route and on GET /v1/plans and GET /v1/meta/filters. Rotate a key you sent that way: proxies write URLs to their logs.
On the trade stream the key goes in the first frame, auth. A parameter with one of those names in the socket's URL closes the socket with 4015.
When a key is refused
401 invalid_key: the key is malformed or unknown; the two answer alike.401 key_revoked: the key was revoked or has expired, or its account is closed.402 subscription_inactive: the account is suspended.
A malformed or unknown key counts against your IP's budget for refused keys, the "Invalid keys" limit on the endpoint blocks. Once that budget is spent, a key the server must look up again is refused as invalid_key too, even a valid one, until the budget refills. If you are sure of the key, wait a minute and retry. An IPv6 caller counts as its /64.
On the trade stream a refused key closes the socket: 4002 for an invalid or revoked key, 4003 for a suspended account. The market stream refuses one before the upgrade, with the status and code a REST read answers with.
Routes without a credential
GET /v1/plans, GET /v1/meta/filters, GET /v1/alert-capabilities, GET /v1/public/market, GET /v1/public/search and WS /v1/market/stream take no credential. The market stream also takes a key on its handshake, which meters it: Under a key. Traktor will require a sign-in for market data, but does not yet. When it does, these market reads and a market socket with no key will answer 401 sign_in_required to a request without a Traktor sign-in, and a socket opened on a sign-in will close 4003 within two minutes of that sign-in ending; by code, read the market with an API key on the paid routes. Each but GET /v1/alert-capabilities has a per-IP limit, on its endpoint block and in Every limit; GET /v1/plans and GET /v1/meta/filters share one. Once market data needs a sign-in, Traktor can also hold each signed-in account to a budget of its own on the market reads and the market socket, listed beside the per-IP one; until it enforces them, nobody is refused for them.
Account routes
The alert, notification and Telegram link routes, but for minting a group's link code, take any of three bearer tokens: an API key, a browser session (trk_session_…) or a Traktor sign-in (trk_trading_…).
A browser session is opened from an API key by the exchange below. It is stored as a hash, bound to that key, and ends with it.
A Traktor sign-in is traktor.fun's own: its web server sends the token from an httpOnly cookie, so no script can hold one. Use a key or a browser session.
GETandDELETE /v1/browser-sessions/currenttake only a browser session. An API key or a sign-in there answers401 session_required.Routes that take Telegram's signed init data, or only a Traktor sign-in, serve Traktor's web app and its Telegram Mini App, and are not part of this reference, but for
POST /v1/telegram/link-codes, which Alerts lists for the link a group's admin opens.
The exchange reads your key from TRAKTOR_API_KEY; export the sessionToken it returns as TRAKTOR_SESSION_TOKEN to run the two samples after it.
POST /v1/browser-sessions/exchange
Exchanges an API key, sent in the body, for a browser session that dies with the key.
- Credential
- API key, in the body
apiKeystringrequiredbodyThe API key to exchange.
Limits
- Exchanges10 a minute, per IP
- Invalid keys30 a minute, per IP
- Session lifetime12 hours, per request
- Live sessions10 kept; the oldest is revoked, per account
Errors
invalid_api_key, invalid_key, key_revoked, subscription_inactive, account_inactive, invalid_json, invalid_body, unknown_field, body_too_large, method_not_allowed, rate_limited, rate_limit_unavailable, internal_error
curl -s -X POST "https://api.traktor.fun/v1/browser-sessions/exchange" \
-H "Content-Type: application/json" \
-d "{\"apiKey\":\"$TRAKTOR_API_KEY\"}"const response = await fetch("https://api.traktor.fun/v1/browser-sessions/exchange", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ apiKey: process.env.TRAKTOR_API_KEY }),
});
const body = await response.json();import os
import requests
response = requests.post(
"https://api.traktor.fun/v1/browser-sessions/exchange",
json={"apiKey": os.environ["TRAKTOR_API_KEY"]},
)
print(response.json()){
"data": {
"sessionToken": "trk_session_7Yw2c9QeN4kV1pR8tL3xM6bZ0aH5sJ2uF9gD4nK1qE0",
"expiresAt": "2026-10-04T00:00:00.000Z",
"account": {
"id": "5f0c2d1e-8a7b-4c3d-9e2f-1a0b9c8d7e6f",
"email": null,
"name": null,
"plan": "free"
}
},
"meta": {
"requestId": "req_01m40t5ek8b3x7r2mh5q",
"generatedAt": "2026-10-03T12:00:04.210Z",
"asOf": null,
"caveats": []
}
}GET /v1/browser-sessions/current
The account a browser session belongs to, and when it expires.
- Credential
- Browser session (
trk_session_…)
Limits
- Requests120 a minute, per account
- Session checks120 a minute, per IP
- Invalid keys30 a minute, per IP
Errors
session_required, missing_credentials, invalid_key, key_revoked, subscription_inactive, session_expired, sign_in_required, method_not_allowed, rate_limited, rate_limit_unavailable, internal_error
curl -s "https://api.traktor.fun/v1/browser-sessions/current" \
-H "Authorization: Bearer $TRAKTOR_SESSION_TOKEN"const response = await fetch("https://api.traktor.fun/v1/browser-sessions/current", {
headers: { Authorization: `Bearer ${process.env.TRAKTOR_SESSION_TOKEN}` },
});
const body = await response.json();import os
import requests
response = requests.get(
"https://api.traktor.fun/v1/browser-sessions/current",
headers={"Authorization": f"Bearer {os.environ['TRAKTOR_SESSION_TOKEN']}"},
)
print(response.json()){
"data": {
"account": {
"id": "5f0c2d1e-8a7b-4c3d-9e2f-1a0b9c8d7e6f",
"email": null,
"name": null,
"plan": "free"
},
"expiresAt": "2026-10-04T00:00:00.000Z"
},
"meta": {
"requestId": "req_01m40t5ek8b3x7r2mh5q",
"generatedAt": "2026-10-03T12:00:04.210Z",
"asOf": null,
"caveats": []
}
}DELETE /v1/browser-sessions/current
Revokes the browser session that sends it.
- Credential
- Browser session (
trk_session_…)
Limits
- Requests120 a minute, per account
- Session checks120 a minute, per IP
- Invalid keys30 a minute, per IP
Errors
session_required, missing_credentials, invalid_key, key_revoked, subscription_inactive, session_expired, sign_in_required, method_not_allowed, rate_limited, rate_limit_unavailable, internal_error
curl -s -X DELETE "https://api.traktor.fun/v1/browser-sessions/current" \
-H "Authorization: Bearer $TRAKTOR_SESSION_TOKEN"const response = await fetch("https://api.traktor.fun/v1/browser-sessions/current", {
method: "DELETE",
headers: { Authorization: `Bearer ${process.env.TRAKTOR_SESSION_TOKEN}` },
});
console.log(response.status);import os
import requests
response = requests.delete(
"https://api.traktor.fun/v1/browser-sessions/current",
headers={"Authorization": f"Bearer {os.environ['TRAKTOR_SESSION_TOKEN']}"},
)
print(response.status_code)Response 204: no body.