---
title: campaign_plan_approve
description: 'Approve a plan, validating every draft line on it and opening the execution gate.'
---

Approves a **Campaign Plan**. This is the human act in the plan's lifecycle — and the gate a Line Item must pass before it can be executed.

:::warning[A Campaign Plan is not a provider campaign]

It is AdCrunch's own planning document — written before anything is bought, and possibly executed into several campaigns, or none. For campaigns that exist on Meta or Google, use [`list_entities`](/mcp/tools/list-entities) and [`get_entity`](/mcp/tools/get-entity).

:::

## Input

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `campaign_plan_name` | `string` | yes | The plan slug. |
| `base_revision` | `integer` | yes | The revision you last read. This is what makes it an approval **of the content you read**. |

## Output

`{ campaignPlan: { status: 'approved', … }, lineItemsValidated: 4 }`

:::warning[It cascades over every draft line]

Approving validates **all** of them, including one somebody else was still writing. When only one line is ready, use [`line_item_validate`](/mcp/tools/line-item-validate) instead — it exists precisely so your approval need not reach another person's half-written row.

:::

:::info[It blocks on nothing, and it spends nothing]

Unbounded, over-allocated and incomplete plans are all approvable: execution carries its own checks, applied where the information is complete, and putting them here too would only let the two drift. Approving creates no provider object — executing goes through the mutation tools and needs `mutation:write`.

:::

:::tip[A line added afterwards starts as a draft]

And adding it returns the plan to `draft`. That hole is the whole reason a line carries a state of its own — otherwise a line of spend could be slipped into a signed plan and be immediately executable.

:::

Requires the `campaign_plan:write` scope.
