---
title: meta_create_adset
description: Create a Meta ad set under a campaign, with its audience and its optimization goal. It always arrives paused.
---

Ask for an ad set under a campaign: the countries, the ages, what delivery optimizes for, and how Meta bids if you want to choose. AdCrunch creates it paused.

> Add an ad set to Spring Prospecting that targets France and Belgium, ages 25 to 54, and optimizes for purchases on the Northwind Web Pixel.

The agent calls `meta_create_adset`, then [`get_mutation_status`](/mcp/tools/get-mutation-status), and you see the id of the new paused ad set. [Change what runs on Meta](/mcp/tools/change-what-runs-on-meta) walks the whole campaign.

## Reference

**Available on:** [![Meta](/providers/meta.svg)](https://docs.adcrunch.dev/connect/providers)

Create an ad set under a Meta campaign on a live ad account. It is always created PAUSED and cannot be created active. Targeting is countries, an age range, and gender — placements are left to Meta's automatic default. Whether a budget is required depends on the parent campaign: if it uses Advantage campaign budget, the ad set must NOT carry one; otherwise it must carry exactly one. Optionally set how Meta bids: `bidStrategy`, with the one amount it takes (`bidCap`, `costCap` or `roasFloor`). Under a campaign that holds the bid strategy, give the same strategy, with the amount for this ad set. Give `pixelId` and `customEventType` when the optimization goal optimizes toward conversions (find a pixel with `meta_list_pixels`). Runs asynchronously: returns a `workflowId` — call `get_mutation_status` with it to get the new ad set's `id`.

### Input

| Argument | Type | Required | Description |
| --- | --- | --- | --- |
| `advertiserId` | string | yes | Advertiser account ID (`acc_<id>`). Must belong to the active organization. |
| `ageMax` | integer, 13 to 65 | no | Oldest age to target. Omit for no upper bound (Meta treats 65 as 65+). |
| `bidCap` | number, more than 0 | no | The highest bid Meta places in an auction. Only with LOWEST_COST_WITH_BID_CAP. A bid is per optimization event, for example per purchase, and per 1,000 impressions when the optimization goal is IMPRESSIONS or REACH. The amount is in whole units of the ad account currency: 2.5 is 2.50. Meta refuses more decimals than the currency has. |
| `costCap` | number, more than 0 | no | The average cost per result that Meta tries to keep. Only with COST_CAP. A bid is per optimization event, for example per purchase, and per 1,000 impressions when the optimization goal is IMPRESSIONS or REACH. The amount is in whole units of the ad account currency: 2.5 is 2.50. Meta refuses more decimals than the currency has. A cost cap can stop the ad set before it spends its full budget. |
| `roasFloor` | number, 0.01 to 1000 | no | The lowest return on ad spend that Meta bids for, as a ratio: 1.5 means purchase value of 1.5 times the spend. Only with LOWEST_COST_WITH_MIN_ROAS. From 0.01 to 1000, with at most 4 decimals. |
| `bidStrategy` | one of `LOWEST_COST_WITHOUT_CAP`, `LOWEST_COST_WITH_BID_CAP`, `COST_CAP`, `LOWEST_COST_WITH_MIN_ROAS` | no | How Meta bids. LOWEST_COST_WITHOUT_CAP ("Highest volume" in Ads Manager) gets the most results for the budget and takes no amount. LOWEST_COST_WITH_BID_CAP ("Bid cap") takes bidCap. COST_CAP ("Cost per result goal") takes costCap. LOWEST_COST_WITH_MIN_ROAS ("ROAS goal") takes roasFloor, and needs the optimization goal VALUE. Give exactly the amount that the strategy takes, and no other amount. A higher bid cap, a higher cost cap or a lower ROAS floor can make an ad set spend its full budget, never more. When the campaign carries the budget, or shares the ad set budgets, the campaign holds the strategy: give the same bidStrategy here, with the amount for this ad set. Omit it, with every amount, to let Meta apply its default strategy. |
| `ageMin` | integer, 13 to 65 | yes | Youngest age to target. Required, not defaulted: many advertisers are obliged to exclude under-18s, and that is not a decision to make on their behalf. Ask the user if you do not know. |
| `campaignId` | string | yes | The Meta ID of the parent campaign, digits only — including one you created moments ago, which is fine. |
| `countries` | array of (string, 2 characters), at least 1 item | yes | Two-letter ISO country codes to target, e.g. ["US", "CA"]. |
| `customEventType` | one of `PURCHASE`, `LEAD`, `COMPLETE_REGISTRATION`, `ADD_TO_CART`, `INITIATED_CHECKOUT`, `ADD_PAYMENT_INFO`, `VIEW_CONTENT`, `SEARCH`, `SUBSCRIBE`, `START_TRIAL`, `CONTACT`, `OTHER` | no | Which pixel event to optimize toward, e.g. `PURCHASE`. Required together with `pixelId` for a conversion-optimizing goal. |
| `dailyBudget` | number, more than 0 | no | Daily budget in whole units of the ad account currency (10.5 is 10.50). Provide this or `lifetimeBudget`, not both — and neither if the parent campaign uses Advantage campaign budget. |
| `endTime` | string | no | When delivery should stop, ISO 8601. Required when using `lifetimeBudget`. |
| `genders` | one of `all`, `men`, `women` | no | Who to target. Defaults to everyone. Default: `all`. |
| `lifetimeBudget` | number, more than 0 | no | Lifetime budget in whole units of the ad account currency (10.5 is 10.50). Requires `endTime`. Provide this or `dailyBudget`, not both — and neither if the parent campaign uses Advantage campaign budget. |
| `name` | string, at least 1 character | yes | Ad set name, as it will appear in Ads Manager. |
| `optimizationGoal` | one of `IMPRESSIONS`, `REACH`, `LINK_CLICKS`, `LANDING_PAGE_VIEWS`, `OFFSITE_CONVERSIONS`, `POST_ENGAGEMENT`, `THRUPLAY`, `LEAD_GENERATION`, `VALUE` | yes | What delivery optimizes for. This is a real media-buying decision on the user's money — `LINK_CLICKS` buys clicks, `LANDING_PAGE_VIEWS` buys arrivals, `OFFSITE_CONVERSIONS` buys conversions and needs a pixel. Meta decides which goals are legal under the parent campaign's objective, and will say so if the pairing is not. |
| `pixelId` | string | no | The Meta Pixel to attribute conversions to. Required together with `customEventType` for a conversion-optimizing goal — find one with `meta_list_pixels`. |
| `startTime` | string | no | When delivery should start, ISO 8601. Omit to start as soon as the ad set is activated. |

### Output

A successful call returns this object in `structuredContent`.

| Field | Type | Always present | Description |
| --- | --- | --- | --- |
| `workflowId` | string | yes | The id of the change. The change has not reached Meta yet. Give this id to `get_mutation_status` to find out how the change ended. |

### Failure codes

A failed call has `isError` set, and `structuredContent.error` holds one of these codes. [Errors](/mcp/errors) describes the shape of a failed call.

- `not_found`
- `provider_not_connected`
- `missing_write_access`
- `forbidden`
- `invalid_request`
- `internal_error`

### Scope

The token must hold `mutation:write`. [Auth & scopes](/mcp/auth) lists each scope.

### Annotations

A client reads these hints. A hint that the tool does not declare has the default value of the MCP specification.

- **Writes.** The tool can change data.
- **Destructive.** The tool can make a change that you cannot undo. A client can ask you to confirm before it calls the tool.
- **Not idempotent.** A second call with the same arguments can change more.
- **Open world.** The tool reaches a system outside AdCrunch, such as an ad platform.

### Example

The arguments:

```json
{
  "advertiserId": "acc_1485443900032333",
  "ageMax": 54,
  "ageMin": 25,
  "campaignId": "120215678901234567",
  "countries": [
    "FR",
    "BE"
  ],
  "customEventType": "PURCHASE",
  "name": "FR BE 25-54 Purchases",
  "optimizationGoal": "OFFSITE_CONVERSIONS",
  "pixelId": "812345678901234"
}
```

The result, in `structuredContent`:

```json
{
  "workflowId": "3f9c2b7e-8a41-4d6e-9b05-c1e7a2d4f860"
}
```
