Docs menu

REST API · Actions

Create action

Prepare an action: what will change is answered, nothing changes until it is confirmed

POSThttps://api.apogee.ad/api/v1/actions

Scope: actions (launch for create_campaign) Pro and Scale plans Credits: Free* Idempotency-Key required

What it does

Meta types: pause_ad, pause_adset, activate_ad, activate_adset, update_budget, scale_budget, duplicate_ad, duplicate_adset, duplicate_campaign, create_adset, create_ad, update_adset_targeting, update_campaign_status, create_campaign, create_ad_from_post. TikTok / Snapchat types (with platform and that platform's ad account id): set_platform_status, set_platform_daily_budget. Budgets above the safety cap are refused. duplicate_ad: Keeps the SAME Facebook post (its likes, comments and shares): a new ad on its post id, else on its creative (Meta's /copies made a new post). Instagram starts a new post for each ad, as with a post id in Ads Manager. Only inside the same ad account (a copy into another ad account makes a new post); changing a text or the URL afterwards makes a new post too. The result lists each new ad id and the method used (post_id: shown as an existing post in Ads Manager; shared_creative: the same post shown as a new ad).

Request

POST /actions on https://api.apogee.ad/api/v1.

Headers

  • Authorization string header required

    Bearer apk_…: an API key with the scope of this route.

  • Idempotency-Key string header required

    A unique key per request, e.g. a UUID, reused when you retry it: the first answer comes back instead of a second write (idempotency).

    1 to 255 visible ASCII characters

  • Content-Type string header required

    application/json

Body

The body takes one of 17 shapes, chosen by its type:

type: "pause_ad"
  • ad_account_id string required

    Meta ad account id (act_…)

    Matches ^(act_)?\d{1,32}$

  • type constant required

    Always pause_ad

  • input object required

    Pause one or more ads. Use when user asks to pause, cut, stop, or kill specific ads. Always confirm with the user before executing.

    Fields (2)
    • ad_ids array of strings required

      Array of ad IDs to pause

    • ad_names array of strings required

      Names of the ads for confirmation display

type: "pause_adset"
  • ad_account_id string required

    Meta ad account id (act_…)

    Matches ^(act_)?\d{1,32}$

  • type constant required

    Always pause_adset

  • input object required

    Pause one or more ad sets. Use when user asks to pause, cut, stop, or kill specific ad sets. Preferred over pause_ad for 1-ad-per-adset structures. When user wants to pause/cut a creative, use this tool with the adset_id.

    Fields (2)
    • adset_ids array of strings required

      Array of ad set IDs to pause

    • adset_names array of strings required

      Names of the ad sets for confirmation display

type: "activate_ad"
  • ad_account_id string required

    Meta ad account id (act_…)

    Matches ^(act_)?\d{1,32}$

  • type constant required

    Always activate_ad

  • input object required

    Reactivate one or more paused ads to ACTIVE status. Use when user asks to reactivate, resume, restart, turn on specific ads.

    Fields (2)
    • ad_ids array of strings required

      Array of ad IDs to activate

    • ad_names array of strings optional

      Names of the ads for confirmation display

type: "activate_adset"
  • ad_account_id string required

    Meta ad account id (act_…)

    Matches ^(act_)?\d{1,32}$

  • type constant required

    Always activate_adset

  • input object required

    Reactivate one or more paused ad sets to ACTIVE status. Use when user asks to reactivate, resume, restart, turn on specific ad sets.

    Fields (2)
    • adset_ids array of strings required

      Array of ad set IDs to activate

    • adset_names array of strings optional

      Names of the ad sets for confirmation display

type: "update_budget"
  • ad_account_id string required

    Meta ad account id (act_…)

    Matches ^(act_)?\d{1,32}$

  • type constant required

    Always update_budget

  • input object required

    Update daily budget for one or more ad sets. Use when user asks to scale, increase, decrease, or change budget.

    Fields (1)
    • updates array of objects required

      Array of budget updates

      Fields of each item (4)
      • adset_id string optional
      • adset_name string optional
      • current_budget number optional

        Current daily budget in account currency

      • new_budget number optional

        New daily budget in account currency

type: "scale_budget"
  • ad_account_id string required

    Meta ad account id (act_…)

    Matches ^(act_)?\d{1,32}$

  • type constant required

    Always scale_budget

  • input object required

    Scale budgets of ad sets by a percentage (e.g. +30% or -20%). Fetches current budgets, calculates new ones, and shows confirmation with before/after. Max +100% per operation, min 1€/day.

    Fields (3)
    • adset_ids array of strings required

      Array of ad set IDs to scale

    • percentage number required

      Percentage to scale by (e.g. 30 for +30%, -20 for -20%). Max +100, cannot go below 1€/day.

    • adset_names array of strings optional

      Names of the ad sets

type: "duplicate_ad"
  • ad_account_id string required

    Meta ad account id (act_…)

    Matches ^(act_)?\d{1,32}$

  • type constant required

    Always duplicate_ad

  • input object required

    Duplicate a winning ad into one or more target ad sets of the same ad account, on the SAME Facebook post: its likes, comments and shares stay (a new ad on its post id, else on its creative). Instagram starts a new post for each ad, as with a post id in Ads Manager. Use when user asks to duplicate, replicate, scale a winning creative to other campaigns. Keeps the SAME Facebook post (its likes, comments and shares): a new ad on its post id, else on its creative (Meta's /copies made a new post). Instagram starts a new post for each ad, as with a post id in Ads Manager. Only inside the same ad account (a copy into another ad account makes a new post); changing a text or the URL afterwards makes a new post too. The result lists each new ad id and the method used (post_id: shown as an existing post in Ads Manager; shared_creative: the same post shown as a new ad).

    Fields (5)
    • source_ad_id string required

      ID of the ad to duplicate

    • source_ad_name string required

      Name of the source ad (for confirmation display)

    • target_adset_ids array of strings required

      Ad set IDs to duplicate into

    • target_adset_names array of strings required

      Names of target ad sets (for confirmation display)

    • rename_suffix string optional

      Optional suffix to append to duplicated ad names (e.g. " - Copy")

type: "duplicate_adset"
  • ad_account_id string required

    Meta ad account id (act_…)

    Matches ^(act_)?\d{1,32}$

  • type constant required

    Always duplicate_adset

  • input object required

    Duplicate an ad set WITH its ads into the same campaign or a different one. Each copied ad keeps its post (likes, comments, shares keep adding up). The duplicate is created as PAUSED. Use when user asks to duplicate or copy an ad set.

    Fields (4)
    • source_adset_id string required

      ID of the ad set to duplicate

    • target_campaign_id string optional

      Optional: campaign ID to duplicate into (defaults to same campaign)

    • new_name string optional

      Optional: added after the source's name ("<source name> - <new_name>"), e.g. a market or a version

    • new_budget number optional

      Optional: new daily budget in account currency

type: "duplicate_campaign"
  • ad_account_id string required

    Meta ad account id (act_…)

    Matches ^(act_)?\d{1,32}$

  • type constant required

    Always duplicate_campaign

  • input object required

    Duplicate a full campaign with all its ad sets and ads (archived and deleted ones left out). Each copied ad keeps its post. The duplicate is created as PAUSED. Use when user asks to duplicate or copy a campaign.

    Fields (3)
    • source_campaign_id string required

      ID of the campaign to duplicate

    • new_name string optional

      Optional: added after the source's name ("<source name> - <new_name>"), e.g. a market or a version

    • status_option string optional

      Status for the new campaign (default PAUSED)

      One of PAUSED, ACTIVE

type: "create_adset"
  • ad_account_id string required

    Meta ad account id (act_…)

    Matches ^(act_)?\d{1,32}$

  • type constant required

    Always create_adset

  • input object required

    Create a new ad set in an existing campaign. The ad set is created as PAUSED. Use when user asks to create a new ad set or audience. In a campaign budget (CBO) leave daily_budget out: the campaign's budget and bid strategy apply, each ad set gets its own bid_amount / roas_floor. In ABO, daily_budget is required. copy_from_adset_id copies the audience, optimization, conversion event, destination and attribution of an ad set of the same account (then targeting and optimization_goal can be left out).

    Fields (12)
    • campaign_id string required

      Campaign ID to create the ad set in

    • name string required

      Ad set name

    • copy_from_adset_id string optional

      Optional: an ad set of the same account to copy targeting, optimization_goal, billing_event, promoted_object, destination_type and attribution_spec from (its budget, bid and schedule are not copied)

    • daily_budget number optional

      ABO only: daily budget in cents (e.g. 2000 = 20€). Leave it out in a CBO campaign

    • targeting object optional

      Targeting spec (geo_locations, age_min, age_max, genders, interests, custom_audiences, etc.). Required unless copy_from_adset_id

    • optimization_goal string optional

      Optimization goal (e.g. OFFSITE_CONVERSIONS, LINK_CLICKS, IMPRESSIONS). Required unless copy_from_adset_id

    • promoted_object object optional

      Conversion event, e.g. { pixel_id, custom_event_type: "PURCHASE" }. Required for OFFSITE_CONVERSIONS / VALUE / LEAD_GENERATION unless copied

    • billing_event string optional

      Billing event (default IMPRESSIONS)

    • bid_strategy string optional

      ABO: this ad set's bid strategy (default LOWEST_COST_WITHOUT_CAP). CBO: the campaign's (leave it out)

      One of LOWEST_COST_WITHOUT_CAP, COST_CAP, LOWEST_COST_WITH_BID_CAP, LOWEST_COST_WITH_MIN_ROAS

    • bid_amount number optional

      Cost cap / bid cap in cents (e.g. 2500 = 25€): required with COST_CAP and LOWEST_COST_WITH_BID_CAP

    • roas_floor number optional

      Minimum ROAS strategy: the ROAS floor, e.g. 2.5 (optimization becomes VALUE)

    • start_time string optional

      Optional: start time in ISO format

type: "create_ad"
  • ad_account_id string required

    Meta ad account id (act_…)

    Matches ^(act_)?\d{1,32}$

  • type constant required

    Always create_ad

  • input object required

    Create a new ad in an existing ad set. Use an object_story_id (page post ID) to preserve social proof (likes, comments, shares), or a creative_id to reuse an existing creative. The ad is created as PAUSED.

    Fields (5)
    • adset_id string required

      Ad set ID to create the ad in

    • name string required

      Ad name

    • object_story_id string optional

      Optional: existing post ID (format pageId_postId) to preserve social proof

    • creative_id string optional

      Optional: existing creative ID to reuse (used if no object_story_id)

    • status string optional

      Ad status (default PAUSED)

      One of PAUSED, ACTIVE

type: "update_adset_targeting"
  • ad_account_id string required

    Meta ad account id (act_…)

    Matches ^(act_)?\d{1,32}$

  • type constant required

    Always update_adset_targeting

  • input object required

    Update the targeting of an existing ad set. Use when user asks to change audience, targeting, demographics, interests, or locations.

    Fields (3)
    • adset_id string required

      Ad set ID to update

    • targeting object required

      New targeting spec (geo_locations, age_min, age_max, genders, flexible_spec, custom_audiences, etc.)

    • adset_name string optional

      Ad set name for confirmation display

type: "update_campaign_status"
  • ad_account_id string required

    Meta ad account id (act_…)

    Matches ^(act_)?\d{1,32}$

  • type constant required

    Always update_campaign_status

  • input object required

    Change the status of an entire campaign (ACTIVE or PAUSED). Use when user asks to pause or activate a whole campaign.

    Fields (3)
    • campaign_id string required

      Campaign ID

    • status string required

      New status

      One of ACTIVE, PAUSED

    • campaign_name string optional

      Campaign name for confirmation display

type: "create_campaign"
  • ad_account_id string required

    Meta ad account id (act_…)

    Matches ^(act_)?\d{1,32}$

  • type constant required

    Always create_campaign

  • input object required

    A new campaign (the app's Create Campaign), always created PAUSED. Scope launch.

    Fields (5)
    • name string required

      1 to 255 characters

    • objective string required

      One of OUTCOME_SALES, OUTCOME_LEADS, OUTCOME_TRAFFIC, OUTCOME_ENGAGEMENT, OUTCOME_AWARENESS, OUTCOME_APP_PROMOTION

    • budget_type string required

      abo = budget per ad set; cbo = campaign budget

      One of abo, cbo

    • budget number optional

      CBO only: daily campaign budget, in the account currency

      > 0

    • bid_strategy string optional

      CBO: the bid strategy shared by all ad sets; each new ad set then gets its own bid_amount / roas_floor (prepare_launch adset_variants). ABO: leave it out and use adset_settings.bid_strategy.

      One of LOWEST_COST_WITHOUT_CAP, COST_CAP, LOWEST_COST_WITH_BID_CAP, LOWEST_COST_WITH_MIN_ROAS

type: "create_ad_from_post"
  • ad_account_id string required

    Meta ad account id (act_…)

    Matches ^(act_)?\d{1,32}$

  • type constant required

    Always create_ad_from_post

  • input object required

    A new ad on an EXISTING post (Facebook or Instagram): its likes, comments and shares are kept. Advantage+ choices required, every other enhancement OFF.

    Fields (11)
    • adset_id string required

      The ad set the new ad goes in (list_adsets)

      Matches ^\d{1,40}$

    • name string required

      The new ad's name

      1 to 255 characters

    • advantage_plus object required

      Required: the Advantage+ creative enhancements, all explicit

      Fields (1)
      • opt_in array of strings required

        Enhancements turned ON; every other one is sent OFF. [] = all off

        One of enhance_cta, inline_comment, reveal_details_over_time, show_destination_blurbs, show_summary, text_optimizations, product_tags, optimize_website_destination, shop, product_browsing, browser_addons, image_brightness_and_contrast, image_templates, image_touchups, video_auto_crop, video_filtering

    • object_story_id string optional

      A Facebook post: <pageId>_<postId> (list_posts)

      Matches ^\d{1,40}_\d{1,40}$

    • instagram_media_id string optional

      An Instagram post (list_posts source instagram or ads)

      Matches ^\d{1,40}$

    • instagram_user_id string optional

      Instagram post: the account that published it

      Matches ^\d{1,40}$

    • page_id string optional

      Instagram post: the Facebook page linked to that account

      Matches ^\d{1,40}$

    • call_to_action string optional

      Instagram post only: e.g. SHOP_NOW, LEARN_MORE

      up to 40 characters

    • website_url string optional

      Instagram post only, with call_to_action

      up to 2,048 characters

    • url_parameters string optional

      UTM parameters added to the post's link

      up to 1,000 characters

    • status string optional

      Default PAUSED

      One of PAUSED, ACTIVE

type: "set_platform_status"
  • ad_account_id string required

    The ad account, from list_ad_accounts with the same platform: a TikTok advertiser id (digits), a Snapchat ad account id (a UUID)

    Matches ^[A-Za-z0-9][A-Za-z0-9-]{0,63}$

  • platform string required

    tiktok or snapchat (Meta has its own reads and actions)

    One of tiktok, snapchat

  • type constant required

    Always set_platform_status

  • input object required

    TikTok / Snapchat: pause or activate campaigns, ad sets (TikTok ad groups, Snapchat ad squads) or ads of the ad account (platform and its own ad account id at the top). TikTok GMV Max and legacy Smart+ campaigns, and the ads TikTok generates inside Smart+ ad groups, are refused.

    Fields (3)
    • level string required

      campaign, adset (a TikTok ad group / a Snapchat ad squad) or ad

      One of campaign, adset, ad

    • ids array of strings required

      1 to 50 campaigns, ad sets or ads of that level

      1 to 50 items

      Matches ^[A-Za-z0-9][A-Za-z0-9-]{0,63}$

    • status string required

      paused (stops delivering) or active (delivers again)

      One of paused, active

type: "set_platform_daily_budget"
  • ad_account_id string required

    The ad account, from list_ad_accounts with the same platform: a TikTok advertiser id (digits), a Snapchat ad account id (a UUID)

    Matches ^[A-Za-z0-9][A-Za-z0-9-]{0,63}$

  • platform string required

    tiktok or snapchat (Meta has its own reads and actions)

    One of tiktok, snapchat

  • type constant required

    Always set_platform_daily_budget

  • input object required

    TikTok / Snapchat: a campaign's or an ad set's new daily budget, in the ad account's currency. Refused above the safety cap (converted to the account's currency), on a lifetime budget, on an ad set whose campaign holds the budget, and on TikTok Smart+ budgets.

    Fields (3)
    • level string required

      campaign (its campaign budget) or adset (a TikTok ad group / a Snapchat ad squad)

      One of campaign, adset

    • id string required

      The campaign or ad set (get_platform_performance shows its daily_budget)

      Matches ^[A-Za-z0-9][A-Za-z0-9-]{0,63}$

    • daily_budget number required

      The new daily budget, in the ad account's currency (not cents or micro)

      > 0

Response

201.

  • id string
  • status string

    One of prepared, done, expired

  • type string or null
  • platform string

    One of meta, tiktok, snapchat

  • ad_account_id string or null
  • will_do string or null
  • created_at string or null
  • expires_at string (date-time)
  • executed_at string or null

Every answer carries X-Request-Id (give it to support), Apogee-Version: 2026-10-06, and the RateLimit and RateLimit-Policy headers; a replayed answer also carries Idempotent-Replayed: true.

Errors

Errors are application/problem+json with a stable code to switch on (all the codes).

Example

With your key in APOGEE_API_KEY (create one):

Request
curl -X POST 'https://api.apogee.ad/api/v1/actions' \
  -H "Authorization: Bearer $APOGEE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "ad_account_id": "act_1234567890",
  "type": "pause_ad",
  "input": {
    "ad_ids": [
      "120200000000000003"
    ],
    "ad_names": [
      "Nordlicht | Spring launch"
    ]
  }
}'
Response 201 (shape)
{
  "id": "120200000000000001",
  "type": "120200000000000001",
  "platform": "meta",
  "ad_account_id": "act_1234567890",
  "status": "prepared",
  "will_do": "Pause 1 ad in act_1234567890: Nordlicht | Spring launch.",
  "created_at": "2026-10-23T09:00:00.000Z",
  "expires_at": "2026-10-23T09:00:00.000Z",
  "executed_at": "2026-10-23T09:00:00.000Z"
}

Access and cost

PlansPro and Scale.
Scopeactions (launch for create_campaign) (scopes).
CreditsFree up to the daily free reads (5,000 a day on Pro, 10,000 on Scale), then 1 credit per read. A request that fails costs nothing, a replayed one neither (credits).
Rate limitWrite: 120 per 15 minutes on Pro, 240 on Scale (rate limits).
Meta budgetReads Meta: spends 1 unit of the account's Meta budget (1,800 per 15 minutes, 900 per ad account); with a TikTok or Snapchat platform, that platform's own budget instead.
Daily capCounts 2 units toward the 2,000 units one API key can use in 24 hours.

In the MCP

An AI assistant does the same with these tools of the MCP server:

Last updated on . The parameters, limits, credits and error codes of these pages are generated from the code of the Apogee API (contract 2026-10-06).

A question, something missing? Write to hello@apogee.ad.

Book a demo

Pick the time that suits you.

Open in a new tab

Loading the calendar…

Talk to Founder