---
title: line_item_update
description: 'Edit a Line Item. A real change returns that Line Item to draft, and no other.'
---

Ask the agent to change one Line Item: its channel, its objective, its money, its audience, its dates, its ad account or its persona.

> "Raise the Meta Line Item of the spring sale Campaign Plan to €3,000, and add the Netherlands."

The agent reads the Campaign Plan to get the id and the revision of the Line Item. Then it calls `line_item_update` with only the fields that change. You see the Line Item as it is now. A real change returns a validated Line Item to draft. The approval of the Campaign Plan stays. A campaign that the Line Item created on Meta does not change.

[Plan a campaign](/mcp/tools/plan-a-campaign) walks the whole job.

## Reference

Update a Line Item. Omit a field to leave it alone; send null to clear it. Pass base_revision from campaign_plan_get. Any real change returns a validated line to draft, and only that line — the plan's own approval stands. The provider objects the line already created are untouched: a live campaign is never altered from here.

### Input

| Argument | Type | Required | Description |
| --- | --- | --- | --- |
| `advertiser_id` | string or null | no | null unlinks the ad account. |
| `age_max` | integer, 0 to 120 or null | no |  |
| `age_min` | integer, 0 to 120 or null | no |  |
| `base_revision` | integer | yes | The revision of the Line Item, as you last read it: the `revision` of that Line Item in `lineItems` of campaign_plan_get. It is not the revision of the Campaign Plan. It guards against a write over a change that another person made after your read. |
| `budget` | number, at least 0 or null | no |  |
| `campaign_plan_name` | string | yes | The Campaign Plan slug — its stable per-organization handle. |
| `channel` | one of `meta`, `tiktok`, `snapchat`, `google_search`, `google_pmax`, `google_display`, `youtube`, `programmatic_display`, `linkedin`, `x` | no |  |
| `countries` | array of (string, 2 characters) | no | The array is the value — send [] to clear the geography. |
| `end_date` | string or null | no | null makes the line inherit the plan's end, which can flip its budget between a total and a daily rate. That is allowed, and it returns the line to draft. |
| `gender` | one of `all`, `men`, `women` or null | no |  |
| `line_item_id` | string | yes | The Line Item id, as returned by campaign_plan_get. |
| `objective` | one of `awareness`, `engagement`, `leads`, `sales`, `traffic`, `app_promotion` | no |  |
| `persona_name` | string or null | no | A persona slug, looked up on the brand this plan is for; null clears it. |
| `start_date` | string or null | no |  |

### Output

A successful call returns this object in `structuredContent`.

| Field | Type | Always present | Description |
| --- | --- | --- | --- |
| `lineItem` | object | yes | A Line Item: one thing that the Campaign Plan buys. |
| `lineItem.advertiserId` | string or null | yes | The ad account that the Line Item runs through, `acc_…`, or `null`. |
| `lineItem.ageMax` | number or null | yes | The highest age, or `null` for no upper bound. |
| `lineItem.ageMin` | number or null | yes | The lowest age, or `null` for no lower bound. |
| `lineItem.budget` | number or null | yes | The amount in whole units of the currency of the Campaign Plan, or `null` when it is not set. `unit` tells how to read it. |
| `lineItem.campaignPlanId` | string | yes | The id of the Campaign Plan that holds the Line Item, `cpl_…`. |
| `lineItem.channel` | one of `meta`, `tiktok`, `snapchat`, `google_search`, `google_pmax`, `google_display`, `youtube`, `programmatic_display`, `linkedin`, `x` | yes | What the Line Item buys, in planning words. A channel is not a provider. |
| `lineItem.countries` | array of string | yes | ISO 3166-1 alpha-2 codes. An empty list means that the geography is not decided. |
| `lineItem.createdAt` | number | yes | Milliseconds since the Unix epoch, UTC. |
| `lineItem.createdBy` | string | yes | The user who added the Line Item, `usr_…`. |
| `lineItem.effectiveEndDate` | string or null | yes | The end that applies: the end date of the Line Item, else the end date of the Campaign Plan. `null` when neither has one. |
| `lineItem.effectiveStartDate` | string or null | yes | The start that applies: the start date of the Line Item, else the start date of the Campaign Plan. `null` when neither has one. |
| `lineItem.endDate` | string or null | yes | The end date of the Line Item itself, or `null` when the Line Item uses the end date of the Campaign Plan. |
| `lineItem.executable` | boolean | yes | `true` when AdCrunch can create objects for this channel today. It is not a promise that a create succeeds. |
| `lineItem.executions` | array of object | yes | The provider objects that the Line Item created, as `line_item_record_execution` recorded them. The list does not tell whether the Line Item is complete. |
| `lineItem.executions[].advertiserId` | string | yes | The ad account that holds the object, `acc_…`. |
| `lineItem.executions[].createdAt` | number | yes | When AdCrunch recorded the object, in milliseconds since the Unix epoch, UTC. |
| `lineItem.executions[].entityId` | string | yes | The id of the object on the provider, with no prefix. `get_entity` and `list_entities` use the same id. |
| `lineItem.executions[].entityType` | string | yes | The word of the provider for the level of the object, such as `campaign`, `adset` or `ad`. |
| `lineItem.executions[].id` | string | yes | The id of the record, `exe_…`. |
| `lineItem.executions[].mutationWorkflowId` | string or null | yes | The `workflowId` of the change that created the object, or `null` when the record names none. |
| `lineItem.executions[].provider` | one of `meta`, `gads`, `tiktok`, `x`, `openai`, `snapchat`, `dv360` | yes | The provider of the object. |
| `lineItem.gender` | one of `all`, `men`, `women` or null | yes | The gender of the audience, or `null` when it is not decided. `null` executes as `all`. |
| `lineItem.id` | string | yes | The id of the Line Item, `lni_…`. |
| `lineItem.objective` | one of `awareness`, `engagement`, `leads`, `sales`, `traffic`, `app_promotion` | yes | What the Line Item is for. |
| `lineItem.personaId` | string or null | yes | The Persona that explains the audience, `psn_…`, or `null`. The countries, the ages and the gender are what execute. |
| `lineItem.provider` | one of `meta`, `gads`, `tiktok`, `x`, `openai`, `snapchat`, `dv360` or null | yes | The provider that sells the channel, or `null` when AdCrunch has no integration for it. |
| `lineItem.revision` | number | yes | The revision of the Line Item. It increments when the Line Item changes. Send it as `base_revision` to `line_item_update`, `line_item_delete` or `line_item_validate`. |
| `lineItem.startDate` | string or null | yes | The start date of the Line Item itself, or `null` when the Line Item uses the start date of the Campaign Plan. |
| `lineItem.status` | one of `draft`, `validated` | yes | `validated` when a person cleared the Line Item to run, by `line_item_validate` or by the approval of the Campaign Plan. A real change to the Line Item returns it to `draft`. |
| `lineItem.unit` | one of `total`, `daily` | yes | How to read `budget`. `total` when the Line Item has an effective end date: the budget is for the whole period. `daily` when it has none: the budget is for each day. |
| `lineItem.updatedAt` | number or null | yes | When the Line Item last changed, or `null` when it never changed. |

### 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`
- `invalid_countries`
- `invalid_age_range`
- `invalid_amount`
- `invalid_window`
- `persona_not_in_brand`
- `advertiser_not_owned`
- `revision_mismatch`
- `forbidden`
- `invalid_request`
- `internal_error`

### Scope

The token must hold `campaign_plan: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.
- **Closed world.** The tool reads and writes the data of AdCrunch only.

### Example

The arguments:

```json
{
  "base_revision": 2,
  "budget": 3000,
  "campaign_plan_name": "spring-sale",
  "countries": [
    "FR",
    "BE",
    "NL"
  ],
  "line_item_id": "lni_2d9e77"
}
```

The result, in `structuredContent`:

```json
{
  "lineItem": {
    "advertiserId": "acc_1203456789012345",
    "ageMax": 44,
    "ageMin": 25,
    "budget": 3000,
    "campaignPlanId": "cpl_4e1a08",
    "channel": "meta",
    "countries": [
      "FR",
      "BE",
      "NL"
    ],
    "createdAt": 1768435200000,
    "createdBy": "usr_5d2b71",
    "effectiveEndDate": "2026-05-31",
    "effectiveStartDate": "2026-03-01",
    "endDate": null,
    "executable": true,
    "executions": [],
    "gender": "all",
    "id": "lni_2d9e77",
    "objective": "sales",
    "personaId": "psn_8c4a20",
    "provider": "meta",
    "revision": 3,
    "startDate": null,
    "status": "draft",
    "unit": "total",
    "updatedAt": 1769644800000
  }
}
```
