Skip to main content
Glama

create_ad_creative

Create ad creatives for Meta Ads using images, videos, or existing posts. Supports placement customization, multi-variant copy testing, dynamic creative, and Advantage+ optimizations.

Instructions

Create a new ad creative using an uploaded image hash, video ID, or an existing post.

Supports six creative modes:
- **Existing post**: Provide object_story_id (format: {page_id}_{post_id}) to promote an existing
  organic or published post. No image_hash or video_id required. Optionally combine with
  asset_customization_rules to attach a 9:16 video for Story/Reels placements.
- **Simple image/video**: Single image_hash or video_id with object_story_spec
- **Multi-variant copy**: Use plural text params (messages[], headlines[], descriptions[]) to test
  multiple text variants with a single image/video. No optimization_type or is_dynamic_creative needed.
- **Placement Asset Customization (dual-aspect, non-DC)**: Serve different aspect ratios per placement
  on a STANDARD ad set without is_dynamic_creative and without the one-ad-per-ad-set cap. Set
  optimization_type="PLACEMENT" and pass videos=[{video_id, label}, ...] (or images=[{image_hash,
  label}, ...]) together with asset_customization_rules whose customization_spec references those
  labels via video_label/image_label. Every label in the rules MUST appear on a videos[]/images[]
  entry, or Meta returns error_subcode=1487390 ("Adcreative Create Failed").
- **Dynamic Creative**: Multiple variants with dynamic_creative_spec (requires is_dynamic_creative on ad set)
- **FLEX/DOF (Advantage+)**: Set optimization_type="DEGREES_OF_FREEDOM" for Meta to auto-optimize
  across all asset combinations without requiring is_dynamic_creative on the ad set

Args:
    account_id: Meta Ads account ID (format: act_XXXXXXXXX)
    image_hash: Hash of a single uploaded image (cannot be used with image_hashes or video_id)
    access_token: Meta API access token (optional - will use cached token if not provided)
    name: Creative name
    page_id: Facebook Page ID (string or int; coerced to string)
    link_url: Destination URL for the ad. Required unless using lead_gen_form_id or
             reminder_data — with one exception: if asset_customization_rules is also
             set, link_url is required even for Lead ads. Meta accepts the creative
             without link_urls but rejects the ad at create_ad time with error 1885800
             ("Asset Customization Ads require a link"). The URL is never shown to the
             user when lead_gen_form_id is set (the CTA opens the form), but Meta still
             demands one be present on the creative. Pass any valid URL in that case
             (e.g. the Facebook page URL or your site root).
    message: Single ad copy/text (cannot be used with messages)
    messages: List of primary text variants for multi-variant copy testing (cannot be used with message).
              Each entry can be a plain string, OR a dict {"text": "...", "adlabels": [{"name": "..."}]}
              when used with asset_customization_rules that reference body_label.
    headline: Single headline for simple ads (cannot be used with headlines)
    headlines: List of headline variants for multi-variant copy testing (cannot be used with headline).
              Each entry can be a plain string, OR a dict {"text": "...", "adlabels": [{"name": "..."}]}
              when used with asset_customization_rules that reference title_label.
              Meta enforces the actual length limit; do not pre-truncate.
    description: Single description for simple ads (cannot be used with descriptions)
    descriptions: List of description variants for multi-variant copy testing (cannot be used with description).
              Each entry can be a plain string, OR a dict {"text": "...", "adlabels": [{"name": "..."}]}
              when used with asset_customization_rules that reference description_label.
    image_hashes: List of image hashes for FLEX creatives (up to 10, cannot be used with image_hash or video_id).
                 IMPORTANT: When optimization_type="DEGREES_OF_FREEDOM" (FLEX/Advantage+ mode),
                 only ONE image is served at delivery time regardless of how many hashes you provide.
                 The Meta API accepts multiple hashes without error and they all appear in
                 asset_feed_spec, but Meta silently collapses to a single image at serving time.
                 Use image_hashes with multiple entries only in non-DOF (regular dynamic creative)
                 mode. In DOF mode, pass a single hash.
    video_id: Meta video ID for video creatives (cannot be used with image_hash or image_hashes).
              Upload a video first via the Meta API, then use the returned video ID here.
              IMPORTANT: When also providing instagram_actor_id, both instagram_actor_id AND
              ad_formats=["SINGLE_VIDEO"] must be present — otherwise Meta returns error 1443048
              ("object_story_spec ill formed"). This is handled automatically: video creatives
              that include instagram_actor_id are routed through asset_feed_spec so that
              ad_formats=["SINGLE_VIDEO"] is always included in the API request.
    thumbnail_url: Thumbnail image URL for video creatives. Recommended when using video_id.
                  Meta will auto-generate a thumbnail if not provided — Pipeboard
                  will fetch the best available frame from the uploaded video.
                  IMPORTANT: when the video was just uploaded via
                  bulk_upload_ad_videos, Meta needs a few seconds to transcode
                  it. If create_ad_creative is called before transcoding
                  completes, the only thumbnail Meta returns is a generic
                  processing-state placeholder, which would be permanently
                  stored on the creative. In that case create_ad_creative
                  returns an error with video_status: "processing" — wait
                  a few seconds (poll with get_ad_video until video_status
                  is "ready") and retry, or pass thumbnail_url explicitly
                  (any public image URL works).
    optimization_type: Optional. Valid values:
                      - "DEGREES_OF_FREEDOM": FLEX (Advantage+) creatives where Meta auto-optimizes
                        across all asset combinations. At least one multi-variant asset field required.
                        NOTE: Meta ignores asset_customization_rules for DOF creatives.
                        NOTE: When using DEGREES_OF_FREEDOM with image_hashes, providing multiple
                        hashes is accepted by the API without error, but Meta silently serves only
                        ONE image at delivery time. A warning is included in the response if multiple
                        hashes are detected. To serve multiple images, omit optimization_type and
                        enable is_dynamic_creative on the ad set instead.
                      - "PLACEMENT": Placement Asset Customization. Use with videos[]/images[] (with
                        labels) and asset_customization_rules (with video_label/image_label references)
                        to serve different aspect ratios per placement (e.g., 1:1 Feed + 9:16 Reels).
                      Other values are passed through to Meta as-is.
    dynamic_creative_spec: Dynamic creative optimization settings
    call_to_action_type: Call to action button type. Meta enum — free-form values
                        (e.g. 'MAKE_RESERVATION', 'RESERVE', 'BOOK_TABLE') are rejected with
                        code 100. Pick from the documented list. Common values:
                          BOOK_NOW         — restaurants, salons, clinics, appointments (use this for
                                             reservations — there is no MAKE_RESERVATION enum)
                          LEARN_MORE, SHOP_NOW, SIGN_UP, SUBSCRIBE, GET_QUOTE, CONTACT_US,
                          DOWNLOAD, WATCH_MORE, GET_OFFER, APPLY_NOW, CALL_NOW, MESSAGE_PAGE,
                          SEE_MENU, ORDER_NOW, BUY_NOW, WHATSAPP_MESSAGE, GET_DIRECTIONS,
                          BUY_TICKETS, EVENT_RSVP, BOOK_TRAVEL.
                        When using CALL_NOW, also provide phone_number.
    lead_gen_form_id: Lead generation form ID for lead generation campaigns. Required when using
                     lead generation CTAs like 'SIGN_UP', 'GET_OFFER', 'SUBSCRIBE', etc.
    instagram_actor_id: Instagram account ID for Instagram placements (must be a string
                       to avoid JavaScript integer precision loss for IDs exceeding
                       Number.MAX_SAFE_INTEGER). Sent as instagram_user_id inside
                       object_story_spec (Meta deprecated instagram_actor_id in Jan 2026).
                       IMPORTANT for video creatives: Meta requires ad_formats=["SINGLE_VIDEO"]
                       in asset_feed_spec alongside instagram_user_id in object_story_spec —
                       omitting either causes error 1443048 ("object_story_spec ill formed").
                       This is auto-handled: video_id + instagram_actor_id always routes through
                       asset_feed_spec so ad_formats=["SINGLE_VIDEO"] is included automatically.
    ad_formats: List of ad format strings for asset_feed_spec (e.g., ["AUTOMATIC_FORMAT"] for
               Flexible ads, ["SINGLE_IMAGE"] for single image, ["SINGLE_VIDEO"] for video).
               When optimization_type is "DEGREES_OF_FREEDOM" with image_hashes, defaults to
               ["AUTOMATIC_FORMAT"] (Flexible format). For video creatives, defaults to
               ["SINGLE_VIDEO"]. Otherwise defaults to ["SINGLE_IMAGE"].
    asset_customization_rules: List of placement-specific asset overrides for asset_feed_spec.
    phone_number: Phone number for CALL_NOW call-to-action ads (click-to-call).
                 Required when call_to_action_type is CALL_NOW. Use E.164 format
                 (e.g., "+18005551234"). The number is sent to Meta as
                 call_to_action.value.link = "tel:<phone_number>" (Meta v24
                 rejects a literal "phone_number" key with code 100). Common
                 use case: geo-routed call ads with different phone numbers
                 per ad set.
    creative_features_spec: Advantage+ Creative feature opt-ins/opt-outs. Controls individual
               creative enhancements like image_touchups, text_optimizations, inline_comment,
               add_text_overlay, music, 3d_animation, etc. Each feature is a dict with
               "enroll_status" set to "OPT_IN" or "OPT_OUT".
               Example: {"image_touchups": {"enroll_status": "OPT_IN"},
                        "inline_comment": {"enroll_status": "OPT_IN"}}
               Sent to Meta as degrees_of_freedom_spec.creative_features_spec.
    url_tags: URL tracking parameters appended to the destination URL (e.g.,
             "utm_source=facebook&utm_medium=cpc&utm_campaign=spring_sale").
             Sets the url_tags field on the creative.
    caption: Display URL shown in the ad (e.g., "example.com/shoes"). Sets the
            caption field in link_data. If not provided, Meta auto-generates it
            from the destination URL. Only applies to image (link_data) creatives.
    image_crops: Crop coordinates for different aspect ratios. Applied in link_data for
                image creatives.

                Use the compute_image_crops tool first to get the correct coordinates
                for your specific image dimensions — it computes centered crop boxes
                for any source size automatically.

                Valid crop keys (only these 6 are accepted by Meta's API):
                  "100x100"  — 1:1 square (Feed, Marketplace, Search)
                  "100x72"   — ~1.39:1 horizontal (Marketplace, some placements)
                  "400x500"  — 4:5 portrait (Feed on mobile, Stories fallback)
                  "400x150"  — ~2.67:1 wide banner (Audience Network)
                  "600x360"  — ~1.67:1 horizontal (Right column, some placements)
                  "90x160"   — 9:16 tall portrait (Stories)

                Format: {"100x100": [[x1,y1],[x2,y2]], "400x500": [[x1,y1],[x2,y2]]}
                Coordinates are pixel-based (top-left and bottom-right corners).
                The bounding box aspect ratio must match the key ratio as closely as possible.
                Image origin (0,0) is the upper-left corner.

                Omit to let Meta auto-crop (default for horizontal is 1.91:1 recommended).
    object_story_id: ID of an existing organic or published Facebook/Instagram post to promote
                    as an ad. Format: "{page_id}_{post_id}" (e.g., "124965744226834_3888007311337206").
                    When provided, image_hash and video_id are not required. page_id is also not
                    required (it is encoded in the story ID). Combine with asset_customization_rules
                    to attach a 9:16 video for Story/Reels placements while the organic post
                    serves as the feed creative — a common "Use Existing Post" workflow.
                    Example: object_story_id="124965744226834_3888007311337206",
                             asset_customization_rules=[{"placement_groups": ["STORY"],
                               "customization_spec": {"video_ids": ["890310874031162"]}}]
    disable_all_enhancements: When True, opts out of all Advantage+ Creative enhancements by
                    setting every known creative_features_spec key (image_touchups,
                    text_optimizations, video_auto_crop, etc.) to OPT_OUT and also
                    disabling contextual_multi_ads. Use when you want full creative
                    control without Meta's auto-modifications.
    event_id: Facebook Event ID for EVENT_RESPONSES campaigns. Required for
             event RSVP/ticket ads so the event card renders properly. Placed
             inside link_data.event_id, and also inside call_to_action.value
             when call_to_action_type is EVENT_RSVP or BUY_TICKETS. Use with
             link_url set to the Facebook event URL
             (https://www.facebook.com/events/EVENT_ID).
    asset_customization_rules: Lets you assign different images or videos to specific placement groups
               (e.g., feed vs. stories). Only valid with image_hashes or plural asset params.
               Each rule uses a user-friendly format that is automatically translated to
               Meta's API format (adlabels + customization_spec positions):
                 - placement_groups: list of placement group names
                   Valid values: FEED, STORY, MESSENGER, INSTREAM_VIDEO, SEARCH, SHOP,
                   AUDIENCE_NETWORK
                 - customization_spec: dict specifying the asset to use for those placements
                   Supported keys: image_hashes (list), video_ids (list),
                   bodies, titles, descriptions (text overrides)
               All image hashes referenced in rules must also be in image_hashes.
               Example (feed gets one image, stories gets another):
               [
                 {"placement_groups": ["FEED"],
                  "customization_spec": {"image_hashes": ["<feed_hash>"]}},
                 {"placement_groups": ["STORY"],
                  "customization_spec": {"image_hashes": ["<story_hash>"]}}
               ]
    videos: List of video objects for placement asset customization (multiple videos with
               different aspect ratios). Each entry: {"video_id": "...", "thumbnail_url": "...",
               "label": "my_label"}. The "label" field is converted to adlabels for use with
               asset_customization_rules video_label references. Cannot be used with video_id.
               Use with optimization_type="PLACEMENT" and asset_customization_rules.
    images: List of image objects for placement asset customization (multiple images with
               different aspect ratios). Each entry: {"image_hash": "...", "label": "my_label"}.
               The "label" field is converted to adlabels for use with asset_customization_rules
               image_label references. Cannot be used with image_hash or image_hashes.
               Use with optimization_type="PLACEMENT" and asset_customization_rules.
    reminder_data: Inline reminder event data for Instagram Reminder Ads
                  (REMINDERS_SET optimization goal). Placed in
                  object_story_spec.link_data.reminder_data. Use this instead of
                  upcoming_events (which requires an existing ig_upcoming_event_id).
                  Required fields:
                    - event_name (str): Display title of the reminder event
                    - start_time (int): Event start as a Unix timestamp (seconds)
                    - end_time (int): Event end as a Unix timestamp (seconds)
                  Example:
                    {"event_name": "Summer Sale", "start_time": 1745596800, "end_time": 1745611200}
                  The ad set must use optimization_goal=REMINDERS_SET and the placement
                  must be restricted to Instagram feeds/stories. link_url is still
                  recommended (the URL users visit after the reminder fires).
    facebook_branded_content: Branded content settings for Facebook partnership ads.
                  Used when a brand sponsors a creator's content on Facebook.
                  Format: {"sponsor_page_id": "<page_id>"} where sponsor_page_id is the
                  Facebook Page ID of the sponsoring brand. Passed as a top-level field
                  on the ad creative. The creator's page should be set as page_id.
    instagram_branded_content: Branded content settings for Instagram partnership ads.
                  Used when a brand sponsors a creator's content on Instagram.
                  Format: {"sponsor_id": "<instagram_user_id>"} where sponsor_id is the
                  Instagram account ID of the sponsoring brand. Passed as a top-level
                  field on the ad creative.

Returns:
    JSON response with created creative details

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
account_idYes
image_hashNo
access_tokenNo
nameNo
page_idNo
link_urlNo
messageNo
messagesNo
headlineNo
headlinesNo
descriptionNo
descriptionsNo
image_hashesNo
video_idNo
thumbnail_urlNo
optimization_typeNo
dynamic_creative_specNo
call_to_action_typeNo
lead_gen_form_idNo
instagram_actor_idNo
ad_formatsNo
asset_customization_rulesNo
creative_features_specNo
phone_numberNo
url_tagsNo
captionNo
image_cropsNo
object_story_idNo
disable_all_enhancementsNo
event_idNo
reminder_dataNo
videosNo
imagesNo
facebook_branded_contentNo
instagram_branded_contentNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Despite no annotations, the description thoroughly discloses behavioral traits: error codes (error_subcode=1487390, error 1885800), video processing delays with retry logic, Meta silently collapsing multiple image_hashes in DOF mode, auto-handling of ad_formats for videos, and quirks like link_url requirement for asset customization. It goes beyond basic expectations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is very long but well-structured with sections for creative modes, parameter details, and examples. It front-loads the purpose and modes, then uses bullet points and clear headings. Some redundancy exists (e.g., asset_customization_rules explained twice), but the structure supports the tool's complexity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the high complexity (35 parameters, multiple modes, error handling) and minimal output schema, the description covers interactions, constraints, and behavioral notes comprehensively. However, the return value description is minimal ('JSON response with created creative details'), lacking details about typical response fields or status codes, which could be improved for full completeness.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description fully compensates by detailing each of the 35 parameters: formats (e.g., account_id as 'act_XXXXXXXXX', instagram_actor_id as string), constraints (e.g., 'cannot be used with image_hash'), nested structures (e.g., messages as string or dict, asset_customization_rules format), and caveats (e.g., phone_number E.164 format and internal handling). The description adds significant meaning beyond the raw schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Create a new ad creative' and lists six distinct creative modes (existing post, simple image/video, multi-variant copy, placement customization, dynamic creative, FLEX/Advantage+). It distinguishes the tool from siblings like create_ad and compute_image_crops by focusing on creative creation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit guidance on when to use each creative mode and how to combine parameters, including mutual exclusivity rules (e.g., image_hash vs video_id vs object_story_id) and prerequisites (e.g., link_url required for asset customization even for lead ads). It also warns about common errors and suggests alternatives like using compute_image_crops before image_crops.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/pipeboard-co/meta-ads-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server