---
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, the interests and the job titles, the Custom Audiences to include or to exclude, whether Meta can reach people outside your targeting (Advantage+ audience), what delivery optimizes for, and how Meta bids if you want to choose. An ad set can optimize for a standard event or for a custom conversion. AdCrunch creates it paused.

> Add an ad set to Spring Prospecting that targets France and Belgium, ages 25 to 54 without Advantage+ audience, 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. For interests and job titles, the agent first finds their ids with [`meta_search_targeting`](/mcp/tools/meta-search-targeting). [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, gender, interests and job titles (`interests`, `workPositions`), and Custom Audiences to include or to exclude — placements are left to Meta's automatic default. Find the id of an interest or a job title with `meta_search_targeting`. `advantageAudience` is required. Its description gives the age rules that go with it. Ask the user when you do not know. 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`). To optimize for a custom conversion, give `customConversionId` in place of `customEventType` (find one with `meta_list_custom_conversions`). Runs asynchronously: returns a `mutationId` — call `get_mutation_status` with it to get the new ad set's `id`.

### Input

| Argument | Type | Required | Description |
| --- | --- | --- | --- |
| `advantageAudience` | boolean | yes | Whether Meta can show the ads to people outside the targeting (Advantage+ audience). This field is required. It has no default. With true, Meta uses the gender, the interests, the job titles and the included Custom Audiences as a suggestion. Meta can then deliver to other genders and to older people when it expects better results. The countries and the minimum age stay hard limits. With true, ageMin must be 25 or less. With true, Meta fixes the oldest age at 65, so ageMax is not allowed. With false, Meta delivers only to the targeting. Ask the user when you do not know. |
| `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+). Omit it when `advantageAudience` is true. |
| `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"]. |
| `customAudiences` | array of string | no | The Meta ids of the Custom Audiences to target, digits only. Meta then delivers only to people in one of these audiences or more. With interests or job titles too, a person must also match one of them. Use the id of a Custom Audience of this ad account. With advantageAudience true, Meta uses these audiences as a suggestion. |
| `excludedCustomAudiences` | array of string | no | The Meta ids of the Custom Audiences to exclude, digits only. Meta does not deliver to a person in one of these audiences, also with advantageAudience true. For example, exclude your customers from an ad set that finds new ones. |
| `interests` | array of string | no | The Meta ids of the interests to target, digits only. Find them with the targeting search of AdCrunch, with type interest. Send the id, not the name: Meta can rename an interest. The interests and the workPositions make one group. Meta delivers to a person who matches one of them or more. No interest can be excluded. With advantageAudience true, Meta uses the group as a suggestion. Meta refuses an interest that it removed or merged, in its own words. |
| `workPositions` | array of string | no | The Meta ids of the job titles to target, digits only. Find them with the targeting search of AdCrunch, with type work_position. Send the id, not the name: Meta can rename a job title. The job titles and the interests make one group. Meta delivers to a person who matches one of them or more. With advantageAudience true, Meta uses the group as a suggestion. |
| `customConversionId` | string | no | The Meta id of the custom conversion to optimize for, digits only. Find it with the custom conversions read of AdCrunch, and choose one that is usable. Send it in place of customEventType, with the pixelId of the custom conversion. The custom conversion gives the event, so do not send customEventType with it. |
| `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`. A conversion-optimizing goal needs `pixelId`, with this or `customConversionId`. |
| `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 with `customEventType` or `customConversionId` 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 |
| --- | --- | --- | --- |
| `consoleUrl` | string | yes | The page of this change in the AdCrunch console. When `get_mutation_status` reports `awaiting_confirmation`, give this URL to the user: a person must confirm the change there before it reaches Meta. You cannot confirm it. |
| `mutationId` | 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`
- `organization_unentitled`
- `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
{
  "advantageAudience": false,
  "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
{
  "consoleUrl": "https://console.adcrunch.dev/activity/mut_k3x9q2v7m4n8p1r5t6w0y2z4",
  "mutationId": "mut_k3x9q2v7m4n8p1r5t6w0y2z4"
}
```
