---
title: line_item_record_execution
description: 'Record one provider object a line item created, so the plan knows what came from where.'
---

Records that this **Line Item** created a particular provider object. Call it after each create.

## Input

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `campaign_plan_name` | `string` | yes | The plan that owns the line. |
| `line_item_id` | `lni_…` | yes | Which line this object came from. |
| `provider` | `enum` | yes | `meta`, `tiktok`, `gads`, `snapchat`, `dv360`. |
| `entity_type` | `string` | yes | The provider's own word for the level: `campaign`, `adset`, `ad`. |
| `entity_id` | `string` | yes | The **native** provider id, unprefixed, exactly as the create returned it. |
| `advertiser_id` | `acc_…` | yes | The account it was created in. |
| `mutation_workflow_id` | `string` | no | The workflow id the create returned, when you have it. |

## Example

```ts
const created = await meta_create_campaign({/* … */});
line_item_record_execution({
  campaign_plan_name: 'q4-acquisition',
  line_item_id: 'lni_abc',
  provider: 'meta',
  entity_type: 'campaign',
  entity_id: created.campaignId,
  advertiser_id: 'acc_123',
  mutation_workflow_id: created.workflowId,
});
```

:::warning[Nothing records this for you]

One line may create any number of objects and you chose the shape, so only you know which objects belong to which line. A line that executed but was never recorded looks unexecuted while it is already spending.

:::

:::info[Recording twice is harmless]

The same object named twice is one fact stated twice, and collapses to one row. Two _different_ objects are two rows — which is how a double execution stays visible, since nothing blocks one.

:::

:::tip[Say "3 objects created", never "complete"]

How many objects a line _should_ produce was never declared, so a line holding a campaign and no ad set cannot be called unfinished rather than done. Only "has created something" is knowable.

:::

Requires the `campaign_plan:write` scope.

## Reference

Record one provider object this Line Item created — call it after each create, with the native provider id. Only you know which objects belong to which line, so nothing records this for you. Almost nothing is refused: the object already exists, and an unrecorded one is worse than a late record. Recording the same object twice is harmless. Note that "how many objects a line should produce" was never declared, so a surface can say "3 objects created" but never "complete".

### Input

| Argument | Type | Required | Description |
| --- | --- | --- | --- |
| `advertiser_id` | string | yes | The ad account the object was created in. |
| `campaign_plan_name` | string | yes | The Campaign Plan slug — its stable per-organization handle. |
| `entity_id` | string | yes | The native provider id, exactly as the provider returned it — unprefixed, which is what makes it match get_entity and list_entities. |
| `entity_type` | string | yes | The provider's own word for the level: campaign, adset, ad. Use the provider's vocabulary, not a normalized one. |
| `line_item_id` | string | yes | The Line Item id, as returned by campaign_plan_get. |
| `mutation_workflow_id` | string | no | The workflow id the create returned, when you have it. It links this record to the attempt without either duplicating the other. |
| `provider` | one of `meta`, `tiktok`, `snapchat`, `gads`, `dv360`, `x`, `openai` | yes |  |

### 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`
- `advertiser_not_owned`
- `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.
- **Idempotent.** A second call with the same arguments changes nothing more.
- **Closed world.** The tool reads and writes the data of AdCrunch only.
