Contents
API reference for TikTok's three-endpoint Smart+ Web Conversions flow
/campaign/spc/create/ removed
March 31, 2026
/campaign/spc/update/ and /campaign/status/update/ removed
June 30, 2026
/campaign/create/ (manual) removed
December 31, 2026
TikTok's Upgraded Smart+ Web Conversions API replaces the legacy /campaign/spc/create/ single-call pattern with three sequential POST endpoints that separately create a campaign, ad group, and ad.1 The legacy endpoint stops accepting new campaign creation requests after 2026-03-31, with update endpoints following on 2026-06-30.2 This guide covers the full integration path for backend engineers: authentication, the three-call dependency chain, field references, error handling, migration, and event deduplication.
All requests require an Access-Token HTTP header containing a token obtained through TikTok's OAuth flow.1 Tokens come in two forms: long-term tokens that do not expire, and short-term tokens that require periodic refresh. Three permission scopes must be granted to the OAuth app before any Smart+ call succeeds: Ads Management > Upgraded Smart Plus Ads, Reporting > Upgraded Smart+ Report, and Creative Management > Creative tool.1
The API enforces a strict creation order: campaign first, then ad group, then ad.1 Each call returns an ID that the next call requires as input. The campaign create response includes campaign_id, which is a required field in ad group creation. The ad group create response includes adgroup_id, which is a required field in ad creation.1 These calls cannot be parallelized.
POST /smart_plus/campaign/create/
| Field | Type | Value |
|---|---|---|
advertiser_id | string | Your advertiser account ID |
campaign_name | string | Human-readable name |
objective_type | string | "WEB_CONVERSIONS" |
The budget_optimize_on boolean controls Campaign Budget Optimization (CBO).1 When true (the default), TikTok distributes budget across ad groups automatically. When false, each ad group manages its own budget.
| CBO Mode | Valid budget_mode values | budget required? |
|---|---|---|
true | BUDGET_MODE_TOTAL, BUDGET_MODE_DYNAMIC_DAILY_BUDGET | Yes |
false | BUDGET_MODE_INFINITE, BUDGET_MODE_DAY, BUDGET_MODE_TOTAL | Yes, except BUDGET_MODE_INFINITE |
| Field | Type | Notes |
|---|---|---|
special_industries | array | US and Canada advertisers only |
po_number | string | Purchase order reference |
The response body contains campaign_id on success.1
POST /smart_plus/adgroup/create/
| Field | Type | Value / Notes |
|---|---|---|
advertiser_id | string | Same advertiser as campaign |
campaign_id | string | From campaign create response |
adgroup_name | string | Human-readable name |
promotion_type | string | "WEBSITE" for web conversions |
pixel_id | string | Your TikTok Pixel ID |
billing_event | string | "OCPM" (only valid option) |
optimization_goal | optimization_event required? | Example event |
|---|---|---|
"CONVERT" | Yes | "COMPLETE_PAYMENT" |
"LANDING_PAGE" | No (Pixel-only goal) | — |
"CLICK" | No | — |
bid_type | Behavior | Price field |
|---|---|---|
"BID_TYPE_NO_BID" | Maximum delivery (no cap) | None |
"BID_TYPE_CUSTOM" | Cost cap | bid_price for CLICK goal; conversion_bid_price for CONVERT or LANDING_PAGE |
When CBO is on with BUDGET_MODE_DYNAMIC_DAILY_BUDGET and BID_TYPE_NO_BID, the optional min_budget and max_budget fields set per-ad-group budget guardrails.1
| Field | Notes |
|---|---|
schedule_type | "SCHEDULE_FROM_NOW" or "SCHEDULE_START_END" |
schedule_start_time | Format: "YYYY-MM-DD HH:MM:SS" |
schedule_end_time | Required when SCHEDULE_START_END; format same as above |
dayparting | String of 0s and 1s encoding half-hour slots |
Set targeting_optimization_mode to "AUTOMATIC" to let TikTok's algorithm select audiences, or "MANUAL" to define a targeting_spec object.1 Under automatic mode, targeting_spec fields split into two categories: Audience Controls (hard constraints TikTok guarantees, such as location_ids) and Audience Suggestions (soft hints the algorithm may expand beyond).3 TikTok recommends starting with automatic targeting and broad audiences to give the algorithm maximum signal for optimization.4
The targeting_spec object accepts: location_ids, age_groups, gender, languages, interest_category_ids, and other demographic or behavioral filters.1
| Field | Value | Notes |
|---|---|---|
placement_type | "PLACEMENT_TYPE_NORMAL" | Omit for automatic placement |
placements | Array | "PLACEMENT_TIKTOK", "PLACEMENT_PANGLE", "PLACEMENT_GLOBAL_APP_BUNDLE", or combinations |
Boolean fields comment_disabled, share_disabled, video_download_disabled, favorite_counts_disabled, and like_counts_disabled toggle individual interaction types on the ad.1
When CBO is off, the ad group must specify its own budget_mode and budget using the same mode/value rules as the campaign-level fields.1
The response body contains adgroup_id on success.1
POST /smart_plus/ad/create/
| Field | Type | Notes |
|---|---|---|
advertiser_id | string | Same advertiser |
adgroup_id | string | From ad group create response |
The creative_list array contains objects, each with a creative_info block.1
creative_info field | Type | Notes |
|---|---|---|
ad_format | string | "SINGLE_VIDEO" or "CAROUSEL" |
video_info | object | {video_id: "..."} for video ads |
image_info | array | [{web_uri: "..."}] — thumbnail for video, or image list for carousel |
tiktok_item_id | string | For Spark Ads (uses an existing organic TikTok post) |
identity_type | string | "CUSTOMIZED_USER", "AUTH_CODE", "TT_USER", or "BC_AUTH_TT" |
identity_id | string | Required for all identity types except CUSTOMIZED_USER |
identity_authorized_bc_id | string | Required when identity_type is "BC_AUTH_TT" |
music_info | object | Carousel ads only |
ad_text_list accepts up to 5 objects, each containing an ad_text string.1 landing_page_url_list holds objects with landing_page_url strings. Alternatively, page_list with page_id entries designates a TikTok Custom Page — these two fields are mutually exclusive.1
The deeplink field accepts both https:// URLs and custom scheme URLs (e.g., myapp://path). Set deeplink_type to "NORMAL".1
Inside ad_configuration, set call_to_action_id for a dynamic CTA chosen by TikTok's algorithm, or call_to_action_list with up to 3 standard CTA options.1
| Field | Notes |
|---|---|
ad_name | Pass an empty string for auto-generation |
The response body contains smart_plus_ad_id on success.1
When CBO is enabled, all ad groups under the same campaign must share identical values for: promotion_type, optimization_goal, optimization_event, billing_event, bid_type, bid_price, conversion_bid_price, deep_bid_type, vbo_window, and roas_bid.1 A mismatch on any of these fields causes the ad group create call to fail.
When CBO is disabled, the uniformity constraint narrows to: bid_type, deep_bid_type, vbo_window, and budget_mode.1
Include a request_id field (unique string per request) in the POST body to prevent duplicate resource creation on retries.1 If the API receives a second request with the same request_id, it returns the original response instead of creating a new entity.
TikTok enforces per-app and per-advertiser rate limits on Marketing API endpoints.1 Implement exponential backoff on HTTP 429 responses. Batch operations (e.g., creating multiple ad groups sequentially) should include delays between calls to stay within limits.
When using both the browser-side TikTok Pixel and the server-side Events API, duplicate conversion events will inflate reported numbers unless deduplicated.5 The deduplication mechanism relies on a shared event_id string.
Browser side (Pixel): Pass event_id as a property in the ttq.track() call:
ttq.track('CompletePayment', {
content_type: 'product',
value: 49.99,
currency: 'USD'
}, {
event_id: 'order-abc-123'
});
Server side (Events API): Include the same event_id in the event object POSTed to the Events API endpoint:
{
"event": "CompletePayment",
"event_id": "order-abc-123",
"timestamp": "2026-03-12T10:30:00Z",
"context": {
"user_agent": "...",
"ip": "..."
},
"properties": {
"content_type": "product",
"value": 49.99,
"currency": "USD"
}
}
When TikTok receives events from both sources with matching event_id values within a deduplication window, it counts them as a single conversion.5
Step 1 — Create Campaign:
curl -X POST 'https://business-api.tiktok.com/open_api/v1.3/smart_plus/campaign/create/' \
-H 'Access-Token: YOUR_ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"advertiser_id": "7000000000000000001",
"campaign_name": "Spring Sale - Smart+ Web",
"objective_type": "WEB_CONVERSIONS",
"budget_optimize_on": true,
"budget_mode": "BUDGET_MODE_DYNAMIC_DAILY_BUDGET",
"budget": 500.00,
"request_id": "req-campaign-20260312-001"
}'
Response contains campaign_id, e.g. "1800000000000001".
Step 2 — Create Ad Group:
curl -X POST 'https://business-api.tiktok.com/open_api/v1.3/smart_plus/adgroup/create/' \
-H 'Access-Token: YOUR_ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"advertiser_id": "7000000000000000001",
"campaign_id": "1800000000000001",
"adgroup_name": "Auto Targeting - Conversions",
"promotion_type": "WEBSITE",
"optimization_goal": "CONVERT",
"optimization_event": "COMPLETE_PAYMENT",
"pixel_id": "CP0000000000000001",
"billing_event": "OCPM",
"bid_type": "BID_TYPE_NO_BID",
"schedule_type": "SCHEDULE_FROM_NOW",
"targeting_optimization_mode": "AUTOMATIC",
"request_id": "req-adgroup-20260312-001"
}'
Response contains adgroup_id, e.g. "1900000000000001".
Step 3 — Create Ad:
curl -X POST 'https://business-api.tiktok.com/open_api/v1.3/smart_plus/ad/create/' \
-H 'Access-Token: YOUR_ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"advertiser_id": "7000000000000000001",
"adgroup_id": "1900000000000001",
"ad_name": "",
"creative_list": [
{
"creative_info": {
"ad_format": "SINGLE_VIDEO",
"video_info": {"video_id": "v10000000000000001"},
"image_info": [{"web_uri": "https://example.com/thumb.jpg"}],
"identity_type": "CUSTOMIZED_USER"
}
}
],
"ad_text_list": [
{"ad_text": "Shop the Spring Sale — 30% off everything"}
],
"landing_page_url_list": [
{"landing_page_url": "https://example.com/spring-sale"}
],
"ad_configuration": {
"call_to_action_id": "shop_now"
},
"request_id": "req-ad-20260312-001"
}'
Response contains smart_plus_ad_id.1
Step 1 — Create Campaign (CBO off):
curl -X POST 'https://business-api.tiktok.com/open_api/v1.3/smart_plus/campaign/create/' \
-H 'Access-Token: YOUR_ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"advertiser_id": "7000000000000000001",
"campaign_name": "Manual Targeting - Cost Cap",
"objective_type": "WEB_CONVERSIONS",
"budget_optimize_on": false,
"budget_mode": "BUDGET_MODE_INFINITE",
"request_id": "req-campaign-20260312-002"
}'
Step 2 — Create Ad Group (manual targeting, cost cap):
curl -X POST 'https://business-api.tiktok.com/open_api/v1.3/smart_plus/adgroup/create/' \
-H 'Access-Token: YOUR_ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"advertiser_id": "7000000000000000001",
"campaign_id": "1800000000000002",
"adgroup_name": "US 25-44 - Cost Cap $15",
"promotion_type": "WEBSITE",
"optimization_goal": "CONVERT",
"optimization_event": "COMPLETE_PAYMENT",
"pixel_id": "CP0000000000000001",
"billing_event": "OCPM",
"bid_type": "BID_TYPE_CUSTOM",
"conversion_bid_price": 15.00,
"budget_mode": "BUDGET_MODE_DAY",
"budget": 200.00,
"schedule_type": "SCHEDULE_START_END",
"schedule_start_time": "2026-03-15 00:00:00",
"schedule_end_time": "2026-04-15 23:59:59",
"targeting_optimization_mode": "MANUAL",
"targeting_spec": {
"location_ids": ["6252001"],
"age_groups": ["AGE_25_34", "AGE_35_44"],
"gender": "GENDER_UNLIMITED",
"languages": ["en"]
},
"placement_type": "PLACEMENT_TYPE_NORMAL",
"placements": ["PLACEMENT_TIKTOK"],
"request_id": "req-adgroup-20260312-002"
}'
Step 3 — Create Ad (same structure as Example 1).1
Common error scenarios and their causes:
| Error | Cause | Resolution |
|---|---|---|
| CBO uniformity violation | Ad groups under a CBO campaign have mismatched optimization_goal, bid_type, or other constrained fields | Ensure all ad groups pass identical values for the 10 CBO-uniform fields |
page_list / landing_page_url_list conflict | Both fields provided in ad create | Use one or the other, never both |
| Budget constraint violation | budget omitted when budget_mode is not BUDGET_MODE_INFINITE | Always provide budget for non-infinite modes |
Invalid optimization_event | optimization_event set when optimization_goal is "CLICK" | Only pass optimization_event with "CONVERT" goal |
Missing conversion_bid_price | bid_type is "BID_TYPE_CUSTOM" with "CONVERT" goal but no price | Provide conversion_bid_price when using cost cap with conversion goals |
The legacy /campaign/spc/create/ combined campaign, ad group, and ad parameters in a single request body.2 The upgraded API splits these into three calls with the following field mapping:
| Legacy field (spc/create) | New endpoint | New field |
|---|---|---|
campaign_name | Campaign create | campaign_name |
objective_type | Campaign create | objective_type |
budget, budget_mode | Campaign create (CBO) or Ad group create (non-CBO) | Same names |
promotion_type, pixel_id | Ad group create | Same names |
optimization_goal, optimization_event | Ad group create | Same names |
bid_type, bid_price, conversion_bid_price | Ad group create | Same names |
targeting | Ad group create | targeting_spec (renamed) |
creative_info, ad_text | Ad create | creative_list[].creative_info, ad_text_list |
landing_page_url | Ad create | landing_page_url_list |
Update and status-change operations on campaigns created with the legacy endpoint continue to work through /campaign/spc/update/ and /campaign/status/update/ until 2026-06-30.2 The manual /campaign/create/ endpoint remains available until 2026-12-31.2
Beyond creation, the API provides symmetric endpoints for retrieval and modification:1
GET /smart_plus/campaign/get/ and POST /smart_plus/campaign/update/GET /smart_plus/adgroup/get/ and POST /smart_plus/adgroup/update/GET /smart_plus/ad/get/ and POST /smart_plus/ad/update/These follow the same authentication and advertiser_id requirements as the create endpoints.1
TikTok's Upgraded Smart+ Web Conversions API replaces the legacy /campaign/spc/create/ single-call pattern with three sequential POST endpoints that separately create a campaign, ad group, and ad.1 The legacy endpoint stops accepting new campaign creation requests after 2026-03-31, with update endpoints following on 2026-06-30.2 This guide covers the full integration path for backend engineers: authentication, the three-call dependency chain, field references, error handling, migration, and event deduplication.
/campaign/spc/create/ removed
March 31, 2026
/campaign/spc/update/ and /campaign/status/update/ removed
June 30, 2026
/campaign/create/ (manual) removed
December 31, 2026
All requests require an Access-Token HTTP header containing a token obtained through TikTok's OAuth flow.1 Tokens come in two forms: long-term tokens that do not expire, and short-term tokens that require periodic refresh. Three permission scopes must be granted to the OAuth app before any Smart+ call succeeds: Ads Management > Upgraded Smart Plus Ads, Reporting > Upgraded Smart+ Report, and Creative Management > Creative tool.1
The API enforces a strict creation order: campaign first, then ad group, then ad.1 Each call returns an ID that the next call requires as input. The campaign create response includes campaign_id, which is a required field in ad group creation. The ad group create response includes adgroup_id, which is a required field in ad creation.1 These calls cannot be parallelized.
POST /smart_plus/campaign/create/
| Field | Type | Value |
|---|---|---|
advertiser_id | string | Your advertiser account ID |
campaign_name | string | Human-readable name |
objective_type | string | "WEB_CONVERSIONS" |
The budget_optimize_on boolean controls Campaign Budget Optimization (CBO).1 When true (the default), TikTok distributes budget across ad groups automatically. When false, each ad group manages its own budget.
| CBO Mode | Valid budget_mode values | budget required? |
|---|---|---|
true | BUDGET_MODE_TOTAL, BUDGET_MODE_DYNAMIC_DAILY_BUDGET | Yes |
false | BUDGET_MODE_INFINITE, BUDGET_MODE_DAY, BUDGET_MODE_TOTAL | Yes, except BUDGET_MODE_INFINITE |
| Field | Type | Notes |
|---|---|---|
special_industries | array | US and Canada advertisers only |
po_number | string | Purchase order reference |
The response body contains campaign_id on success.1
POST /smart_plus/adgroup/create/
| Field | Type | Value / Notes |
|---|---|---|
advertiser_id | string | Same advertiser as campaign |
campaign_id | string | From campaign create response |
adgroup_name | string | Human-readable name |
promotion_type | string | "WEBSITE" for web conversions |
pixel_id | string | Your TikTok Pixel ID |
billing_event | string | "OCPM" (only valid option) |
optimization_goal | optimization_event required? | Example event |
|---|---|---|
"CONVERT" | Yes | "COMPLETE_PAYMENT" |
"LANDING_PAGE" | No (Pixel-only goal) | — |
"CLICK" | No | — |
bid_type | Behavior | Price field |
|---|---|---|
"BID_TYPE_NO_BID" | Maximum delivery (no cap) | None |
"BID_TYPE_CUSTOM" | Cost cap | bid_price for CLICK goal; conversion_bid_price for CONVERT or LANDING_PAGE |
When CBO is on with BUDGET_MODE_DYNAMIC_DAILY_BUDGET and BID_TYPE_NO_BID, the optional min_budget and max_budget fields set per-ad-group budget guardrails.1
| Field | Notes |
|---|---|
schedule_type | "SCHEDULE_FROM_NOW" or "SCHEDULE_START_END" |
schedule_start_time | Format: "YYYY-MM-DD HH:MM:SS" |
schedule_end_time | Required when SCHEDULE_START_END; format same as above |
dayparting | String of 0s and 1s encoding half-hour slots |
Set targeting_optimization_mode to "AUTOMATIC" to let TikTok's algorithm select audiences, or "MANUAL" to define a targeting_spec object.1 Under automatic mode, targeting_spec fields split into two categories: Audience Controls (hard constraints TikTok guarantees, such as location_ids) and Audience Suggestions (soft hints the algorithm may expand beyond).3 TikTok recommends starting with automatic targeting and broad audiences to give the algorithm maximum signal for optimization.4
The targeting_spec object accepts: location_ids, age_groups, gender, languages, interest_category_ids, and other demographic or behavioral filters.1
| Field | Value | Notes |
|---|---|---|
placement_type | "PLACEMENT_TYPE_NORMAL" | Omit for automatic placement |
placements | Array | "PLACEMENT_TIKTOK", "PLACEMENT_PANGLE", "PLACEMENT_GLOBAL_APP_BUNDLE", or combinations |
Boolean fields comment_disabled, share_disabled, video_download_disabled, favorite_counts_disabled, and like_counts_disabled toggle individual interaction types on the ad.1
When CBO is off, the ad group must specify its own budget_mode and budget using the same mode/value rules as the campaign-level fields.1
The response body contains adgroup_id on success.1
POST /smart_plus/ad/create/
| Field | Type | Notes |
|---|---|---|
advertiser_id | string | Same advertiser |
adgroup_id | string | From ad group create response |
The creative_list array contains objects, each with a creative_info block.1
creative_info field | Type | Notes |
|---|---|---|
ad_format | string | "SINGLE_VIDEO" or "CAROUSEL" |
video_info | object | {video_id: "..."} for video ads |
image_info | array | [{web_uri: "..."}] — thumbnail for video, or image list for carousel |
tiktok_item_id | string | For Spark Ads (uses an existing organic TikTok post) |
identity_type | string | "CUSTOMIZED_USER", "AUTH_CODE", "TT_USER", or "BC_AUTH_TT" |
identity_id | string | Required for all identity types except CUSTOMIZED_USER |
identity_authorized_bc_id | string | Required when identity_type is "BC_AUTH_TT" |
music_info | object | Carousel ads only |
ad_text_list accepts up to 5 objects, each containing an ad_text string.1 landing_page_url_list holds objects with landing_page_url strings. Alternatively, page_list with page_id entries designates a TikTok Custom Page — these two fields are mutually exclusive.1
The deeplink field accepts both https:// URLs and custom scheme URLs (e.g., myapp://path). Set deeplink_type to "NORMAL".1
Inside ad_configuration, set call_to_action_id for a dynamic CTA chosen by TikTok's algorithm, or call_to_action_list with up to 3 standard CTA options.1
| Field | Notes |
|---|---|
ad_name | Pass an empty string for auto-generation |
The response body contains smart_plus_ad_id on success.1
When CBO is enabled, all ad groups under the same campaign must share identical values for: promotion_type, optimization_goal, optimization_event, billing_event, bid_type, bid_price, conversion_bid_price, deep_bid_type, vbo_window, and roas_bid.1 A mismatch on any of these fields causes the ad group create call to fail.
When CBO is disabled, the uniformity constraint narrows to: bid_type, deep_bid_type, vbo_window, and budget_mode.1
Include a request_id field (unique string per request) in the POST body to prevent duplicate resource creation on retries.1 If the API receives a second request with the same request_id, it returns the original response instead of creating a new entity.
TikTok enforces per-app and per-advertiser rate limits on Marketing API endpoints.1 Implement exponential backoff on HTTP 429 responses. Batch operations (e.g., creating multiple ad groups sequentially) should include delays between calls to stay within limits.
When using both the browser-side TikTok Pixel and the server-side Events API, duplicate conversion events will inflate reported numbers unless deduplicated.5 The deduplication mechanism relies on a shared event_id string.
Browser side (Pixel): Pass event_id as a property in the ttq.track() call:
ttq.track('CompletePayment', {
content_type: 'product',
value: 49.99,
currency: 'USD'
}, {
event_id: 'order-abc-123'
});
Server side (Events API): Include the same event_id in the event object POSTed to the Events API endpoint:
{
"event": "CompletePayment",
"event_id": "order-abc-123",
"timestamp": "2026-03-12T10:30:00Z",
"context": {
"user_agent": "...",
"ip": "..."
},
"properties": {
"content_type": "product",
"value": 49.99,
"currency": "USD"
}
}
When TikTok receives events from both sources with matching event_id values within a deduplication window, it counts them as a single conversion.5
Step 1 — Create Campaign:
curl -X POST 'https://business-api.tiktok.com/open_api/v1.3/smart_plus/campaign/create/' \
-H 'Access-Token: YOUR_ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"advertiser_id": "7000000000000000001",
"campaign_name": "Spring Sale - Smart+ Web",
"objective_type": "WEB_CONVERSIONS",
"budget_optimize_on": true,
"budget_mode": "BUDGET_MODE_DYNAMIC_DAILY_BUDGET",
"budget": 500.00,
"request_id": "req-campaign-20260312-001"
}'
Response contains campaign_id, e.g. "1800000000000001".
Step 2 — Create Ad Group:
curl -X POST 'https://business-api.tiktok.com/open_api/v1.3/smart_plus/adgroup/create/' \
-H 'Access-Token: YOUR_ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"advertiser_id": "7000000000000000001",
"campaign_id": "1800000000000001",
"adgroup_name": "Auto Targeting - Conversions",
"promotion_type": "WEBSITE",
"optimization_goal": "CONVERT",
"optimization_event": "COMPLETE_PAYMENT",
"pixel_id": "CP0000000000000001",
"billing_event": "OCPM",
"bid_type": "BID_TYPE_NO_BID",
"schedule_type": "SCHEDULE_FROM_NOW",
"targeting_optimization_mode": "AUTOMATIC",
"request_id": "req-adgroup-20260312-001"
}'
Response contains adgroup_id, e.g. "1900000000000001".
Step 3 — Create Ad:
curl -X POST 'https://business-api.tiktok.com/open_api/v1.3/smart_plus/ad/create/' \
-H 'Access-Token: YOUR_ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"advertiser_id": "7000000000000000001",
"adgroup_id": "1900000000000001",
"ad_name": "",
"creative_list": [
{
"creative_info": {
"ad_format": "SINGLE_VIDEO",
"video_info": {"video_id": "v10000000000000001"},
"image_info": [{"web_uri": "https://example.com/thumb.jpg"}],
"identity_type": "CUSTOMIZED_USER"
}
}
],
"ad_text_list": [
{"ad_text": "Shop the Spring Sale — 30% off everything"}
],
"landing_page_url_list": [
{"landing_page_url": "https://example.com/spring-sale"}
],
"ad_configuration": {
"call_to_action_id": "shop_now"
},
"request_id": "req-ad-20260312-001"
}'
Response contains smart_plus_ad_id.1
Step 1 — Create Campaign (CBO off):
curl -X POST 'https://business-api.tiktok.com/open_api/v1.3/smart_plus/campaign/create/' \
-H 'Access-Token: YOUR_ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"advertiser_id": "7000000000000000001",
"campaign_name": "Manual Targeting - Cost Cap",
"objective_type": "WEB_CONVERSIONS",
"budget_optimize_on": false,
"budget_mode": "BUDGET_MODE_INFINITE",
"request_id": "req-campaign-20260312-002"
}'
Step 2 — Create Ad Group (manual targeting, cost cap):
curl -X POST 'https://business-api.tiktok.com/open_api/v1.3/smart_plus/adgroup/create/' \
-H 'Access-Token: YOUR_ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"advertiser_id": "7000000000000000001",
"campaign_id": "1800000000000002",
"adgroup_name": "US 25-44 - Cost Cap $15",
"promotion_type": "WEBSITE",
"optimization_goal": "CONVERT",
"optimization_event": "COMPLETE_PAYMENT",
"pixel_id": "CP0000000000000001",
"billing_event": "OCPM",
"bid_type": "BID_TYPE_CUSTOM",
"conversion_bid_price": 15.00,
"budget_mode": "BUDGET_MODE_DAY",
"budget": 200.00,
"schedule_type": "SCHEDULE_START_END",
"schedule_start_time": "2026-03-15 00:00:00",
"schedule_end_time": "2026-04-15 23:59:59",
"targeting_optimization_mode": "MANUAL",
"targeting_spec": {
"location_ids": ["6252001"],
"age_groups": ["AGE_25_34", "AGE_35_44"],
"gender": "GENDER_UNLIMITED",
"languages": ["en"]
},
"placement_type": "PLACEMENT_TYPE_NORMAL",
"placements": ["PLACEMENT_TIKTOK"],
"request_id": "req-adgroup-20260312-002"
}'
Step 3 — Create Ad (same structure as Example 1).1
Common error scenarios and their causes:
| Error | Cause | Resolution |
|---|---|---|
| CBO uniformity violation | Ad groups under a CBO campaign have mismatched optimization_goal, bid_type, or other constrained fields | Ensure all ad groups pass identical values for the 10 CBO-uniform fields |
page_list / landing_page_url_list conflict | Both fields provided in ad create | Use one or the other, never both |
| Budget constraint violation | budget omitted when budget_mode is not BUDGET_MODE_INFINITE | Always provide budget for non-infinite modes |
Invalid optimization_event | optimization_event set when optimization_goal is "CLICK" | Only pass optimization_event with "CONVERT" goal |
Missing conversion_bid_price | bid_type is "BID_TYPE_CUSTOM" with "CONVERT" goal but no price | Provide conversion_bid_price when using cost cap with conversion goals |
The legacy /campaign/spc/create/ combined campaign, ad group, and ad parameters in a single request body.2 The upgraded API splits these into three calls with the following field mapping:
| Legacy field (spc/create) | New endpoint | New field |
|---|---|---|
campaign_name | Campaign create | campaign_name |
objective_type | Campaign create | objective_type |
budget, budget_mode | Campaign create (CBO) or Ad group create (non-CBO) | Same names |
promotion_type, pixel_id | Ad group create | Same names |
optimization_goal, optimization_event | Ad group create | Same names |
bid_type, bid_price, conversion_bid_price | Ad group create | Same names |
targeting | Ad group create | targeting_spec (renamed) |
creative_info, ad_text | Ad create | creative_list[].creative_info, ad_text_list |
landing_page_url | Ad create | landing_page_url_list |
Update and status-change operations on campaigns created with the legacy endpoint continue to work through /campaign/spc/update/ and /campaign/status/update/ until 2026-06-30.2 The manual /campaign/create/ endpoint remains available until 2026-12-31.2
Beyond creation, the API provides symmetric endpoints for retrieval and modification:1
GET /smart_plus/campaign/get/ and POST /smart_plus/campaign/update/GET /smart_plus/adgroup/get/ and POST /smart_plus/adgroup/update/GET /smart_plus/ad/get/ and POST /smart_plus/ad/update/These follow the same authentication and advertiser_id requirements as the create endpoints.1