Developer Docs
SDKs
The official JavaScript and Python clients for the Toktik API: install one, add your key and make your first typed request.
Two official clients wrap the same /v1 contract — both fully typed, over matching namespaces. Every block below shows JavaScript and Python side by side; flip the tabs to your language. Step-by-step guides: Python · Node.js · TikTok LIVE API overview.
| SDK | Package | Version | Targets |
|---|---|---|---|
| JavaScript / TypeScript | @toktikhq/sdk-js | 0.4.1 | v1 |
| Python | toktik | 0.3.1 | v1 |
Install
npm i @toktikhq/sdk-jsPython's realtime client needs the realtime extra — pip install "toktik[realtime]". The JavaScript client ships realtime in the one package.
Initialise
import { TokTikClient } from "@toktikhq/sdk-js";
const client = new TokTikClient({ apiKey: process.env.TOKTIK_API_KEY! });Call the REST API
const board = await client.rankings.official({ board: "hourly", region: "VN" });
console.log(board.data.board); // the ranked rows
const perf = await client.live.creatorPerformance("some.creator", { limit: 20 });Every read resolves to the data wrapped with its provenance. The rankings.official call above returns:
{
"data": {
"board": {
"kind": "official",
"board": "string",
"region": "US+",
"periodKey": "string",
"resetAt": "2026-09-28T11:00:00Z",
"publishable": true,
"coverage": {
"completeBoards": 1,
"expectedBoards": 1,
"ratio": 1,
"threshold": 1
},
"game": {
"gameKey": "string",
"gameTitle": "string"
},
"entries": [
{
"rank": 1,
"creatorUid": "string",
"uniqueId": "example_creator",
"nickname": "Example Creator",
"avatarUrl": "https://…",
"isLive": true,
"roomId": "string",
"score": 12840,
"leagueClass": "string",
"leagueClassSource": "observed",
"leagueClassAsOf": "2026-09-28T11:00:00Z",
"movement": "up",
"previousRank": 1,
"masked": false,
"unmaskTier": "string",
"sourceRegion": "US+",
"isLivePro": true
}
]
}
},
"provenance": {
"observedAt": "2026-09-28T11:00:00Z",
"freshness": "near_realtime",
"source": "rank-worker",
"coverageStatus": "observed",
"methodologyVersion": "v1"
}
}Realtime
import { TokTikClient } from "@toktikhq/sdk-js";
const client = new TokTikClient({ apiKey: process.env.TOKTIK_API_KEY! });
const stream = await client.live.stream(["@creator_handle"], {
onStatus: (s) => console.log("status", s.creatorId, s.status), // queued → active
onEvent: (frame) => {
if (frame.event === "gift") {
const g = frame.data.decoded;
if (g.isCompleted) console.log(g.gift?.giftName, (g.gift?.diamondCount ?? 0) * g.repeatCount);
}
},
onError: (e) => console.error(e),
onReconnect: (attempt) => console.warn("reconnected", attempt)
});
// later: await stream.close();Errors & retries
import { TokTikClient, TokTikApiError } from "@toktikhq/sdk-js";
try {
await client.creators.get("someone");
} catch (err) {
if (err instanceof TokTikApiError) {
if (err.isPaymentRequired) {/* 402 — top up credits */}
else if (err.status === 403) {/* missing scope */}
else if (err.retryable) {/* 429 / 5xx — back off and retry */}
}
}Namespaces
Both clients expose the same namespaces over the same scopes:
| Namespace | JavaScript | Python | Scope |
|---|---|---|---|
rankings | official | official | rank:read |
livePro / live_pro | directory, regions | directory, regions | live-pro:read |
recruit | list, mark, unmark, marks | list, mark, unmark, marks | rank:read / watchlist:manage |
live | creatorPerformance, streamToken, stream | creator_performance, stream_token, stream | live:read / live:stream |
creators | list, get, changes, analysis, following, followers | list, get, changes, analysis, following, followers | creator:read |
content | creatorVideos, video, videoComments | creator_videos, video, video_comments | content:read |
gifters | list, get, forCreator | list, get, for_creator | gifter:read |
agencies | list, get, regions | list, get, regions | agencies:read |
trends | list | list | trend:read |
exports | list, create, get, download | list, create, get, download | export |
account | entitlements, usage | entitlements, usage | keys:manage |
Recipes
Common tasks, in both languages. Each is a real call sequence against the shipped surface.
Poll a leaderboard every hour and store it
A cron job that pulls the official board and persists the rows.
const { data } = await client.rankings.official({ board: "hourly", region: "VN" });
await db.saveBoard(data.board);Watch one creator's gifts in realtime
Subscribe to a single creator and total each finished gift streak.
const stream = await client.live.stream(["@creator_handle"], {
onEvent: (f) => {
if (f.event === "gift" && f.data.decoded.isCompleted) {
const g = f.data.decoded;
console.log(g.gift?.giftName, (g.gift?.diamondCount ?? 0) * g.repeatCount);
}
}
});Export a board to CSV
Kick off a bulk export, poll until it is ready, then download the CSV text.
const job = await client.exports.create({ dataset: "rankings", board: "daily", region: "VN", format: "csv" });
// poll client.exports.get(job.id) until status is ready, then:
const csv = await client.exports.download(job.id); // CSV text, not JSONVersioning
Both SDK lines target the v1 API. The API is versioned in its path (/v1) and only ever grows compatibly within a major — see Versioning. Pin the SDK version in your lockfile; upgrading within the v1 line is additive.