toktik — Python SDK for the TokTik Developer API
Typed Python client for the TokTik Developer API: the full REST data-plane plus a realtime
(asyncio) LIVE-event client. Feature parity with @toktikhq/sdk-js; the contract source
of truth is @v2/contracts / the served GET /openapi.json.
from toktik import TokTikClient
client = TokTikClient(api_key="ttk_live_...")
board = client.rankings.official(board="hourly", region="VN")
print(board["provenance"]) # the envelope is never stripped
import asyncio
from toktik import TokTikClient, EventFrame
async def main():
client = TokTikClient(api_key="ttk_live_...")
async for frame in await client.live.stream(["@creator"]):
if isinstance(frame, EventFrame):
print(frame.event, frame.data) # chat / gift / like / ...
asyncio.run(main())
Install
pip install toktik # REST only — zero dependencies
pip install "toktik[realtime]" # adds `websockets` for the realtime client
The REST client speaks HTTP through the standard library, so the data-plane surface pulls in nothing.
The realtime client needs a WebSocket implementation; installing the realtime extra provides it, or
you can pass your own transport (RealtimeStream(connect=...)).
Design
- Provenance is never stripped. Data methods return the parsed JSON envelope unchanged —
{"data": ..., "provenance": {...}}. For observed (rather than officially published) data, that context is part of the answer. The two documented exceptions match the JS SDK:exports.downloadreturns CSV text, andaccount.usageis returned directly (no envelope). - Errors are surfaced, not swallowed. A non-2xx raises
TokTikApiErrorcarryingstatus,code,request_idand helpers (is_payment_requiredfor 402,is_forbiddenfor 403,is_rate_limitedfor 429,retryable). Distinguishing them is the whole point: 402 means buy credits, 403 means the key lacks the scope, 429 means back off. - Argument names are snake_case, mapped to the server's wire names. Every route's Fastify schema
sets
additionalProperties: false, so a wrong query key is a hard 400. The mapping is transcribed from the routes, and a CI parity test asserts every documented data-plane path is covered. - The realtime client owns token lifetime, reconnection and resume. A fresh handshake token is
minted per connection (expiry becomes a reconnect, not a dead socket); reconnects use exponential
backoff with full jitter; and because the gateway keeps no per-connection memory, subscriptions are
re-sent on every open.
queued/active/offline/unavailableare reported honestly.
REST surface
| Namespace | Methods | Scope |
|---|---|---|
client.rankings |
official(board, region, limit), movers(board, region, limit), history(board, region, limit, cursor, league_tier), regions(), games(region) |
rank:read |
client.live |
creator_performance, stream_token, stream |
live:read / live:stream |
client.creators |
list, get, changes, analysis, following, followers |
creator:read |
client.content |
creator_videos, video, video_comments |
content:read |
client.gifters |
list, get, for_creator |
gifter:read |
client.trends |
list(region, type) |
trend:read |
client.exports |
list, create, get, download |
export |
client.account |
entitlements, usage |
keys:manage |
Realtime
await client.live.stream(creator_ids) returns a connected RealtimeStream — an async iterator of
frames:
StatusFrame(creator_id, status, room_id, reason)— subscription lifecycle (queued→active→…, oroffline).EventFrame(event, event_id, creator_id, room_id, sequence, room_state, data, provenance)— a LIVE event (chat,gift,like,member,roomUser,social,control,envelope,goodyBag,unknown).ErrorFrame(code, message, retryable)— a server-side subscription error.
subscribe(id) / unsubscribe(id) change the set mid-stream; aclose() (or async with) stops for
good and cancels reconnection.
The token is minted from platform-api; its wsUrl points at the API host, which nginx routes to the
gateway in production. Driving a local gateway directly, mint the token yourself and pass the
gateway URL — see examples/realtime_demo.py.
Development
python -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"
python -m unittest discover -s tests # 51 tests, no network
mypy && ruff check src tests
The OpenAPI parity snapshot is generated from @v2/contracts (regenerated + diffed in CI):
npm run build --workspace @v2/contracts
node packages/sdk-python/scripts/gen_openapi_snapshot.mjs
0.2.0 (breaking)
live.list_sessions and live.get_session were removed — GET /v1/live/sessions answers 410 endpoint_removed
since 2026-09-24. exports.create now requires dataset and takes every real export: rankings (board, region,
optional game / period), gifters (range_days, optional region / segment), creator_roster, and
creator_gifters (creator_unique_id, optional window). live_sessions is no longer a dataset.
Publishing
Releases are tag-driven through .github/workflows/sdk-release.yml:
git tag sdk-python-v0.2.0
git push origin sdk-python-v0.2.0
The release job builds and checks both the sdist and wheel, installs the wheel into a clean virtual
environment, and publishes with PyPI Trusted Publishing. The PyPI project must trust this repository,
that workflow, and the pypi GitHub environment before the first release.
Known scope limits
- Response bodies are typed
dict(JsonDict), not generated models. The shapes live in@v2/contracts(TypeScript); generating Pydantic models from them was deliberately deferred to avoid silent drift. Method arguments and realtime frames are typed. - Sync REST only. An
asyncioREST client is not yet provided; the realtime client is async, and it mints its token off the event loop viaasyncio.to_thread.
Metadata
Release files for toktik 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| toktik-0.2.0.tar.gz | 27.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| toktik-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 47.8 kB
Release files / toktik-0.2.0.tar.gz
| Download URL | toktik-0.2.0.tar.gz |
|---|---|
| Size | 27.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
810330a8677ec70c7b71e3b4cdc4fdda4c6061b19dc6a647295e81e8c39a3f98
|
|
BLAKE2b-256 checksum How to use checksums |
576d943af5b2a0a5b57102b205a7d6f8d72eca133e23ef795faafb7076108cd4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.
Transparency logRelease files / toktik-0.2.0-py3-none-any.whl
| Download URL | toktik-0.2.0-py3-none-any.whl |
|---|---|
| Size | 20.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b3091c72d34f244c3f038d61b37f7bf11e4f2d083eff66122ff591ad90ff7347
|
|
BLAKE2b-256 checksum How to use checksums |
badfc092062aa505b9f8da06a936771388d008eb937441e1b7be3742323932ce
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.
Transparency log