> ## Documentation Index
> Fetch the complete documentation index at: https://docs.appeeky.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Meta Ads

> Connect your Meta ad account, launch Facebook and Instagram campaigns, read insights, and look up competitor ads in the Meta Ad Library.

**Meta Ads** connects your own Meta (Facebook and Instagram) ad account to Appeeky. Once connected, you or your AI assistant can create campaigns, ad sets and ads, launch app-install ads, manage audiences and lead forms, and read spend and results. Separately, the **Meta Ad Library** endpoints let you see which ads any app or brand is running, with no Meta account needed.

> [!NOTE]
>
> Managing ads requires a signed-in Appeeky account on the **Indie plan or higher** and a connected Meta ad account. Ad Library search works with any API key.

***

## How it works

```
Connect Meta  →  choose ad accounts  →  create campaign / ad set / ad (paused)  →  review  →  activate  →  read insights
```

* **Everything starts paused.** Campaigns, ad sets, ads and drafts are created with `status: PAUSED` unless you pass `ACTIVE`, so nothing spends money until you turn it on.
* **Default ad account.** Every endpoint accepts `adAccountId` (with or without the `act_` prefix). Leave it out and Appeeky uses your default ad account, or the first one you selected.
* **Budgets are in minor units.** `dailyBudgetMinor: 5000` means 50.00 in your ad account's currency. The one exception is boosting a post, which takes whole currency units.

***

## Connect Meta Ads

In the dashboard: **Settings → Data sources → Ads**, then **Connect Meta Ads**. Sign in with Meta, then pick the ad accounts Appeeky should use.

| Method | Endpoint | Description |
| - | - | - |
| GET | `/v1/connect/meta-ads/oauth/start` | Returns `authorizeUrl` to open in a browser (`?return_to=` optional) |
| GET | `/v1/connect/meta-ads/credentials/status` | Connection status, default ad account and selected ad accounts |
| GET | `/v1/connect/meta-ads/ad-accounts` | Ad accounts your Meta login can access (`?limit=` up to 500, `?after=`) |
| PUT | `/v1/connect/meta-ads/ad-accounts/selection` | Choose which ad accounts Appeeky uses |
| GET | `/v1/connect/meta-ads/ad-accounts/stored` | Ad accounts saved on your Appeeky account |
| PATCH | `/v1/connect/meta-ads/ad-accounts/:adAccountId/default` | Set the default ad account |
| GET | `/v1/connect/meta-ads/pages` | Facebook Pages you can publish ads from |
| GET | `/v1/connect/meta-ads/publisher-identities` | Facebook Pages plus linked Instagram professional accounts |
| DELETE | `/v1/connect/meta-ads/credentials` | Disconnect Meta Ads |

### Pick ad accounts

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
PUT /v1/connect/meta-ads/ad-accounts/selection
{
  "adAccountIds": ["act_123456789", "act_987654321"],
  "preferredDefaultId": "act_123456789"
}
```

`adAccountIds` must contain at least one id. `preferredDefaultId` is optional.

### Connection types

Your account is connected either with a direct Meta login or through a partner connection. `GET /v1/connect/meta-ads/credentials/status` returns `provider: "direct"` for a direct login. Most features work with both; a few depend on the connection type:

| Feature | Direct login | Partner connection |
| - | - | - |
| Campaigns, ad sets, ads, one-call campaigns, insights | Yes | Yes |
| App-install drafts | Yes | Yes (needs `applicationId`, a store URL or `storeAppId`, and `pictureUrl`) |
| Creatives, image upload, advertisable apps | Yes | No |
| Targeting search, audiences, boost post, lead forms | No | Yes |

A feature that your connection type doesn't support returns HTTP `501`.

***

## Campaigns, ad sets and ads

| Method | Endpoint | Description |
| - | - | - |
| GET | `/v1/connect/meta-ads/campaigns` | List campaigns (`?limit=` up to 500, default 50) |
| POST | `/v1/connect/meta-ads/campaigns` | Create a campaign |
| PATCH | `/v1/connect/meta-ads/campaigns/:campaignId` | Change status or daily/lifetime budget |
| DELETE | `/v1/connect/meta-ads/campaigns/:campaignId` | Delete a campaign |
| GET | `/v1/connect/meta-ads/adsets` | List ad sets (`?campaignId=` optional) |
| POST | `/v1/connect/meta-ads/adsets` | Create an ad set under a campaign |
| PATCH | `/v1/connect/meta-ads/adsets/:adSetId` | Change status or daily/lifetime budget |
| DELETE | `/v1/connect/meta-ads/adsets/:adSetId` | Delete an ad set |
| GET | `/v1/connect/meta-ads/ads` | List ads (`?campaignId=`, `?adsetId=` optional) |
| POST | `/v1/connect/meta-ads/ads` | Create an ad in an ad set |
| PATCH | `/v1/connect/meta-ads/ads/:adId` | Change status |
| DELETE | `/v1/connect/meta-ads/ads/:adId` | Delete an ad |
| POST | `/v1/connect/meta-ads/standalone` | Create campaign + ad set + ad in one call |

List endpoints paginate with `?after=`. Create and list endpoints also work under `/v1/connect/meta-ads/ad-accounts/:adAccountId/...` when you want to name the ad account in the path.

### Create a campaign

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
POST /v1/connect/meta-ads/campaigns
{
  "adAccountId": "act_123456789",
  "name": "Dibble - US installs",
  "objective": "OUTCOME_APP_PROMOTION",
  "status": "PAUSED",
  "dailyBudgetMinor": 5000
}
```

| Field | Required | Notes |
| - | - | - |
| `name` | Recommended | Campaign name |
| `objective` | No | Meta objective. Default `OUTCOME_TRAFFIC` |
| `status` | No | `ACTIVE` or `PAUSED` (default) |
| `dailyBudgetMinor` / `lifetimeBudgetMinor` | No | Campaign budget. Leave both out to set budgets on ad sets |
| `isAdSetBudgetSharingEnabled` | No | Required by Meta when the campaign has no campaign budget |
| `specialAdCategories` | No | Comma-separated list. Empty means none |
| `bidStrategy`, `buyingType`, `spendCapMinor` | No | Passed to Meta as-is |

### Create an ad set

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
POST /v1/connect/meta-ads/adsets
{
  "campaignId": "120200000000000001",
  "name": "US 18-34",
  "dailyBudgetMinor": 2000,
  "targeting": { "geo_locations": { "countries": ["US"] }, "age_min": 18, "age_max": 34 },
  "optimizationGoal": "LINK_CLICKS",
  "billingEvent": "IMPRESSIONS"
}
```

`name`, `campaignId` and `targeting` are required. `dailyBudgetMinor` must be greater than zero unless you also send the first ad's copy (`existingCreativeId`, or `headline` + `body` + `imageUrl`/`linkUrl`). Optional: `destinationType`, `promotedObject`, `startTime`, `endTime`, `bidStrategy`, `bidAmountMinor`, `pageId`, `instagramUserId`.

### Create an ad

`name` and `adSetId` are required. Pass `creativeId` to reuse a creative, or `headline`, `body`, `imageUrl`, `linkUrl` and `callToAction` to create the ad from copy.

### One-call campaign

`POST /v1/connect/meta-ads/standalone` creates a campaign, ad set and ad together. Only `name` is required.

| Field | Notes |
| - | - |
| `goal` | `traffic` (default), `conversions`, `lead_generation`, `lead_conversion`, `app_promotion`, `awareness`, `engagement`, `video_views`, `catalog_sales`, `page_likes` |
| `dailyBudgetMinor` / `lifetimeBudgetMinor` | Budget in minor units |
| `budgetLevel` | `adset` (default) or `campaign` |
| `headline`, `body`, `description`, `linkUrl`, `imageUrl`, `callToAction` | Ad copy and media |
| `countries`, `ageMin`, `ageMax`, `gender`, `interests`, `audienceId` | Simple targeting (`interests` come from targeting search) |
| `existingCampaignId` / `adSetId` | Add to an existing campaign or ad set instead of creating one |
| `existingCreativeId` | Reuse a creative |
| `promotedObject` | Pixel and event for `conversions`; app id and store URL for `app_promotion` |
| `leadGenFormId` | Instant form for `lead_generation` |
| `validateOnly` | `true` to check the request with Meta without creating anything |

### Update and pause

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
PATCH /v1/connect/meta-ads/campaigns/120200000000000001
{ "status": "ACTIVE", "dailyBudgetMinor": 8000 }
```

Campaigns and ad sets accept `status`, `dailyBudgetMinor` and `lifetimeBudgetMinor`. Ads accept `status` only. `status` is `ACTIVE` or `PAUSED`.

***

## App-install ads

`POST /v1/connect/meta-ads/app-install-drafts` builds a complete app-install ad in one call: an app promotion campaign, an ad set, an install creative and the ad. The draft is paused by default.

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
POST /v1/connect/meta-ads/app-install-drafts
{
  "storeAppId": "123456789",
  "platform": "apple",
  "country": "US",
  "dailyBudgetMinor": 3000,
  "message": "Build tiny routines without overwhelm.",
  "headline": "Dibble - habit tracker",
  "pictureUrl": "https://example.com/ad-image.png",
  "instagramUserId": "17841400000000000"
}
```

| Field | Required | Notes |
| - | - | - |
| `dailyBudgetMinor` | Yes | Greater than zero |
| `message` | Yes | Primary text |
| `headline` | Yes | Ad headline |
| `applicationId`, `storeAppId` or `objectStoreUrl` | One of them | `storeAppId` is the App Store id or Google Play package; pair it with `platform` (`apple` or `google`) |
| `pageId` / `instagramUserId` | No | With only an Instagram professional account, the ad runs on Instagram only |
| `imageHash` / `pictureUrl` | No | Ad image |
| `country` | No | Used for default targeting and the store URL |
| `targeting`, `optimizationGoal`, `billingEvent`, `destinationType`, `bidStrategy` | No | Defaults: `APP_INSTALLS`, `IMPRESSIONS`, `APP`, `LOWEST_COST_WITHOUT_CAP` |
| `status` | No | `ACTIVE` or `PAUSED` (default) |

Your app must be registered with Meta and advertisable from the ad account. With a direct login, `GET /v1/connect/meta-ads/advertisable-applications` lists the apps you can promote.

***

## Creatives and images

Available with a direct Meta login.

| Method | Endpoint | Description |
| - | - | - |
| POST | `/v1/connect/meta-ads/adimages/from-url` | Upload an image by public URL (`imageUrl`) and get its image hash |
| POST | `/v1/connect/meta-ads/creatives` | Create a creative |
| GET | `/v1/connect/meta-ads/creatives` | List creatives |
| GET | `/v1/connect/meta-ads/creatives/:creativeId` | Get one creative |
| GET | `/v1/connect/meta-ads/advertisable-applications` | Apps this ad account can promote |

A creative needs `name`, `linkUrl`, `message` and `headline`. `format` is `link` (default, needs `pageId`) or `app_install` (can use `instagramUserId` instead of a Page). Optional: `description`, `callToActionType` (default `LEARN_MORE`), `imageHash` or `pictureUrl`, `urlTags`.

***

## Audiences, targeting and lead forms

Available with a partner connection.

| Method | Endpoint | Description |
| - | - | - |
| GET | `/v1/connect/meta-ads/targeting/search` | Find interest ids or locations (`?q=`, `?dimension=interest` or `geo`, `?limit=` up to 100) |
| GET | `/v1/connect/meta-ads/audiences` | List audiences (`?type=` optional) |
| POST | `/v1/connect/meta-ads/audiences` | Create an audience |
| POST | `/v1/connect/meta-ads/audiences/:audienceId/users` | Add customers to a customer list audience |
| DELETE | `/v1/connect/meta-ads/audiences/:audienceId` | Delete an audience |
| GET | `/v1/connect/meta-ads/lead-forms` | List Instant forms |
| POST | `/v1/connect/meta-ads/lead-forms` | Create an Instant form |
| GET | `/v1/connect/meta-ads/lead-forms/:formId/leads` | Leads submitted to a form (`?limit=` up to 200, default 50) |

**Audiences.** `name` and `type` are required. Types: `customer_list`, `website` (needs `pixelId`), `lookalike` (`sourceAudienceId`, `country`, `ratio` such as `0.01` for 1%) and `meta_engagement` (`engagementSource` of `page`, `instagram` or `video`, plus `sourceId` and `retentionDays`). For a customer list, send `users` as an array of `{ "email": "...", "phone": "..." }`.

**Instant forms.** Send `name`, `privacyPolicyUrl` and optional `questions` such as `[{ "type": "EMAIL" }, { "type": "FULL_NAME" }]`. Then create a one-call campaign with `goal: "lead_generation"` and the form's id as `leadGenFormId`.

### Boost a post

`POST /v1/connect/meta-ads/boost` promotes an existing Facebook or Instagram post as an ad.

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
POST /v1/connect/meta-ads/boost
{
  "postId": "post-id",
  "name": "Boost launch post",
  "goal": "traffic",
  "budget": { "amount": 40, "type": "daily" },
  "schedule": { "startDate": "2026-11-03", "endDate": "2026-11-10" },
  "targeting": { "countries": ["US"], "age_min": 18 }
}
```

`postId` is required. `goal` defaults to `traffic`; `budget.amount` is in whole currency units (`40` = 40.00) and `budget.type` defaults to `daily`.

***

## Insights

`GET /v1/connect/meta-ads/insights` returns spend, impressions, reach, clicks, CTR, CPC, CPM, actions and cost per action.

| Query | Notes |
| - | - |
| `targetType` | `ad_account` (default), `campaign`, `adset` or `ad` |
| `targetId` | Id of the target. Optional for `ad_account`; your default ad account is used |
| `level` | Break rows down by `account`, `campaign`, `adset` or `ad` |
| `datePreset` | Meta date preset, e.g. `last_7d`, `last_30d` |
| `since` / `until` | `YYYY-MM-DD`. Together they override `datePreset` |
| `breakdowns`, `fields` | Comma-separated Meta breakdowns and fields |
| `limit` / `after` | Up to 500 rows per page, default 100 |

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl "https://api.appeeky.com/v1/connect/meta-ads/insights?targetType=ad_account&level=campaign&datePreset=last_7d" \
  -H "X-API-Key: $APPEEKY_API_KEY"
```

***

## Meta Ad Library

Look up public ads that any advertiser runs on Facebook, Instagram, Messenger, Audience Network and Threads. No Meta connection needed.

| Method | Endpoint | Description |
| - | - | - |
| GET | `/v1/ads/meta/search` | Search ads by keyword or Page id |
| GET | `/v1/ads/meta/pages/:pageId/ads` | Ads from one Facebook Page |
| GET | `/v1/apps/:id/ad-intelligence` | Find the Meta ads for an App Store or Google Play app |

| Query | Notes |
| - | - |
| `q` | Search terms. `q` or `pageIds` is required for search |
| `pageIds` | Comma-separated Page ids, up to 10 |
| `countries` | Comma-separated reached countries, or `ALL` (default) |
| `status` | `ACTIVE` (default), `INACTIVE` or `ALL` |
| `mediaType` | `ALL`, `IMAGE`, `MEME`, `VIDEO` or `NONE` |
| `platforms` | `FACEBOOK`, `INSTAGRAM`, `MESSENGER`, `AUDIENCE_NETWORK`, `THREADS` |
| `startDate` / `endDate` | Delivery dates, `YYYY-MM-DD` |
| `limit` / `after` | Up to 100 ads, default 25 |

Each ad includes the library id, Page name, creative text, snapshot and preview URLs, delivery dates and platforms.

**App ad intelligence.** `GET /v1/apps/:id/ad-intelligence` takes an App Store id or Google Play package (`?platform=apple` or `google`) and finds the advertiser's Page for you. Use `?adCountries=` to choose where ads ran. The response adds a `summary`: total and active ads, Pages, platform counts, first and latest seen dates and sample ad texts. Pass `pageIds` if you already know the Page.

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl "https://api.appeeky.com/v1/apps/123456789/ad-intelligence?platform=apple&adCountries=US&status=ACTIVE" \
  -H "X-API-Key: $APPEEKY_API_KEY"
```

***

## Launch Tests

To test demand for an app idea, create a paused Meta campaign for a Launch Test (**Launch Tests** in the dashboard) with `POST /v1/validation-experiments/:id/meta-ad-draft`. It builds the campaign, ad set, link creative and ad, and points the ad to the hosted Launch Test page unless you pass `landingUrl`. `pageId` and `dailyBudgetMinor` are required.

***

## MCP tools

| Tool | Description |
| - | - |
| `meta_ads_oauth_start` | Get the Meta connect link |
| `meta_ads_credentials_status` | Check whether Meta Ads is connected |
| `meta_ads_list_ad_accounts` | List ad accounts |
| `meta_ads_set_default_ad_account` | Set the default ad account |
| `meta_ads_list_pages` | List Facebook Pages |
| `meta_ads_list_publisher_identities` | Pages and linked Instagram accounts |
| `meta_ads_list_advertisable_applications` | Apps the ad account can promote |
| `meta_ads_list_campaigns` / `meta_ads_create_campaign` | List or create campaigns |
| `meta_ads_update_campaign` / `meta_ads_delete_campaign` | Pause, activate, change budget, delete |
| `meta_ads_list_adsets` / `meta_ads_create_adset` | List or create ad sets |
| `meta_ads_update_adset` / `meta_ads_delete_adset` | Pause, activate, change budget, delete |
| `meta_ads_list_ads` / `meta_ads_create_ad` | List or create ads |
| `meta_ads_update_ad` / `meta_ads_delete_ad` | Pause, activate, delete |
| `meta_ads_create_standalone` | Campaign + ad set + ad in one call |
| `meta_ads_create_app_install_draft` | Paused app-install campaign end to end |
| `meta_ads_create_creative` / `meta_ads_list_creatives` / `meta_ads_get_creative` | Manage creatives |
| `meta_ads_upload_ad_image_from_url` | Upload an image and get its hash |
| `meta_ads_insights` | Spend and results |
| `meta_ads_search_targeting` | Find interests and locations |
| `meta_ads_list_audiences` / `meta_ads_create_audience` | List or create audiences |
| `meta_ads_add_audience_users` / `meta_ads_delete_audience` | Fill or delete an audience |
| `meta_ads_boost_post` | Promote an existing post |
| `meta_ads_list_lead_forms` / `meta_ads_create_lead_form` / `meta_ads_list_lead_form_leads` | Instant forms and leads |
| `meta_ads_search` | Search the Meta Ad Library |
| `meta_ads_page_ads` | Ad Library ads for one Page |
| `meta_app_ad_intelligence` | Meta ads for an App Store or Google Play app |
| `launch_test_create_meta_ad_draft` | Paused Meta campaign for a Launch Test |

***

## Credits

| Request | Cost |
| - | - |
| Connect, status, ad account selection and default | Free |
| Other `/connect/meta-ads` reads and writes | 2 credits per request |
| Meta Ad Library search, Page ads and app ad intelligence | 1 credit per request |
| Launch Test Meta draft | Free |

Requests made from the Appeeky dashboard don't use API credits. Ad spend is billed by Meta to your ad account.

***

## Common errors

| Code | Meaning |
| - | - |
| `PRO_FEATURE` | Ads integrations need the Indie plan or higher |
| `META_ADS_CONNECTION_REQUIRED` | Connect Meta Ads first |
| `META_ADS_TOKEN_EXPIRED` | Your Meta login expired. Reconnect Meta Ads |
| `META_AD_ACCOUNT_REQUIRED` | Pass `adAccountId` or set a default ad account |
| `META_STATUS_INVALID` | `status` must be `ACTIVE` or `PAUSED` |
| `META_AD_LIBRARY_QUERY_REQUIRED` | Ad Library search needs `q` or `pageIds` |
| HTTP `501` | This action isn't available for your connection type |

***

## Related

* [TikTok Ads](https://docs.appeeky.com/docs/tiktok-ads.md) — campaigns and performance on TikTok
* [Apple Search Ads](https://docs.appeeky.com/docs/apple-search-ads.md) — App Store search campaigns
* [Ad signals](https://docs.appeeky.com/docs/analytics-ad-signals.md) — send app conversions back to Meta


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.