Meta Ads Write
User wants to add another ad/creative variation to an EXISTING ad set
POST https://api.adspirer.ai/api/v1/tools/add_meta_ad/execute
Authorization: Bearer sk_live_... — your Adspirer API key (required)Content-Type: application/json (required)Idempotency-Key: <uuid> — recommended for write operations to make retries safeAll tool arguments are wrapped in an arguments object.
| Field | Type | Description |
|---|---|---|
ad_set_id | string required | **REQUIRED.** The Meta Ad Set ID to add the ad to. If you don't have it, call `list_meta_ad_sets` first. Example: '120209876543210'. |
ad_type | string required | **REQUIRED.** Type of ad: 'image', 'video', or 'carousel'. Must match the creative source you're providing — image needs image_url/hash/bundle, video needs video_url/existing_video_id, carousel needs cards. |
auto_copy_creative | boolean optional | When True and `existing_image_hash` (or carousel card image_hash) belongs to a DIFFERENT connected Meta account than `ad_account_id`, the image is automatically copied to the target account and the new hash is used in the ad. Default False = pre-validation blocks with an actionable error. ⚠️ **ASK THE USER FIRST.** Auto-copy creates a new image asset in the target Meta account. On accounts with many creatives (e.g. a library of seasonal images), running auto-copy can be wasteful and surprising. Only set this flag after the user explicitly confirms they want the asset copied. Does not apply to videos (`existing_video_id` mismatches still require manual handling). default: false |
image_url | string optional | Image URL (for image type) |
existing_image_hash | string optional | Existing Meta image hash. For image ads, this is the image itself. For video ads, doubles as the video thumbnail (used when Meta's auto-generated thumbnail edge stays empty after upload, which happens for 10-30s on freshly uploaded videos). |
asset_bundle_id | string optional | Asset bundle ID |
story_image_url | string optional | Image URL for Stories/Reels (9:16, recommended 1080x1920px). Uses asset_feed_spec for placement-specific creatives. |
right_column_image_url | string optional | Image URL for Right Column (1.91:1, recommended 1200x628px). Uses asset_feed_spec for placement-specific creatives. |
video_url | string optional | Video URL (for video type) |
existing_video_id | string optional | Existing video ID |
thumbnail_url | string optional | Custom thumbnail URL |
placement_specific_videos | object optional | Map of placement name → video URL or existing Meta video ID. Keys: 'feed' (1:1 or 16:9 horizontal), 'stories_reels' (9:16 vertical), 'right_column' (1.91:1). Values: public MP4 URL or existing video ID. Backend uploads each, resolves thumbnails, builds asset_feed_spec.videos[] + asset_customization_rules[] mapping each video to its placement. Mutually exclusive with video_url / existing_video_id. ad_type='video' only. |
cards | array optional | Carousel cards (2-10). Each card MUST have: `headline` and ONE of `existing_image_hash` (preferred — use the hash from `discover_meta_assets`) OR `image_url` (will upload). `image_hash` is accepted as an alias for `existing_image_hash`. Per-card `landing_page_url` is optional — falls back to the carousel-level `landing_page_url` if omitted. Video-only cards (`video_id` / `existing_video_id` without an image source) are NOT supported; use `create_meta_video_campaign` for video ads. Optional per-card keys: `description` (≤20 chars), `call_to_action`. |
primary_text | string optional | Primary ad text (max 2200 chars, recommended 125). Provide EITHER this (single) OR `primary_texts` (a 2-5 item list for dynamic creative). One of the two is REQUIRED. Ask the user before calling. Supports emojis and line breaks. ⚠️ If the user gives you 2+ primary text variations, put ALL of them in `primary_texts` (one Dynamic-Creative ad) — do not pick one for this field. |
headline | string optional | Headline (max 255 chars, recommended 40). If the user gives you 2+ headline variations, use the `headlines` array instead of this single field. |
landing_page_url | string required | **REQUIRED.** Landing page URL (HTTPS). Ask the user for it before calling. |
call_to_action | string optional | CTA button default: "LEARN_MORE" |
description | string optional | Description (max 255 chars, recommended 30). For 2+ description variations use the `descriptions` array instead. |
display_link | string optional | Optional display URL (caption) shown in the ad instead of the full landing page URL (e.g. 'brand.com'). Must match or redirect to the landing_page_url domain. NOT supported for ad_type='video'. |
image_urls | array optional | List of image URLs for multi-image Dynamic Creative (2-10). Meta automatically tests all combinations and optimizes delivery. Only valid with ad_type='image'. Mutually exclusive with image_url/existing_image_hash/story_image_url. |
headlines | array optional | List of headline variations (2-5). **USE THIS whenever the user gives you 2+ headlines** — one ad, Meta tests the combinations (Dynamic Creative); do not pick one into the singular headline field. Works with image_urls (multi-image DCO) OR on a single image/video. Not supported for carousel — use per-card cards[].headline. |
primary_texts | array optional | List of primary text variations (2-5). **USE THIS whenever the user gives you 2+ primary texts** — one ad, Meta tests the combinations (Dynamic Creative); do not pick one into the singular primary_text field. Works with image_urls (multi-image DCO) OR on a single image/video. Not supported for carousel. |
descriptions | array optional | List of description variations (up to 5). Works with image_urls (multi-image DCO) OR on a single image/video (multi-text A/B testing without DCO). Not supported for carousel — use per-card cards[].description. |
lead_form_id | string optional | Lead form ID for OUTCOME_LEADS campaigns. If not provided, auto-fetched from the ad set's campaign. |
facebook_page_id | string optional | Facebook Page ID |
instagram_account_id | string optional | Instagram account ID |
ad_name | string optional | Custom name for the ad. Also accepts 'name' as alias. |
ad_account_id | string optional | Meta ad account ID |
multi_advertiser | boolean optional | Set to false to opt out of Meta's multi-advertiser ad format at the creative level. Default (None) = Meta's default behavior (enrolled). |
url_tags | string optional | URL parameters (e.g. 'utm_source=meta&utm_medium=cpc&utm_campaign=...') appended to the landing-page URL on every click. Use for UTM tracking. Leading '?' is stripped automatically. Set at the creative level — applies to every click on this ad. |
advantage_plus_creative | boolean optional | Master switch for Meta's Advantage+ Creative AI enhancements. Set False to opt OUT of ALL granular enhancements at once. Leave None or True to keep Meta's defaults. |
disabled_creative_features | array optional | List of granular Advantage+ Creative features to opt OUT of individually. 'standard_enhancements' rejected (deprecated in Meta API v22, breaks duplicate_campaign). |
deep_link_url_ios | string optional | Optional iOS deep link to open a specific app screen (e.g. 'myapp://product/123'). Only takes effect when the parent ad set's campaign is OUTCOME_APP_PROMOTION. |
deep_link_url_android | string optional | Optional Android deep link (e.g. 'myapp://product/123' or 'intent://...'). Only takes effect when the parent ad set's campaign is OUTCOME_APP_PROMOTION. |
{
"arguments": {
"ad_set_id": "string",
"ad_type": "https://example.com",
"landing_page_url": "https://example.com",
"auto_copy_creative": false,
"image_url": "string",
"existing_image_hash": "string",
"asset_bundle_id": "string",
"story_image_url": "string",
"right_column_image_url": "string"
}
}
{
"success": true,
"data": {
"text": "(tool-specific textual output for add_meta_ad)",
"quota": {
"used": 42,
"limit": 150,
"tier": "plus",
"period_end": "2026-05-01"
}
},
"tool": "add_meta_ad"
}
{
"success": false,
"error": "You have 25 meta_ads accounts connected. Please specify which account to use by passing the ad_account_id parameter:\n - Acme Holdings (ad_account_id=\"act_123456789\")\n - Acme EU (ad_account_id=\"act_987654321\")",
"is_error": true,
"tool": "add_meta_ad"
}
{
"success": false,
"error": "\ud83d\udea8 Monthly limit reached (150/150 tool calls on Plus tier).\nUpgrade to Pro at https://adspirer.ai to keep building.",
"is_error": true,
"tool": "add_meta_ad",
"quota": {
"used": 150,
"limit": 150,
"tier": "plus",
"period_end": "2026-05-01",
"upgrade_url": "https://adspirer.ai"
}
}
Interactive: Swagger UI
Machine-readable: OpenAPI 3.1 spec · llms-full.txt
Adspirer REST API — get an API key at adspirer.ai/keys · adspirer.ai