MCP tool · Launch
prepare_launch
Prepares the launch without creating anything: the whole recap and a plan_id, valid 24 hours. Refuses while a question is open. Starts from scratch, a copied ad set and ad, or saved templates; the ads are new files (grouped by your naming convention or by hand), or existing ads reused with their post ID.
What it does
Prepare a launch from the interview's answers (get_launch_questions) WITHOUT creating anything. Returns the full recap and a plan_id, valid 24 hours.
Refuses a plan with an open question: answers ready:false + missing (question ids) + what to ask. Ask those, then call it again. It applies only the Apogee app's documented defaults and lists them in defaults_applied.
Files: drive:<id> refs, or your own files in Apogee storage (get_upload_urls + confirm_uploads, import_link + import_status); each one is checked present.
Advantage+ enhancements: only those in advantage_plus.opt_in are ON, every other one is sent OFF.
Existing ads (Duplicate with post ID, likes and comments kept): ads[].source_ad_id instead of files; no nomenclature, texts, identity, destination, Advantage+ or catalog. New ad sets: structure all_in_one + adset_variants (one cost cap / bid / ROAS floor each, copy_adset_from for the audience and conversion; adset_variants[].ads = each one's own ads); existing ad sets: insert_in_adset. The plan is checked with Meta (validate_only, nothing created) before it is saved.
By hand: ads[].files = the formats of one creative (one file per format, never a video with an image); adsets = the ads arranged into new ad sets, each ad in exactly one.
Options of a launch plan
- Ads grouped by hand (
ads[].ad_name,ads[].files,ads[].concept): Each ad lists its own files: the formats of one creative, one file per format, never a video with an image, no naming convention needed. Two ads never share a name. An ad without a concept gets its own ad set, or "Group 1" once other ads have one. - Ad sets chosen by hand (
adsets[].name,adsets[].ads): Which ad goes into which new ad set, each ad in exactly one, on top of One Adset One Ad, One Concept One Adset or All in One; every ad set takes the plan's ad set settings. Not with Insert in Adset,adset_variantsor existing ads. Without it, the structure follows your naming convention. - Duplicate with post ID: each new ad set its own ads (
adset_variants[].ads): With existing ads, each new ad set lists its ads, by ad name or source ad id. Left out everywhere: every ad in every ad set. Given on one: every ad set needs its list, and every ad must be in one at least. - Copy the latest ad set and ad of a campaign (
copy_adset_from,copy_ad_from):get_latest_in_campaignreturns them (REST:GET /ad-accounts/{acc}/campaigns/{id}/latest); the launch interview also offers them as a starting point once the campaign is chosen.
Parameters
-
ad_account_idstring requiredThe ad account (list_ad_accounts): Meta act_…, a TikTok advertiser id, a Snapchat ad account id
-
adsarray of objects requiredThe confirmed ads (get_launch_questions proposed_ads, corrected by the user), or the existing ads to reuse (each either files or source_ad_id, all the same kind; 50 existing ads max)
Fields of each item (6)
-
source_ad_idstring optionalAn ad of this account to reuse with its post (likes and comments stay). Instead of files (get_launch_questions → creatives.choices.existing_ads)
-
filesarray of objects optionalNew files: the formats of ONE creative, linked by hand or as proposed (one file per format: 9:16, 4:5, 1:1, 16:9; never a video with an image). Leave out with source_ad_id
Fields of each item (4)
-
refstring requireddrive:<id> (list_drive_folder), or the Apogee storage URL returned by get_upload_urls / confirm_uploads / import_status (your own files only)
-
namestring optional -
mimeTypestring optional -
formatstring optional9:16, 4:5, 1:1, 16:9 or auto
-
-
conceptstring optionalConcept = ad set name in 1 Concept 1 Adset. Files without it: the ad's own (its name), or "Group 1" once other ads have one (the app's Group by hand)
-
ad_namestring optionalAd name = ad set name in 1 Adset 1 Ad. Required with files; existing ads: default = the source ad's name + " - Copy with post ID"
-
copyobject optionalThis ad's own texts (question "copy"). Not with source_ad_id: an existing ad keeps its post
Fields (5)
-
primary_textsarray of strings optional -
headlinesarray of strings optional -
descriptionstring optional -
website_urlstring optional -
call_to_actionstring optional
-
-
spark_postobject optionalTikTok Spark Ads: an existing TikTok post run as this ad instead of files (its caption is the ad text, its likes and comments stay), as list_tiktok_posts gives it
Fields (2)
-
tiktok_item_idstring requiredThe TikTok post (list_tiktok_posts: its spark_post)
-
identityobject requiredFields (3)
-
idstring requiredThe account that posted it
-
typestring requiredTT_USER / BC_AUTH_TT: one of the brand's TikTok accounts; AUTH_CODE: a creator who authorized the post for this ad account
-
bc_idstring or null optionalBC_AUTH_TT: its Business Center
-
-
-
-
platformstring optionalDefault meta. tiktok / snapchat: the same interview and arguments where they mean the same, their own settings under
tiktok/snapchat, groups made by hand underadgroups/adsquads -
campaign_idstring optionalQuestion "campaign": an existing campaign
-
structurestring optionalQuestion "test_structure": 1 Adset 1 Ad, 1 Concept 1 Adset, All in One, Insert in Adset
-
all_in_one_namestring optionalAll in One: the ad set name (required, unless adset_variants)
-
existing_adset_idsarray of strings optionalInsert: the existing ad sets (Meta), ad groups (TikTok) or ad squads (Snapchat)
-
adset_variantsarray of objects optionalall_in_one: the same ads in 1-5 new ad sets, each with its own bid / budget (e.g. two cost caps), or each with its own ads (ads)
Fields of each item (5)
-
namestring requiredThe new ad set's name
-
bid_amountnumber optionalCost cap / bid cap, in the account currency
-
roas_floornumber optionalMinimum ROAS strategy, e.g. 2.5
-
daily_budgetnumber optionalABO only, account currency
-
adsarray of strings optionalExisting ads (source_ad_id) only: the ads that go into this new ad set, each by its ad_name or its source_ad_id. Left out on every ad set: every ad in each. Given on one: every ad set needs its own, and every ad must be in one at least
-
-
adsetsarray of objects optionalNew files: the ads arranged into new ad sets by hand, on top of structure one_adset_one_ad, one_concept_one_adset or all_in_one. Launched as 1 Concept 1 Adset (each ad set = a concept), the ad names unchanged; every ad set takes the plan's ad set settings. Not with insert_in_adset, adset_variants or existing ads
Fields of each item (2)
-
namestring requiredThe new ad set's name
-
adsarray of strings requiredThe ads that go into it, by their ad_name (each ad in exactly one ad set)
-
-
nomenclatureobject optionalQuestion "nomenclature", when a saved convention reads the names: named in the recap. Files grouped by hand: leave it out
Fields (3)
-
confirmedconstant requiredtrue = the user validated the parsed concepts / iterations / formats
-
config_idstring or null optionalThe saved naming convention used, null when none
-
namestring optional
-
-
grouping_confirmedconstant optionalQuestion "grouping": true = the user validated the ads (their names and files), read by a convention or grouped by hand
-
copy_adset_fromstring optionalQuestion "starting_point": the ad set / ad group / ad squad whose settings are copied ("latest" = TikTok: the latest ad group of campaign_id)
-
adset_template_idstring optionalQuestion "starting_point": a saved Apogee ad set template
-
adset_settingsobject optionalA new ad set (questions "audience", "tracking"), or the changes to a copied ad set / template
Fields (26)
-
goalstring optionalNew ad set only. Default: from the campaign objective
-
countriesarray of strings optionalISO codes, e.g. ["FR"] (a new ad set needs countries, regions or cities)
-
regionsarray of objects optionalRegion keys from search_targeting(type: locations)
Fields of each item (1)
-
keystring required
-
-
citiesarray of objects optionalCity keys from search_targeting(type: locations)
Fields of each item (3)
-
keystring required -
radiusnumber optional -
distance_unitstring optional
-
-
age_mininteger optional -
age_maxinteger optional -
gendersstring optionalDefault all
-
localesarray of integers optionalLanguage keys from search_targeting(type: locales)
-
advantage_audienceboolean optionalDefault true (broad)
-
custom_audience_idsarray of strings optionallist_custom_audiences
-
excluded_audience_idsarray of strings optionallist_custom_audiences
-
interestsarray of objects optionalsearch_targeting(type: interests)
Fields of each item (2)
-
idstring required -
namestring optional
-
-
behaviorsarray of objects optionalsearch_targeting(type: behaviors)
Fields of each item (2)
-
idstring required -
namestring optional
-
-
life_eventsarray of objects optionalsearch_targeting(type: demographics): the app's demographics / life events
Fields of each item (2)
-
idstring required -
namestring optional
-
-
placementsone of optional"advantage" (Advantage+ placements, the default) or the platforms to keep
option 1(0 fields)option 2(1 fields)-
publisher_platformsarray of strings required
-
-
pixel_idstring optionalA pixel (list_pixels)
-
eventstring optionalMeta enum: PURCHASE, LEAD, CONTENT_VIEW, INITIATED_CHECKOUT, ADD_TO_CART, COMPLETE_REGISTRATION…
-
custom_event_strstring optionalA pixel custom event name (sent as OTHER + this name)
-
custom_conversion_idstring optionalA custom conversion (sent alone)
-
optimization_goalstring optionalNew ad set: overrides the default optimization (e.g. LINK_CLICKS for traffic)
-
bid_strategystring optionalABO: the new ad sets' strategy (default Lowest cost, the highest volume). CBO: must be the campaign's (or leave it out)
-
bid_amountnumber optionalCOST_CAP / LOWEST_COST_WITH_BID_CAP: the cost per result goal (cost cap) or bid cap of every new ad set, account currency (adset_variants: one each)
-
roas_floornumber optionalLOWEST_COST_WITH_MIN_ROAS: the minimum ROAS of every new ad set, e.g. 2.5 (adset_variants: one each)
-
attributionobject optionalDefault 7-day click, 1-day view, 1-day engaged view
Fields (3)
-
clickstring required -
viewstring optional -
engaged_viewstring optional
-
-
application_idstring optionalapp_installs
-
object_store_urlstring optionalapp_installs: App Store / Play Store link
-
-
copy_ad_fromstring optionalQuestion "starting_point": the ad whose settings are copied ("latest" = TikTok: the latest ad)
-
ad_template_idstring optionalQuestion "starting_point": a saved Apogee ad template
-
ad_settingsobject optionalA new ad (questions "identity", "destination"), or the changes to a copied ad / template
Fields (8)
-
page_idstring optionalA Facebook page (list_pages)
-
instagram_idstring or null optionalDefault: the page's linked Instagram
-
partnershipobject or null optionalA partnership ad with a creator who approved the brand's Instagram account, or whose Facebook Page accepted the brand's Page; null = none (default)
Fields (7)
-
creator_ig_idstring optionalAn Instagram creator (get_launch_questions → identity.choices.partnership_creators, source instagram)
-
creator_usernamestring optional -
creator_fb_page_idstring or null optionalAn Instagram creator's Page (default: read from the approved creators; null: none), or alone a Facebook creator (source facebook)
-
creator_namestring optionalA Facebook creator's Page name (as listed)
-
ad_codestring optionalNot used: a partnership ad code boosts the creator's own post, Apogee launches your files. Use creator_ig_id
-
identity_modestring optionaladvertiser_primary = your brand first (default); creator_primary = the creator first (on Instagram only when the creator has no Facebook Page)
-
header_displaystring optionaldynamic (default, Meta picks; optimizes on Instagram only), both identities, or the first identity only
-
-
website_urlstring optionalRequired except for instant forms
-
url_parametersstring optionalUTM parameters, "" = none (required for a new ad)
-
call_to_actionstring optionalRequired for a new ad, e.g. SHOP_NOW, LEARN_MORE, SIGN_UP
-
lead_form_idstring optionalInstant form leads (list_lead_forms)
-
display_linkstring optional
-
-
advantage_plusobject optionalQuestion "advantage_plus" (required)
Fields (1)
-
opt_inarray of strings requiredThe enhancements the user turned ON; every other one is sent OFF. [] = all off
-
-
productsobject optionalQuestion "products" (required when the account has a catalog)
Fields (3)
-
showboolean required"Show relevant products" from the catalog
-
catalog_idstring optionalA catalog (get_launch_questions → products)
-
product_set_idstring optionalA product set of that catalog
-
-
daily_budgetnumber optionalABO: daily budget of each new ad set, account currency (required)
-
launch_statusstring optionalCreated Paused (default), Live Now, Scheduled & Paused, Scheduled & Live
-
scheduleobject optionalScheduled & Paused / Scheduled & Live
Fields (2)
-
datestring requiredYYYY-MM-DD
-
timestring requiredHH:MM, account time zone
-
-
ad_overridesobject optionalAdvanced: raw ad template fields (description, display_link, url_parameters, website_url, call_to_action, instagram_account_id, lead_gen_form_id, primary_texts, headlines)
Fields (9)
-
descriptionany optional -
display_linkany optional -
url_parametersany optional -
website_urlany optional -
call_to_actionany optional -
instagram_account_idany optional -
lead_gen_form_idany optional -
primary_textsany optional -
headlinesany optional
-
-
adset_overridesobject optionalAdvanced: raw ad set template fields (name, billing_event, optimization_goal, destination_type, daily_min_spend_target, daily_spend_cap, start_time, end_time, bid_strategy, bid_amount, bid_constraints, attribution_spec, attribution_setting, targeting), Meta's units
Fields (14)
-
nameany optional -
billing_eventany optional -
optimization_goalany optional -
destination_typeany optional -
daily_min_spend_targetany optional -
daily_spend_capany optional -
start_timeany optional -
end_timeany optional -
bid_strategyany optional -
bid_amountany optional -
bid_constraintsany optional -
attribution_specany optional -
attribution_settingany optional -
targetingany optional
-
-
adgroupsarray of objects optionalTikTok: ad groups made by hand, instead of structure
Fields of each item (5)
-
adsarray of strings requiredThe ad_name of each ad in it (every ad in exactly one group)
-
namestring optionalA new ad group's name
-
existing_adgroup_idstring optionalAn existing ad group to fill instead (all groups existing, or all new)
-
settingsobject optionalThis ad group's own settings, over the shared ones
Fields (15)
-
pixel_idstring optionalA pixel (get_launch_questions → tracking.choices.pixels)
-
optimization_eventstring optionalTikTok's optimization_event: SHOPPING (purchase), INITIATE_ORDER, ON_WEB_CART, ON_WEB_DETAIL, ON_WEB_REGISTER, FORM…
-
bid_typestring optionalDefault BID_TYPE_NO_BID (maximum delivery); BID_TYPE_CUSTOM = cost cap (bid)
-
bidnumber optionalCost cap per conversion (BID_TYPE_CUSTOM), account currency
-
pacingstring optional -
countriesarray of strings optionalISO codes, read into TikTok location ids (or location_ids)
-
location_idsarray of strings optional -
age_groupsarray of strings optional[] or absent = every age
-
genderstring optional -
languagesarray of strings optional -
interest_category_idsarray of strings optional -
action_category_idsarray of strings optional -
audience_idsarray of strings optional -
excluded_audience_idsarray of strings optional -
placementsarray of strings optionalDefault TikTok only
-
-
daily_budgetnumber optionalABO: this one's budget (default daily_budget)
-
-
adsquadsarray of objects optionalSnapchat: ad squads made by hand, instead of structure
Fields of each item (5)
-
adsarray of strings requiredThe ad_name of each ad in it (every ad in exactly one group)
-
namestring optionalA new ad squad's name
-
existing_adsquad_idstring optionalAn existing ad squad to fill instead (all groups existing, or all new)
-
settingsobject optionalThis ad squad's own settings, over the shared ones
Fields (15)
-
optimization_goalstring optionalDefault PIXEL_PURCHASE. The PIXEL_ goals need pixel_id (and enough of that event on the pixel lately: get_launch_questions tracking.choices.optimization_goals); SWIPES and LANDING_PAGE_VIEW need none
-
pixel_idstring optionalA Snap pixel (get_launch_questions → tracking.choices.pixels)
-
bid_strategystring optionalDefault AUTO_BID
-
bidnumber optionalLOWEST_COST_WITH_MAX_BID / TARGET_COST: the bid, account currency
-
pacing_typestring optionalDefault STANDARD
-
conversion_windowstring optionalDefault Snapchat's SWIPE_28DAY_VIEW_1DAY
-
countriesarray of strings optionalISO codes (at least one for a new ad squad)
-
region_idsarray of strings optional -
min_ageinteger optionalDefault 18 for a new ad squad: Snapchat refuses its goal for under-18s in the EU, the EEA, Switzerland and the UK
-
max_ageinteger optional -
gendersstring optional -
languagesarray of strings optional -
interest_idsarray of strings optional -
segment_idsarray of strings optional -
excluded_segment_idsarray of strings optional
-
-
daily_budgetnumber optionalABO: this one's budget (default daily_budget)
-
-
tiktokobject optionalTikTok's own settings (platform tiktok)
Fields (9)
-
new_campaignobject optionalA new Sales campaign (website conversions; Standard, or Upgraded Smart+), created by the launch (instead of campaign_id)
Fields (5)
-
namestring required -
budget_typestring requiredabo = a budget per ad group (daily_budget); cbo = the campaign's budget
-
budgetnumber optionalCBO: the campaign budget, account currency
-
budget_modestring optionalDefault daily
-
smart_plusboolean optionaltrue = an Upgraded Smart+ campaign (website Sales), as the app's Create Campaign: up to 30 ad groups of 30 ads, one ad per creative (its texts rotate inside), TikTok's dynamic CTA (ad_settings.cta_language / cta_texts), no Spark post. Default: a Standard campaign
-
-
adgroup_settingsobject optionalA new ad group's settings, or the changes to a copied one (copy_adset_from)
Fields (15)
-
pixel_idstring optionalA pixel (get_launch_questions → tracking.choices.pixels)
-
optimization_eventstring optionalTikTok's optimization_event: SHOPPING (purchase), INITIATE_ORDER, ON_WEB_CART, ON_WEB_DETAIL, ON_WEB_REGISTER, FORM…
-
bid_typestring optionalDefault BID_TYPE_NO_BID (maximum delivery); BID_TYPE_CUSTOM = cost cap (bid)
-
bidnumber optionalCost cap per conversion (BID_TYPE_CUSTOM), account currency
-
pacingstring optional -
countriesarray of strings optionalISO codes, read into TikTok location ids (or location_ids)
-
location_idsarray of strings optional -
age_groupsarray of strings optional[] or absent = every age
-
genderstring optional -
languagesarray of strings optional -
interest_category_idsarray of strings optional -
action_category_idsarray of strings optional -
audience_idsarray of strings optional -
excluded_audience_idsarray of strings optional -
placementsarray of strings optionalDefault TikTok only
-
-
ad_settingsobject optionalThe ads' TikTok account (and whether their videos show on its profile), destination and CTA (new, or the changes to a copied ad); Smart+ and carousel settings
Fields (8)
-
identityobject optionalFields (3)
-
idstring requiredThe identity id (get_launch_questions → identity.choices.identities)
-
typestring requiredOne of the brand's TikTok accounts: TT_USER, or BC_AUTH_TT through its Business Center (TikTok refuses a custom identity on these ads)
-
bc_idstring or null optionalBC_AUTH_TT: the Business Center
-
-
show_on_profileboolean optionalThe app's "Also show the video on the TikTok profile": true = the video is also posted on the TikTok account's profile; default: it only runs as an ad (TikTok's default). Not where TikTok keeps the videos ads-only (get_launch_questions identity.show_on_profile)
-
website_urlstring optionalApogee's TikTok tracking replaces its own utm_ parameters (no UTM option on TikTok: the app's final URL)
-
call_to_actionstring optionalDefault SHOP_NOW (a Standard ad's; a Smart+ ad runs TikTok's dynamic CTA: cta_language, cta_texts)
-
cta_languagestring optionalSmart+: the language of TikTok's dynamic call to action when the ad group lends none (default en)
-
cta_textsarray of strings optionalSmart+: the calls to action kept among the ones TikTok offers in cta_language (default: TikTok's whole list)
-
automationsobject optionalSmart+: TikTok's automations of the ads (as Meta's Advantage+ creative enhancements), each off unless turned on
Fields (2)
-
auto_addboolean optionalTikTok adds assets of its own
-
enhancementsarray of strings optional
-
-
music_idstring optionalCarousels (image ads): the music, one of list_tiktok_music; default TikTok's pick at the launch
-
-
carousel_modestring optionalImages run as carousels (TikTok's image ads), as the app's Configure switch: single (default) = each image ad a carousel of its image; by_concept = a concept's images one carousel ad named after the concept (35 images at most, its first ad's settings and texts)
-
adgroup_template_idstring (uuid) optionalQuick Bulk Edit: a saved ad group template (list_platform_templates level adgroup), the base of the new ad groups' settings (instead of copy_adset_from); adgroup_settings over it
-
ad_template_idstring (uuid) optionalQuick Bulk Edit: a saved ad template (list_platform_templates level ad), the base of the ads' settings (instead of copy_ad_from); ad_settings over it
-
time_zonestring optionalThe IANA zone of schedule (only when the advertiser's time zone is unknown)
-
end_datestring optionalA lifetime campaign budget (CBO, budget_mode lifetime, a new campaign or an existing one): the date it runs to, YYYY-MM-DD in the schedule's time zone, after the launch (a scheduled launch: TikTok spreads the budget until then). Ignored for a daily budget
-
end_timestring optionalHH:MM of end_date, default the start's time
-
-
snapchatobject optionalSnapchat's own settings (platform snapchat)
Fields (6)
-
new_campaignobject optionalA new Sales campaign, created by the launch (instead of campaign_id)
Fields (3)
-
namestring required -
budget_typestring requiredabo = a budget per ad squad (daily_budget, 5 minimum); cbo = the campaign's (20 minimum per day), Snapchat's Smart Budget: its ad squads share their optimisation goal, pixel, bid strategy and conversion window (get_launch_questions tracking.choices); a lower budget is raised to it
-
budgetnumber optionalCBO: the campaign budget per day, account currency
-
-
adsquad_settingsobject optionalA new ad squad's settings, or the changes to a copied one (copy_adset_from)
Fields (15)
-
optimization_goalstring optionalDefault PIXEL_PURCHASE. The PIXEL_ goals need pixel_id (and enough of that event on the pixel lately: get_launch_questions tracking.choices.optimization_goals); SWIPES and LANDING_PAGE_VIEW need none
-
pixel_idstring optionalA Snap pixel (get_launch_questions → tracking.choices.pixels)
-
bid_strategystring optionalDefault AUTO_BID
-
bidnumber optionalLOWEST_COST_WITH_MAX_BID / TARGET_COST: the bid, account currency
-
pacing_typestring optionalDefault STANDARD
-
conversion_windowstring optionalDefault Snapchat's SWIPE_28DAY_VIEW_1DAY
-
countriesarray of strings optionalISO codes (at least one for a new ad squad)
-
region_idsarray of strings optional -
min_ageinteger optionalDefault 18 for a new ad squad: Snapchat refuses its goal for under-18s in the EU, the EEA, Switzerland and the UK
-
max_ageinteger optional -
gendersstring optional -
languagesarray of strings optional -
interest_idsarray of strings optional -
segment_idsarray of strings optional -
excluded_segment_idsarray of strings optional
-
-
ad_settingsobject optionalThe ads' profile, destination and CTA (new, or the changes to a copied ad)
Fields (5)
-
profile_idstring optionalA public profile (get_launch_questions → identity.choices.profiles)
-
website_urlstring optionalhttps only
-
utmobject optionalUTM parameters appended to the URL (the app's UTM toggle): given = on, the app's defaults for the fields left out
Fields (5)
-
sourcestring optional -
mediumstring optional -
campaignstring optional -
idstring optional -
contentstring optional
-
-
call_to_actionstring optionalDefault SHOP_NOW
-
brand_namestring optional
-
-
adsquad_template_idstring (uuid) optionalQuick Bulk Edit: a saved ad squad template (list_platform_templates level adgroup), the base of the new ad squads' settings (instead of copy_adset_from); adsquad_settings over it
-
ad_template_idstring (uuid) optionalQuick Bulk Edit: a saved ad template (list_platform_templates level ad), the base of the ads' settings (instead of copy_ad_from); ad_settings over it
-
time_zonestring optionalThe IANA zone of schedule (only when the ad account's time zone is unknown)
-
Example
Your assistant calls it for you when you ask in your own words. What it sends (MCP tools/call, JSON-RPC 2.0):
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "prepare_launch",
"arguments": {
"ad_account_id": "act_1234567890",
"campaign_id": "120200000000000001",
"structure": "one_concept_one_adset",
"copy_adset_from": "120200000000000002",
"copy_ad_from": "120200000000000003",
"ads": [
{
"ad_name": "NORDLICHT_RAIN_HOOK1",
"concept": "Rain test",
"files": [
{
"ref": "drive:EXAMPLE_FILE_916",
"name": "NORDLICHT_RAIN_HOOK1_9x16.mp4",
"format": "9:16"
},
{
"ref": "drive:EXAMPLE_FILE_45",
"name": "NORDLICHT_RAIN_HOOK1_4x5.mp4",
"format": "4:5"
}
],
"copy": {
"primary_texts": [
"Rain-proof, wind-proof, and light enough to forget you are wearing it."
],
"headlines": [
"The Nordlicht shell jacket"
],
"description": "Free returns within 30 days"
}
}
],
"grouping_confirmed": true,
"advantage_plus": {
"opt_in": []
},
"daily_budget": 50,
"launch_status": "CREATED_PAUSED"
}
}
} The same call over HTTP with an API key, for an MCP client of your own (an assistant that signs in sends its OAuth token instead):
curl -X POST https://app.apogee.ad/mcp \
-H "Authorization: Bearer $APOGEE_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"prepare_launch","arguments":{"ad_account_id":"act_1234567890","campaign_id":"120200000000000001","structure":"one_concept_one_adset","copy_adset_from":"120200000000000002","copy_ad_from":"120200000000000003","ads":[{"ad_name":"NORDLICHT_RAIN_HOOK1","concept":"Rain test","files":[{"ref":"drive:EXAMPLE_FILE_916","name":"NORDLICHT_RAIN_HOOK1_9x16.mp4","format":"9:16"},{"ref":"drive:EXAMPLE_FILE_45","name":"NORDLICHT_RAIN_HOOK1_4x5.mp4","format":"4:5"}],"copy":{"primary_texts":["Rain-proof, wind-proof, and light enough to forget you are wearing it."],"headlines":["The Nordlicht shell jacket"],"description":"Free returns within 30 days"}}],"grouping_confirmed":true,"advantage_plus":{"opt_in":[]},"daily_budget":50,"launch_status":"CREATED_PAUSED"}}}' Access and cost
| Plans | Pro and Scale. |
|---|---|
| Scope | launch: a connection or an API key without it does not see this tool (scopes). |
| Effect | Stores a plan or an action and says what it will do. Nothing changes on the ad account until it is confirmed. |
| Credits | Free up to the daily free reads (5,000 a day on Pro, 10,000 on Scale), then 1 credit per read. A call that fails costs nothing (credits). |
| Rate limit | 600 MCP requests per 15 minutes on Pro, 1,200 on Scale (rate limits). |
| Daily cap | Counts 10 units toward the 2,000 units one API key or assistant connection can use in 24 hours. |
In the REST API
The same thing for your own code, with an API key:
- Create launch plan:
POST /launch-plans
Related tools
Launch: The interview, the recap, your yes, then the launch.
get_launch_questions: The questions the app asks before every launch, in order, with the choices read from your account and a recommended answer (TikTok's and Snapchat's own withplatform). Called again with the files (it reads their names with your naming convention and proposes the ads) and with the answers so far.launch: Launches a prepared plan (Meta, TikTok or Snapchat: the plan knows), once, after your explicit yes to its recap.launch_status: Follows a launch until it is finished.interruptedmeans an Apogee deploy cut it: check Ads Manager before launching again.create_campaign: Prepares a new campaign, always created paused: name, objective, budget per ad set (ABO) or per campaign (CBO, with its bid strategy).execute_actioncreates it after your OK.