---
title: meta_create_adset
description: Create a Meta ad set under a campaign — budget, audience, and optimization goal.
---

The ad set is where the money actually gets configured: what you're willing to spend, who you're reaching, and what delivery optimizes for.

:::warning[Nothing spends until you say so]

Created **PAUSED**, always. There is no `status` input at any layer. Activate with `meta_set_status` once you've reviewed it.

:::

## Input

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `advertiserId` | `acc_*` | yes | The Meta advertiser. |
| `campaignId` | `string` | yes | Parent campaign — including one created moments ago. |
| `name` | `string` | yes | Ad set name. |
| `optimizationGoal` | enum | yes | What delivery optimizes for. |
| `countries` | `string[]` | yes | Two-letter ISO codes, e.g. `["US", "CA"]`. |
| `ageMin` | `13`–`65` | yes | Youngest age to target. **Not defaulted** — see below. |
| `ageMax` | `13`–`65` | no | Oldest age. Omit for no upper bound. |
| `genders` | `all \| men \| women` | no | Defaults to everyone. |
| `dailyBudget` | `integer` | \* | Minor currency units (cents). |
| `lifetimeBudget` | `integer` | \* | Requires `endTime`. |
| `startTime` | ISO 8601 | no | When delivery starts. |
| `endTime` | ISO 8601 | no | When delivery stops. Required with `lifetimeBudget`. |
| `pixelId` | `string` | \*\* | From `meta_list_pixels`. |
| `customEventType` | enum | \*\* | The pixel event to optimize toward, e.g. `PURCHASE`. |

\* **Whether a budget is required depends on the parent campaign.** If it uses Advantage campaign budget, the ad set must carry **none**; otherwise it must carry exactly one. AdCrunch reads the campaign to find out and tells you which case you're in, rather than guessing.

\*\* **Required together** when the optimization goal optimizes toward conversions (`OFFSITE_CONVERSIONS`, `VALUE`). This is checked before anything is created — it's Meta's most common create rejection.

:::info[Why ageMin is required]

Many advertisers are legally obliged to exclude under-18s. Defaulting to Meta's floor would make that decision on the user's behalf, in the one direction they cannot undo once money has been spent. Ask.

:::

## What is not exposed

`billingEvent` is **derived** from the optimization goal — it's `IMPRESSIONS` in nearly every real ad set, so exposing it would only add a way to be wrong. Interests, behaviours, cities and radius targeting are not available: each would need its own lookup tool before an agent could use it. Placements are left to Meta's automatic default. Custom audiences are the named next addition.

## Output

`{ workflowId }`. Poll `get_mutation_status` for the new ad set's `{ id }`.

## Errors

- A conversion goal with no pixel, or a lifetime budget with no end time — both refused before anything is created, with a message saying what to fix.
- A budget on a CBO campaign, or none on a non-CBO one — refused with the same message `meta_update_budget` gives for the same disagreement.
- An objective/goal pairing Meta doesn't allow comes back in **Meta's own words**, including its error subcode. AdCrunch deliberately doesn't second-guess that matrix.
- `401` or `403` — see [Errors](/mcp/errors), which every tool shares. This one needs `mutation:write`.
