Skip to main content
Prerequisite A Growi organization on the Growth plan or higher, a connected Meta ad account with at least one campaign and ad set, and an owner or admin who can create an API key.

How to automate Meta ad launches

The API under /api/public/v1/meta_ads, and Claude with the Growi MCP server, let you turn creator social posts, TikTok Shop videos and content submissions into Meta ads in ad sets you already have. A daily job usually looks like this:
  1. List ad sources: new creator posts, TikTok Shop videos or approved submissions.
  2. Read the builder options: ad account, ad set, copy, CTA, UTMs and each creator’s tracking link, in one call.
  3. Create the ads in bulk, up to 50 per request, launched as soon as they publish.
  4. Poll the ads while Growi publishes them to Meta.
  5. Launch or pause individual ads when you need to.
The seven endpoints are listed under Meta ads in the API reference.
Campaigns, ad sets, targeting, ad account sync, partnership requests, Meta ad codes, copy templates, UTM params and naming are managed in the dashboard under Meta Ads. The API reads your saved settings and builds ads into the ad sets you set up there.

Before you start

An API key

  1. In the Growi dashboard, open Settings → Developer.
  2. Under API keys, choose Full access in the access level menu.
  3. Click Add API key and copy the key.
Only owners and admins can create keys. A key acts as the person who created it, with their current role: if their role changes, so does what the key can do, and if they leave the organization the key stops working.
  • Full access keys can create, launch and pause ads, as long as the key’s person is an owner or admin. If that person now has the viewer role, the key is read-only.
  • View only keys can call the GET endpoints but get 403 on bulk, launch and pause.
Treat the key like a password: anyone who has it can spend on your Meta ad account.

A connected Meta ad account with sync on

  1. Connect Meta in Settings → Integrations → Meta Ads.
  2. In Meta Ads → Settings → Ad Accounts, turn on auto-sync for every ad account you run creator ads from. The active account always syncs.
  3. Create the campaigns and ad sets you want to fill in the Meta Ads builder, or import them from Ads Manager.
Ads publish with your organization’s active Facebook page and Instagram account, so both need to be connected. Spend and results only reach Growi, and count toward creator payouts, for ad accounts that sync.

Creators who are ready for partnership ads

To run an ad as the creator (a partnership ad, with the creator’s name on it), the creator must approve your partnership request on Instagram. Send requests and check who approved in Meta Ads → Partnerships. List ad sources shows each creator’s readiness in whitelisting_status and gives you the approved request in meta_partnership_ad_request_id. Creators also need an active enrollment in the campaign that pays them for Meta ads, so they have a Meta tracking link. See How creators get credited and paid.

Authentication and base URL

A parent organization’s key can act on one of its brands by adding organization_id=<brand id> to any request. Any other id returns 404.

1. List ad sources

List ad sources returns the content you can build ads from. Pick a source: For a daily job, ask for content from the last day that is not in an ad yet:
Other filters: campaign_id, campaign_affiliate_id, creator_id (Growi user id), search, page and per_page (up to 100). Dates default to the last 30 days and can span up to 366 days. From each row you need:
  • creative_source: copy its keys into the ad’s creative as they are.
  • meta_partnership_ad_request_id: send it to run the ad as the creator.
  • creator.id: to get the creator’s Meta tracking link in step 2.

2. Read the builder options

Get builder options returns everything else you need in one call. Read it once at the start of a run and reuse it for every ad.
Pages, campaigns and ad sets are for one ad account: the active one, or the one you pass as meta_ad_account_id. Pass meta_campaign_id to see only the ad sets of one campaign.
The API does not apply your naming convention, default CTA, copy template text or UTM params for you. Read them here and put the values in each ad.
Meta allows 50 ads per ad set (150 with Advantage+ audience). If you build more ads than one ad set can take, spread them across ad sets using max_ads - ads_count, or add ad sets in the dashboard first.

3. Create ads in bulk

Create ads in bulk takes up to 50 ads. Each row is checked and created on its own, so one bad row does not stop the rest.
Send each batch of up to 50 ads in one bulk call with "launch_state": "active". The ads turn on by themselves as soon as they publish, so you do not need a launch call per ad. With the default limit of 40 requests per hour, that keeps a daily run to a handful of requests.
Each ad needs:
  • name, meta_ad_account_id and meta_ad_set_id (an existing ad set of that ad account).
  • creative with primary_text, headline, call_to_action, link_url and the row’s creative_source keys.
  • Optionally launch_state (paused by default, or active), meta_partnership_ad_request_id and copy_template_id.
The response is 207 with one result per row:
Keep the meta_ad_id of every successful row: it is the Growi ad id you use from now on.

4. Poll the ads

Growi publishes each ad to Meta in the background, usually within a few minutes. Ask for all of a run’s ads in one call with List ads, up to 200 ids:
status is Meta’s own delivery status (ACTIVE, PAUSED, DELETED, ARCHIVED). Get an ad returns the same fields for one ad.

5. Launch or pause

  • Launch turns the ad, its ad set and its campaign on. Spend starts. An ad that has not published yet launches as soon as it does (deferred: true).
  • Pause pauses the ad on Meta.
Each call is one request, so use them for single ads. For a batch, set launch_state on the bulk call instead.

Example: a daily job

This Python sketch builds partnership ads from yesterday’s Instagram posts with your default copy template, fills the ad sets of one campaign, launches them as they publish, and reports failures. It spaces requests 2 seconds apart and waits out 429 responses.
This run makes 2 requests, plus one per batch of 50 ads and one per poll, well inside the default hourly limit. Poll with per_page at or above the number of ids you send.

How creators get credited and paid

Growi credits each ad to one creator enrollment when you create it, and the ad’s campaign_affiliate_id shows which one:
  • An ad built from a creator’s social post is credited to the enrollment that post is attributed to.
  • An ad built from a content submission is credited to the enrollment the submission came from.
  • Otherwise, a link_url that carries the creator’s Meta tag (a=meta_<tag>, from creator_links in Get builder options) credits the creator the tag belongs to.
Always use the creator’s Meta link as link_url, whatever the source. Growi attributes purchases to the creator through that tag. It also attributes ads made outside Growi when their URL has a=meta_<tag>, utm_source=meta and utm_content={{ad.id}}. What the creator earns depends on the campaign they are enrolled in: A campaign can also require creators to deliver a number of posts before their Meta commissions unlock. Ad spend commission, sales and fees show up in the creator’s payouts like any other earnings. If a creator is removed from a campaign, ads already credited to that enrollment stay on it: re-add the creator to the same campaign to keep treating those ads as active on that program.

Rate limits and batching

The Meta ads endpoints share your organization’s public API limits:
  • 2 seconds between requests from the same key.
  • 40 requests per hour per key by default. Some organizations have a higher limit; the X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers on each response show yours.
  • Over a limit you get 429 with a Retry-After header and retry_after in the body. The hourly limit resets at the top of the hour.
Claude and other MCP clients have their own budget and do not use these requests. See Connect Claude to Growi. To stay inside the limit:
  • Send up to 50 ads per bulk request with launch_state: "active", instead of one request per ad and a launch call per ad.
  • Read builder options once per run and reuse them.
  • Poll List ads for up to 200 ids in one call, every few minutes.
  • Use per_page=100 on sources.

Errors and troubleshooting

Rows in a bulk request fail with a PREFLIGHT_* code before anything is created; the full list is on Create ads in bulk. Ads that fail while publishing end in state: failed with error_message and last_step.
meta_ad_set_id is missing, is not one of your ad sets, or belongs to a different ad account than meta_ad_account_id. Use an id from meta_ad_sets in builder options for the same ad account.
The ad set already holds Meta’s maximum of 50 ads (150 with Advantage+ audience). Rows run in order and ads created by earlier rows in the same request count, so the rows past the limit fail. Spread rows across ad sets using ads_count and max_ads from builder options, or add an ad set in the dashboard.
creative.call_to_action must be a Meta CTA type such as SHOP_NOW or LEARN_MORE. allowed.call_to_actions in builder options lists every value.
Your organization has no active Instagram account for the ad. Check instagram_accounts in builder options, or send creative.require_instagram: false to run the ad from the Facebook page only.
The ad set optimizes for conversions and the ad account has no Meta pixel. Install one, or pick an ad set with another goal.
The partnership request is not approved yet, or Meta says the creator’s Instagram account is not eligible. Check Meta Ads → Partnerships, or build the ad without meta_partnership_ad_request_id to run it from your page.
The ad set’s campaign was archived or deleted in Ads Manager. Builder options hides closed campaigns and ad sets, so read it again and pick another ad set.
A campaign_id, campaign_affiliate_id or creator_id that is not in your organization, a bad date or range, or tik_tok_shop_videos when no TikTok Shop is connected. The error field says which.
Growi could not download the post’s video. Ask the creator for the file, or build the ad from a content submission instead.
Check that the ad has the creator’s campaign_affiliate_id (Get an ad), that its ad account syncs, and that the creator’s campaign pays Meta ad spend commission. Use the creator’s Meta link as link_url on new ads.

Do the same with Claude

If you connected Claude to Growi, you can run the whole flow by asking, for example: “Build partnership ads from yesterday’s Instagram posts into the Broad US ad set, launch them, then tell me which ones failed.” create_meta_ads and manage_meta_ads need an owner or admin, connected with their Growi login or with a full-access key they created. Both ask before they change anything:
  1. Claude calls the tool without confirming. Nothing is created or changed: create_meta_ads checks every ad and reports which ones would fail and which would start spend, and manage_meta_ads lists the ads that would change.
  2. Claude shows you the plan.
  3. After you approve, Claude calls the tool again with the same arguments and the confirmation token from step 1. The token works once, only for those exact arguments, and expires after 10 minutes.
On the MCP budget, list_meta_ad_sources costs 5 units, create_meta_ads and manage_meta_ads cost 3, and the other tools cost 1.