tokportal-mcp
Officialtokportal
TokPortal is the managed social infrastructure API: real TikTok, Instagram and YouTube accounts created, warmed and operated by human account managers in 16+ countries — exposed as a REST API and an MCP server. No OAuth per account, no 25-posts/day cap, no app review.
Docs https://developers.tokportal.com · API base https://app.tokportal.com/api/ext · OpenAPI https://developers.tokportal.com/openapi.json · MCP remote https://app.tokportal.com/api/ext/mcp · Get an API key https://app.tokportal.com/developer/api-keys?utm_source=pypi&utm_medium=readme&utm_campaign=tokportal-python · llms.txt https://developers.tokportal.com/llms.txt
tokportal is the official Python SDK for the TokPortal API (Python 3.9+, typed, standard library only). Every public operation is available as a resource method or through the generated request_operation map.
Install
pip install tokportal30-second quickstart
import os
from tokportal import TokPortal
client = TokPortal(api_key=os.environ["TOKPORTAL_API_KEY"])
# 1. Create a bundle: a fresh managed TikTok account in the USA + 1 video slot.
# Credits are debited now; the account manager is assigned at publish time.
bundle = client.bundles.create({
"bundle_type": "account_and_videos",
"platform": "tiktok",
"country": "USA",
"title": "US launch",
"videos_quantity": 1,
})
bundle_id = bundle["data"]["id"]
# 2. Upload the video straight from disk -> public_url
upload = client.uploads.video_direct("./launch.mp4", bundle_id, content_type="video/mp4")
# 3. Configure the account profile and video slot 1, then publish
client.bundles.configure_account(bundle_id, {
"username": "mybrand.us",
"visible_name": "My Brand",
"biography": "Official account",
})
client.bundles.configure_video(bundle_id, 1, {
"video_type": "video",
"video_url": upload["data"]["public_url"],
"description": "Day 1 - launching in the US #launch",
"target_publish_date": "2026-09-01",
})
client.bundles.publish(bundle_id)
# 4. Later (webhook `account.in_review` / `account.finalized`, or polling):
# saved_account_id is the real delivered account -> read it back
current = client.bundles.get(bundle_id)["data"]
if current.get("saved_account_id"):
account = client.accounts.get(current["saved_account_id"])["data"]
print(account["username"], account["profile_url"])Method names follow the generated resource map (
bundles,uploads,accounts,analytics,webhooks). If a helper does not exist for an operation, useclient.request_operation("<operationId>", path=..., query=..., body=...).
Full example
import os
from tokportal import TokPortal, TokPortalApiError
client = TokPortal(api_key=os.environ["TOKPORTAL_API_KEY"])
me = client.me()
bundle = client.bundles.create({
"bundle_type": "account_and_videos",
"country": "USA",
"videos_quantity": 5,
})
csv = client.analytics.export_videos(account=["saved-account-id"])
image = client.uploads.image_from_url({
"url": "https://cdn.example.com/photo.jpg",
"bundle_id": bundle["data"]["id"],
})
print(me["data"]["email"], bundle["data"], csv, image["data"])Direct multipart uploads use the same structured errors and idempotency support:
uploaded = client.uploads.video_direct(
"./video.mp4",
bundle["data"]["id"],
content_type="video/mp4",
idempotency_key="video-upload-123",
)Manage TokPortal Coverage from the latest atomic quote. A zero-credit quote is valid and still requires an explicit reactivation call:
coverage = client.accounts.coverage("saved-account-id")
quote = coverage["data"]["reactivation_quote"]
if quote:
client.accounts.reactivate_coverage(
"saved-account-id",
{
"expected_credits": quote["credits"],
"expected_current_period_end": quote["current_period_end"],
"expected_lock_version": quote["lock_version"],
},
idempotency_key="coverage-reactivate-saved-account-id-v4",
)
client.accounts.pause_coverage(
"saved-account-id",
idempotency_key="coverage-pause-saved-account-id-v4",
)Credential reveal and verification-code access use the same irreversible
two-step policy flow. First call without acceptance to receive HTTP 428 and
error.details.policy_version; then show those terms to the account owner and
retry with that exact version. The accepted request may debit credits and
permanently detach the account. These secret-bearing responses are never stored
for replay, so these helpers intentionally do not accept idempotency_key.
After an uncertain transport result, reconcile the safe account state before
deciding whether to call the endpoint again without a key:
If an accepted call returns HTTP 409 with
CREDENTIAL_REVEAL_QUOTE_CHANGED, no charge or reveal occurred. Read the
current policy and expected_credit_cost from error.details, show the new
terms to the owner, obtain fresh consent, and retry with the new version. Never
retry a 409 automatically.
try:
client.accounts.reveal_credentials("saved-account-id")
except TokPortalApiError as error:
if error.status_code != 428:
raise
policy_version = str(error.details["policy_version"])
credentials = client.accounts.reveal_credentials(
"saved-account-id",
acceptance={
"acknowledge_support_forfeit": True,
"policy_version": policy_version,
},
)The same no-replay rule applies to webhooks.create, uploads.image,
uploads.video, and analytics.create_report because they return a signing
secret, signed upload capability, or report access token. These helpers do not
accept idempotency_key, and request_operation rejects one locally for all
six sensitive operation IDs.
Discover and operate webhooks without dropping to raw HTTP:
catalog = client.webhooks.events()
endpoints = client.webhooks.list(event="bundle.published")
retry = client.webhooks.retry_delivery(endpoints["data"][0]["id"], "delivery-id")Every OpenAPI operation is also reachable through the generated operation map:
same_retry = client.request_operation(
"retryWebhookDelivery",
path={"id": endpoints["data"][0]["id"], "delivery_id": "delivery-id"},
)
csv_again = client.request_operation(
"exportAnalyticsVideos",
query={"account": ["saved-account-id"]},
)The SDK sends X-TokPortal-Client: tokportal-python/0.1.0 on API requests for observability and support diagnostics.
Verify signed webhook deliveries with the exact raw request body:
from tokportal import verify_webhook_signature
valid = verify_webhook_signature(
raw_body,
request.headers["TokPortal-Signature"],
os.environ["TOKPORTAL_WEBHOOK_SECRET"],
)from tokportal import TokPortalApiError
try:
client.bundles.create({
"bundle_type": "account_and_videos",
"country": "USA",
"videos_quantity": 5,
})
except TokPortalApiError as error:
print(error.status_code, error.code, error.details, error.request_id)
if error.retryable:
wait_seconds = error.retry_after_seconds or 1
# Retry with backoff.
pass
print(error.rate_limit)API keys use the format sk_ followed by 64 lowercase hex characters. TokPortal stores only a SHA-256 hash of the key and shows the raw key once at creation.
Source of truth
This package is generated from the TokPortal public OpenAPI schema
(https://developers.tokportal.com/openapi.json) in the private TokPortal
monorepo. Generated files (tokportal/_generated.py) are overwritten on every release — do not edit
them by hand. See CONTRIBUTING.md for what we accept as PRs
and SECURITY.md for vulnerability reporting.
Links
Documentation: https://developers.tokportal.com
SDKs & CLI guide: https://developers.tokportal.com/sdks-cli
MCP server: https://developers.tokportal.com/mcp ·
tokportal-mcpAPI reference (OpenAPI): https://developers.tokportal.com/openapi.json
Other packages:
@tokportal/node·@tokportal/cli·tokportal(PyPI) ·github.com/tokportal/tokportal-go
MIT © TokPortal
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/tokportal/tokportal-python'
If you have feedback or need assistance with the MCP directory API, please join our Discord server