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.

SDKPackageVersionTargets
JavaScript / TypeScript@toktikhq/sdk-js0.4.1v1
Pythontoktik0.3.1v1

Install

npm i @toktikhq/sdk-js

Python'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:

Response
{
  "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:

NamespaceJavaScriptPythonScope
rankingsofficialofficialrank:read
livePro / live_prodirectory, regionsdirectory, regionslive-pro:read
recruitlist, mark, unmark, markslist, mark, unmark, marksrank:read / watchlist:manage
livecreatorPerformance, streamToken, streamcreator_performance, stream_token, streamlive:read / live:stream
creatorslist, get, changes, analysis, following, followerslist, get, changes, analysis, following, followerscreator:read
contentcreatorVideos, video, videoCommentscreator_videos, video, video_commentscontent:read
gifterslist, get, forCreatorlist, get, for_creatorgifter:read
agencieslist, get, regionslist, get, regionsagencies:read
trendslistlisttrend:read
exportslist, create, get, downloadlist, create, get, downloadexport
accountentitlements, usageentitlements, usagekeys: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 JSON

Versioning

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.