---
title: Change what runs on Meta
description: Build a paused campaign on a Meta advertiser, then start it, stop it, or change its budget, from a conversation. Each change runs in the background, and nothing spends until you activate it.
---

You ask the agent to build or change a campaign on one of your Meta advertisers. AdCrunch sends the change to Meta. Each change runs in the background, and each create arrives paused.

## Before you start

- Connect Meta with write access, and share a Facebook Page when Meta asks for assets. [Connect Meta](/connect/meta) shows the steps.
- To make a change, the token of your client must hold `mutation:write`. The two reads of this job, the Pages and the Pixels, need `observe:read` only. So you can plan on a token that cannot change anything. [Auth & scopes](/mcp/auth) lists each scope.
- The agent finds the advertiser with [`list_advertisers`](/mcp/tools/list-advertisers).

## How a change runs

Six tools make a change on Meta: [`meta_create_campaign`](/mcp/tools/meta-create-campaign), [`meta_create_adset`](/mcp/tools/meta-create-adset), [`meta_create_creative`](/mcp/tools/meta-create-creative), [`meta_create_ad`](/mcp/tools/meta-create-ad), [`meta_set_status`](/mcp/tools/meta-set-status) and [`meta_update_budget`](/mcp/tools/meta-update-budget). Each one works in two steps.

1. **The tool starts the change.** First it checks the scope of the token, the arguments, the advertiser and the write access. When one check fails, the call fails at once, and nothing starts. When all checks pass, the tool answers a `workflowId`. At that time, the change has not reached Meta.
2. **[`get_mutation_status`](/mcp/tools/get-mutation-status) reports the outcome.** The agent gives it the `workflowId`, and it answers one of three states.

| State | What it means | What the agent does |
| --- | --- | --- |
| `running` | The change has not ended. | It asks again. |
| `complete` | The change ended. `result` tells how. | It reads `result`. |
| `errored` | The run itself stopped. AdCrunch cannot tell whether Meta applied the change. | It tells you. Look at the object in Meta Ads Manager before you ask for the change again. |

`complete` does not always mean that Meta applied the change. When `result.ok` is true, Meta applied it. A create then gives the Meta id of the new object, and a change of status or of budget gives `success`. When `result.ok` is false, the change did not apply, and `result.error` holds the code:

| `result.error` | Why the change did not apply |
| --- | --- |
| `budget_cap_exceeded` | The budget is above the safety cap. |
| `wrong_level` | The budget is on the wrong level of the campaign. The message tells which level holds the budget. |
| `invalid_request` | A rule of AdCrunch refused the change before it reached Meta. The message names the rule. |
| `provider_error` | Meta refused the change. The message holds the words of Meta. |
| `missing_write_access` | The Meta connection lost its write access after the change started. Connect Meta again. |
| `not_found` | The advertiser left your organization after the change started. |

A refused change is a finished change, so the agent does not send it again by itself. It tells you the reason, and you decide what to change. [Errors](/mcp/errors) describes the failure of a tool call.

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

Each create arrives paused: the campaign, the ad set and the ad. No tool can create an active object. Meta delivers an ad only when the ad, its ad set and its campaign are all active. So spend starts only when you ask the agent to activate all three.

:::

## Build a campaign

### 1. Find the Page and the Pixel

> Which Facebook Page and which Pixel can my Northwind advertiser use?

The agent calls [`meta_list_pages`](/mcp/tools/meta-list-pages) and [`meta_list_pixels`](/mcp/tools/meta-list-pixels), and it asks you which ones to use. Each ad speaks from a Page. An ad set that optimizes for conversions needs a Pixel.

The list of Pages comes from your Meta connection, so it is the same for each advertiser of that connection. Each list holds 100 rows at most. An empty list of Pages means that you shared no Page when you connected Meta. Connect Meta again and share a Page. Prefer a Pixel that received an event recently. A Pixel that never received an event is usually absent from your site.

### 2. Create the campaign

> Create a sales campaign called Spring Prospecting on Northwind, with a daily budget of 50 euros.

The agent calls [`meta_create_campaign`](/mcp/tools/meta-create-campaign), then `get_mutation_status`, and it gives you the id of the new campaign. The campaign is paused.

A budget is in whole units of the account currency: 50 is 50.00 euros, and 10.5 is 10.50. A budget on the campaign turns on Advantage campaign budget, so Meta shares that budget across the ad sets. If the campaign is about employment, housing, credit, politics, gambling or financial products, Meta requires you to declare that category. The agent must ask you, and not guess.

### 3. Create the ad set

> 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`](/mcp/tools/meta-create-adset). The campaign holds the budget, so the ad set holds none. The ad set is paused.

The agent asks you for the youngest age to target, because many advertisers must exclude people under 18. A goal that optimizes for conversions needs a Pixel and an event. Without both, AdCrunch refuses the change with `invalid_request`. Meta decides which goals each objective allows, and Meta gives its refusal in its own words.

### 4. Create the creative

> Make a creative from the spring trail image, from the Northwind Outdoor Page, with a Shop now button to example.com/spring.

The agent calls [`meta_create_creative`](/mcp/tools/meta-create-creative). First, you upload the image or the video to AdCrunch as an asset, and the agent registers the asset to this advertiser with [`asset_register`](/mcp/tools/asset-register). For an asset that has no registration to this advertiser, AdCrunch refuses the change with `invalid_request`, and the message tells the next step. The kind of the asset decides the format of the creative. For a video that you uploaded a short time ago, the change waits until Meta finishes the processing. If the processing does not finish in that time, AdCrunch refuses the change with `invalid_request`, and you can ask again later.

### 5. Create the ad

> Put that creative in the new ad set.

The agent calls [`meta_create_ad`](/mcp/tools/meta-create-ad) with the id of the ad set and the id of the creative. The ad is paused. An ad can also use a creative that already runs in another ad.

### 6. Review and activate

> Activate Spring Prospecting, its ad set and its ad.

The agent calls [`meta_set_status`](/mcp/tools/meta-set-status) with `ACTIVE` on each of the three. When all three are active, Meta starts delivery, and spend starts.

The id that `get_mutation_status` gives is the handle of each new object. AdCrunch refreshes its stored copy in the background, so a new object can be absent from [`list_entities`](/mcp/tools/list-entities) for a short time.

## Change what already runs

> Pause the FR BE 25-54 ad set.

The agent calls [`meta_set_status`](/mcp/tools/meta-set-status) with `PAUSED`. `ACTIVE` starts delivery again.

> Raise the daily budget of Spring Prospecting to 150 euros.

The agent calls [`meta_update_budget`](/mcp/tools/meta-update-budget). AdCrunch reads the object on Meta to find where the budget is. With Advantage campaign budget, the campaign holds the budget. Otherwise, each ad set holds its own budget. For a change on the wrong level, AdCrunch refuses the change with `wrong_level`, and the message tells which level to use.

## Guardrails

- **A create arrives paused.** No tool, and no argument, creates an active object.
- **No tool deletes.** `ARCHIVED` retires an object, and it is almost permanent: an archived object cannot deliver again. Use it only for an object that must not exist, such as a duplicate. To stop delivery, use `PAUSED`.
- **AdCrunch does not deduplicate a create.** If you ask for the same create two times, you get two objects. Wait for the outcome before you ask again.
- **A budget has a safety cap.** Above the cap, AdCrunch refuses the change with `budget_cap_exceeded`, and the message gives the cap in the account currency. The cap is 1,000,000 in a currency with cents, such as EUR or USD. It applies to a new campaign, a new ad set and a budget change.
- **A budget is exact.** A budget has no more decimals than Meta counts in the account currency. AdCrunch refuses an amount with more decimals, and never rounds it.
- **The record keeps only the new budget.** If you may want to put a budget back, ask the agent to read the current value first.
- **The console records each change.** Its Activity page lists each change, the advertiser, the person who asked, and the outcome.
- **The same rules for each tool.** [What to expect](/mcp/what-to-expect) states how a change is queued and then confirmed, and why a create arrives paused.
