Python SDK
Typed sync and async Python client backed by httpx: domain resources, client/geo matrix defaults, automatic cursor pagination, one-call multipart publishing and credit telemetry.
Installation
Requires Python 3.10+. Install from PyPI or directly from the repository subdirectory:
pip install tikultraSync and async clients
Import TikUltra for synchronous pipelines or AsyncTikUltra for asyncio workloads. Both read TIKULTRA_KEY from the environment if api_key is omitted and pool persistent HTTP/2-ready connections when used as context managers.
1from tikultra import TikUltra
2
3with TikUltra(api_key="tu_live_...") as client:
4 video = client.video.get("7705852133855161377")
5 profile = client.user.profile("acme")
6 pdp = client.shop.pdp("1729481038291048421")
7 print(video["aweme_id"], profile["user"]["unique_id"], pdp.credits_cost)
Every resource namespace maps 1:1 to the gateway surface: client.video, client.user, client.feed, client.search, client.tako, client.creator, client.douyin, client.shop, client.live, client.series, client.music, client.hashtag, client.account, client.devices, client.crypto and client.jobs, plus client.resolve(...), client.id_converter(...), client.translate(...) and raw client.request(method, path, ...).
Client & geo matrix defaults
Pin default os, app_flavour, app_version, region, city or device_id once on the client constructor, and override any field per call via keyword arguments:
1from tikultra import TikUltra
2
3with TikUltra(
4 api_key="tu_live_...",
5 os="android",
6 app_flavour="tiktok",
7 app_version="47.5.41",
8 region="US",
9 city="los_angeles",
10) as client:
11 # Uses Los Angeles Android 47.5.41 defaults
12 us_fyp = client.feed.persona_fyp("specialty coffee")
13
14 # Per-call override: run on iOS TikTok 47.5.0 out of Tokyo
15 jp_search = client.search.query(
16 "matcha latte",
17 os="ios",
18 app_version="47.5.0",
19 region="JP",
20 city="tokyo",
21 )
Automatic cursor pagination
client.paginate(...) walks any paginated GET or POST endpoint using the unified { cursor, has_more } contract and stops automatically when has_more is false or max_pages is reached:
1from tikultra import TikUltra
2
3with TikUltra(api_key="tu_live_...") as client:
4 for page in client.paginate("GET", "/v1/video/comments", params={"aweme_id": "7705852133855161377", "count": 50}, max_pages=10):
5 for comment in page["comments"]:
6 print(comment["cid"], comment["text"])
Multipart video & slideshow publishing
Pass file paths, raw bytes, or binary streams directly to client.account.upload_video and client.account.upload_slideshow:
1from tikultra import TikUltra
2
3with TikUltra(api_key="tu_live_...") as client:
4 post = client.account.upload_video(
5 account_id="acc_creator_01",
6 file="launch.mp4",
7 caption="Launching v2 today #devtools #engineering",
8 visibility="public",
9 )
10 carousel = client.account.upload_slideshow(
11 account_id="acc_creator_01",
12 files=["slide_1.jpg", "slide_2.jpg"],
13 title="Architecture notes",
14 caption="Swipe through the latency breakdown",
15 )
16 print(post["aweme_id"], carousel["aweme_id"])
Response credit & trace metadata
Every SDK call returns an APIResponse wrapper that behaves like the decoded dictionary (res["aweme_id"], "items" in res) while exposing typed gateway headers:
| Attribute | Type | Description |
|---|---|---|
res.data | dict[str, Any] | Decoded JSON response payload |
res.credits_cost | int | Credits charged for this call (x-credits-cost, 0 on errors) |
res.credits_tier | str | None | Billing tier (primitive, standard, heavy, premium) |
res.credits_remaining | int | None | Remaining key balance (x-credits-remaining) |
res.request_id | str | None | Gateway trace ID (x-request-id) |
res.cursor / res.has_more | str | None / bool | Normalized pagination state on list responses |
Typed exception handling
Transient 429 and 5xx responses are retried automatically up to max_retries (default 2), honoring Retry-After. Non-retryable or exhausted failures raise typed subclasses of TikUltraError:
1from tikultra import (
2 TikUltra,
3 AuthenticationError,
4 InsufficientCreditsError,
5 PermissionDeniedError,
6 RateLimitError,
7 UpstreamError,
8)
9
10with TikUltra(api_key="tu_live_...", max_retries=3) as client:
11 try:
12 res = client.video.get("7705852133855161377")
13 except RateLimitError as err:
14 print("Rate limited, retry after:", err.retry_after, err.request_id)
15 except InsufficientCreditsError as err:
16 print("Top up key balance:", err.code, err.credits_cost)
17 except (AuthenticationError, PermissionDeniedError) as err:
18 print("Auth or plan gate:", err.status_code, err.code)
19 except UpstreamError as err:
20 print("Upstream mobile error (0 credits charged):", err.request_id)