Skip to main content

Python Quickstart – TokPortal API in 10 Minutes

Run a complete TokPortal workflow from Python: create a bundle (campaign), upload a video via presigned URL, configure it, publish, and fetch analytics. Uses the requests library and Bearer token auth.

1. Install dependencies

pip install requests

2. Set up auth

Store your API key in an environment variable. See Authentication for key generation.

import os
import requests

BASE_URL = "https://api.tokportal.com/v1"
API_KEY = os.environ.get("TOKPORTAL_API_KEY")
if not API_KEY:
raise ValueError("Set TOKPORTAL_API_KEY in your environment")

HEADERS = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}

3. Create a bundle

A bundle provisions an account and video slots. Check Credits for costs.

def create_bundle():
resp = requests.post(
f"{BASE_URL}/bundles",
headers=HEADERS,
json={
"bundle_type": "account_and_videos",
"platform": "tiktok",
"country": "US",
"videos_quantity": 2,
"title": "Python Quickstart Campaign",
},
)
resp.raise_for_status()
data = resp.json()
return data["data"]["bundle_id"]

# Example response:
# {"data": {"bundle_id": "bnd_abc123", "status": "pending_setup", "videos_quantity": 2, ...}, "credits_charged": 29}

4. Upload media via presigned URL

Request a presigned URL, upload the file, then use the returned public_url in video config. See Media Upload.

def upload_video(bundle_id: str, filepath: str) -> str:
# Step 1: Get presigned URL
resp = requests.post(
f"{BASE_URL}/upload/video",
headers=HEADERS,
json={
"filename": os.path.basename(filepath),
"content_type": "video/mp4",
"bundle_id": bundle_id,
},
)
resp.raise_for_status()
upload_data = resp.json()["data"]
upload_url = upload_data["upload_url"]
public_url = upload_data["public_url"]
content_type = upload_data["content_type"]

# Step 2: PUT file to presigned URL (no auth header)
with open(filepath, "rb") as f:
put_resp = requests.put(upload_url, data=f, headers={"Content-Type": content_type})
put_resp.raise_for_status()
return public_url

5. Configure videos

Set description, publish date, and the video URL. Use PUT /bundles/{id}/videos for batch or PUT /bundles/{id}/videos/{position} for a single slot.

def configure_video(bundle_id: str, position: int, video_url: str, description: str, publish_date: str):
resp = requests.put(
f"{BASE_URL}/bundles/{bundle_id}/videos/{position}",
headers=HEADERS,
json={
"video_type": "video",
"description": description,
"target_publish_date": publish_date,
"video_url": video_url,
},
)
resp.raise_for_status()
return resp.json()

# Example response:
# {"data": {"position": 1, "video_type": "video", "status": "configured", ...}}

6. Publish

Submit the bundle for processing. Account must be configured; at least one video must be set.

def publish_bundle(bundle_id: str):
resp = requests.post(f"{BASE_URL}/bundles/{bundle_id}/publish", headers=HEADERS)
resp.raise_for_status()
return resp.json()

# Example response:
# {"data": {"id": "bnd_abc123", "status": "published", "published_at": "2026-02-27T..."}}

7. Check analytics

Once the account is delivered and videos are live, fetch analytics by account_id. Get account_id from the bundle or accounts API.

def get_analytics(account_id: str):
resp = requests.get(
f"{BASE_URL}/accounts/{account_id}/analytics",
headers=HEADERS,
)
resp.raise_for_status()
return resp.json()

# Example response:
# {"data": {"followers_count": 12400, "total_views": 580000, "average_engagement_rate": 7.24, ...}}

Error handling

Errors return JSON with error.code and error.message. Check for INSUFFICIENT_CREDITS, VALIDATION_ERROR, and 401 auth failures before calling resp.raise_for_status().

Full script

Using the functions above:

from datetime import datetime, timedelta

bundle_id = create_bundle()
video_url = upload_video(bundle_id, "./promo.mp4")
publish_date = (datetime.utcnow() + timedelta(days=5)).strftime("%Y-%m-%d")
configure_video(bundle_id, 1, video_url, "Check this out! #python #api", publish_date)
publish_bundle(bundle_id)
print(f"Bundle {bundle_id} published.")

Next steps

Developer Portal · Schedule a call