Create Bundle - Provision Accounts & Videos
Create a new TokPortal bundle via API to provision accounts and video slots for TikTok or Instagram campaigns.
Create Bundle
Create a new bundle to provision an account, upload videos, or both.
POST /bundles
All fields are top-level in the request body. There is no options wrapper.
Request Body
Required
| Field | Type | Description |
|---|---|---|
bundle_type | string | "account_only", "account_and_videos", or "videos_only". |
Conditional
| Field | Type | Required When | Description |
|---|---|---|---|
country | string | account_only, account_and_videos | TokPortal country code or supported alias. Use GET /countries to list countries currently available for new account creation. Disabled countries and countries restricted to existing-account videos_only work are excluded. Optional for videos_only (derived from the saved account). |
account_id | string (UUID) | videos_only | The saved account ID to upload videos to. Only valid with bundle_type: "videos_only" — passing it on account_and_videos or account_only returns ACCOUNT_ID_NOT_ALLOWED (this prevents accidentally being charged the account-creation credits while reusing an existing account). |
videos_quantity | integer | account_and_videos, videos_only | Number of video slots. Must be greater than 0. |
Optional
| Field | Type | Default | Description |
|---|---|---|---|
platform | string | "tiktok" | "tiktok" or "instagram". |
title | string | — | Bundle title. Max 200 characters. |
edits_quantity | integer | 0 | Number of video edits. Cannot exceed videos_quantity. |
wants_advanced_warming | boolean | false | Enable Advanced Niche Warming (recommended) — niche-target based warming with recorded proof and a data report. 3 credits per target, TikTok and Instagram only. Requires advanced_warming_terms_count or advanced_warming_terms. See the Advanced Niche Warming guide. |
advanced_warming_terms_count | integer | — | Number of niche targets to purchase: 3-30, multiples of 3. Recommended flow: buy the count now and write the actual targets later via PUT /bundles/{id}/account. Purchases never configured within 14 days are auto-cancelled and fully refunded. |
advanced_warming_terms | string[] | — | Alternative to advanced_warming_terms_count: provide the niche targets immediately (3-30 terms, count multiple of 3, each 2-50 characters). |
wants_niche_warming | boolean | false | Enable niche warming (review-based, will be deprecated in favor of Advanced Niche Warming). Mutually exclusive with wants_advanced_warming. |
wants_deep_warming | boolean | false | ⚠️ Discontinued. Any request with wants_deep_warming: true is rejected with DEEP_WARMING_DEPRECATED. Use Advanced Niche Warming instead. |
wants_moderation | boolean | false | ⚠️ Deprecated — no longer applied. Was the per-bundle "community management" add-on (25 credits). Use the Comments API instead. Sending it has no effect. |
niche_warming_instructions | string | — | Instructions for niche warming. Required when wants_niche_warming is true. |
moderation_notice | string | — | ⚠️ Deprecated — no longer applied. Was the guidelines notice for community management. Use the Comments API instead. |
auto_finalize_videos | boolean | true | Automatically finalize videos when they are ready. |
external_ref | string | — | Your own reference ID. Max 200 characters. |
WARNING: Community management is deprecated The per-bundle "community management" / content-moderation add-on (
wants_moderation, 25 credits) has been replaced by the standalone Comments API, which lets you post comments and reply to specific comments from your managed accounts.wants_moderation/moderation_noticeare still accepted for backward compatibility but are ignored (no credits charged, no moderation provisioned).
Validation Rules
wants_advanced_warmingrequires eitheradvanced_warming_terms_countoradvanced_warming_terms(3-30 targets, multiples of 3) — otherwiseADVANCED_WARMING_TERMS. TikTok and Instagram only (ADVANCED_WARMING_PLATFORM).wants_advanced_warmingandwants_niche_warmingare mutually exclusive (WARMING_CONFLICT).wants_deep_warming: trueis always rejected withDEEP_WARMING_DEPRECATED— deep warming is discontinued.edits_quantitycannot exceedvideos_quantity.niche_warming_instructionsis required whenwants_niche_warmingistrue.countrymust be available for new account creation. Disabled countries and countries restricted to existing-accountvideos_onlywork are rejected.USandGBaliases are accepted and normalized by the API.
GET /countries keeps new-account countries in data and exposes countries available for existing-account video orders in videos_only_countries. For example, a country can be absent from data but present in videos_only_countries; in that case, new account creation is blocked while a videos_only order linked to an existing account remains supported.
Response
{
"data": {
"bundle_id": "...",
"bundle_type": "account_and_videos",
"platform": "tiktok",
"country": "US",
"status": "pending_setup",
"videos_quantity": 5,
"edits_quantity": 2,
"external_ref": "my-campaign-001",
"created_at": "2026-02-10T09:00:00Z"
},
"credits_charged": 41,
"credits_remaining": 459,
"cost_breakdown": {
"account": 25,
"videos": 10,
"edits": 6,
"niche_warming": 0,
"deep_warming": 0,
"moderation": 0
}
}
| Field | Type | Description |
|---|---|---|
data.bundle_id | string | Unique identifier for the created bundle. |
data.bundle_type | string | The bundle type as submitted. |
data.platform | string | Target platform. |
data.country | string | Country code. |
data.status | string | Initial bundle status. |
data.videos_quantity | integer | Number of video slots (if applicable). |
data.edits_quantity | integer | Number of edits (if applicable). |
data.external_ref | string | Your external reference (if provided). |
data.created_at | string | ISO 8601 timestamp. |
credits_charged | integer | Credits deducted for this bundle. |
credits_remaining | integer | Your remaining credit balance. |
cost_breakdown | object | Itemized cost breakdown. |
Examples
1. Account and Videos (with niche warming)
curl -X POST https://app.tokportal.com/api/ext/bundles \
-H "X-API-Key: sk_xxx" \
-H "Content-Type: application/json" \
-d '{
"bundle_type": "account_and_videos",
"platform": "tiktok",
"country": "US",
"videos_quantity": 5,
"edits_quantity": 2,
"wants_niche_warming": true,
"niche_warming_instructions": "Focus on fitness and gym content. Follow fitness influencers, like workout videos.",
"auto_finalize_videos": true,
"external_ref": "campaign-42"
}'
Response:
{
"data": {
"bundle_id": "bnd_a1b2c3d4",
"bundle_type": "account_and_videos",
"platform": "tiktok",
"country": "US",
"status": "pending_setup",
"videos_quantity": 5,
"edits_quantity": 2,
"external_ref": "campaign-42",
"created_at": "2026-02-10T09:00:00Z"
},
"credits_charged": 48,
"credits_remaining": 452,
"cost_breakdown": {
"account": 25,
"videos": 10,
"edits": 6,
"niche_warming": 7,
"deep_warming": 0,
"moderation": 0
}
}
2. Account Only (with Advanced Niche Warming, targets configured later)
curl -X POST https://app.tokportal.com/api/ext/bundles \
-H "X-API-Key: sk_xxx" \
-H "Content-Type: application/json" \
-d '{
"bundle_type": "account_only",
"platform": "instagram",
"country": "FR",
"wants_advanced_warming": true,
"advanced_warming_terms_count": 9,
"title": "French lifestyle account"
}'
Response:
{
"data": {
"bundle_id": "bnd_e5f6g7h8",
"bundle_type": "account_only",
"platform": "instagram",
"country": "FR",
"status": "pending_setup",
"videos_quantity": 0,
"edits_quantity": 0,
"wants_advanced_warming": true,
"advanced_warming_terms": [],
"advanced_warming_terms_count": 9,
"external_ref": null,
"created_at": "2026-02-10T09:05:00Z"
},
"credits_charged": 52,
"credits_remaining": 400,
"cost_breakdown": {
"account": 25,
"videos": 0,
"edits": 0,
"niche_warming": 0,
"deep_warming": 0,
"advanced_warming": 27,
"moderation": 0
}
}
The 9 niche targets are written afterwards on the bundle:
PUT /bundles/{id}/accountwithadvanced_warming_terms. See the Advanced Niche Warming guide.
3. Videos Only (existing account)
Recommendation: Instead of creating a
videos_onlybundle, consider using the add-video-slots endpoint on an existing active bundle. This preserves the same account manager, which is better for continuity and turnaround time.
curl -X POST https://app.tokportal.com/api/ext/bundles \
-H "X-API-Key: sk_xxx" \
-H "Content-Type: application/json" \
-d '{
"bundle_type": "videos_only",
"account_id": "9f3a7b2e-1c4d-4e8f-a5b6-7d9e0f1a2b3c",
"videos_quantity": 3,
"external_ref": "restock-wave-2"
}'
Response:
{
"data": {
"bundle_id": "bnd_i9j0k1l2",
"bundle_type": "videos_only",
"platform": "tiktok",
"country": "US",
"status": "pending_setup",
"videos_quantity": 3,
"edits_quantity": 0,
"external_ref": "restock-wave-2",
"created_at": "2026-02-10T09:10:00Z"
},
"credits_charged": 6,
"credits_remaining": 381,
"cost_breakdown": {
"account": 0,
"videos": 6,
"edits": 0,
"niche_warming": 0,
"deep_warming": 0,
"moderation": 0
}
}
Note:
platformandcountryare derived from the saved account when usingvideos_only.
Error Responses
| Status | Code | Description |
|---|---|---|
400 | VALIDATION_ERROR | Invalid or missing fields (see details for specifics). |
400 | WARMING_CONFLICT | wants_advanced_warming and wants_niche_warming cannot both be enabled. |
400 | ADVANCED_WARMING_TERMS | Provide advanced_warming_terms (3-30 terms, multiple of 3, each 2-50 chars) or advanced_warming_terms_count (3-30, multiple of 3). |
400 | ADVANCED_WARMING_PLATFORM | Advanced Niche Warming is only available for TikTok and Instagram. |
| 400 | EDITS_EXCEED_VIDEOS | edits_quantity exceeds videos_quantity. |
| 400 | COUNTRY_NOT_ENABLED | Country is not enabled for your organization. |
| 400 | ACCOUNT_ID_NOT_ALLOWED | account_id was passed with a bundle_type other than videos_only. Set bundle_type to videos_only to add videos to an existing account, or omit account_id. |
| 402 | INSUFFICIENT_CREDITS | Not enough credits to create this bundle. |
| 404 | ACCOUNT_NOT_FOUND | account_id does not exist or does not belong to your organization. |
FAQ
Can I comment or reply to comments?
Yes — but not through bundle creation. Commenting is its own product, the Comments API, separate from bundles.
From any of your delivered (managed) accounts, you can:
- Comment on a video — post a comment under any TikTok/Instagram video. Set
target_type: "video"and passtarget_video_url. - Reply to a specific comment — reply under a particular comment on a TikTok video (TikTok only). Set
target_type: "comment"and passtarget_comment_url(the link from the app's Share comment → Copy link).
The assigned account manager posts it, then TokPortal auto-verifies the comment/reply by scraping the target (matching your account handle + text). Each comment costs 1 credit, debited up-front and refunded if it can't be fulfilled.
curl -X POST https://app.tokportal.com/api/ext/comments \
-H "X-API-Key: sk_xxx" \
-H "Content-Type: application/json" \
-d '{
"saved_account_id": "9f3a7b2e-1c4d-4e8f-a5b6-7d9e0f1a2b3c",
"target_type": "comment",
"target_comment_url": "https://www.tiktok.com/t/ZT9j5AXVsyuRS/",
"comment_text": "100% agree with this!"
}'
See the full Comments API reference for lifecycle, verification, and batch usage.
The old per-bundle "community management" add-on (
wants_moderation) is deprecated in favor of this Comments API.