> ## Documentation Index
> Fetch the complete documentation index at: https://docs.adcontextprotocol.org/llms.txt
> Use this file to discover all available pages before exploring further.

# report_usage

> report_usage sends consumption data to AdCP vendor agents after campaign delivery — impressions served, signals queried, governance checks run — so vendors can track revenue and verify billing.

Reports how a vendor's service was consumed after campaign delivery. Called by orchestrators to inform a vendor agent (signals, governance, creative) what was used so the vendor can track earned revenue and verify billing. It is also used against the sales agent itself when a media buy names the buyer or a measurement vendor as the billing authority.

Each usage record is self-contained — it carries its own `account` and `media_buy_id`. A single request can span multiple accounts and campaigns.

**Response Time**: \~1s.

**Response Schema**: [`/schemas/3.2.0-rc.7/account/report-usage-response.json`](https://adcontextprotocol.org/schemas/3.2.0-rc.7/account/report-usage-response.json)

## Request Parameters

| Parameter | Type | Required | Description |
| - | - | - | - |
| `idempotency_key` | string | Recommended | Client-generated unique key for this request (UUID recommended). If a request with the same key has already been accepted, the server returns the original response without re-processing. Prevents duplicate billing on retries. |
| `reporting_period` | object | Yes | `start` and `end` as ISO 8601 date-time in UTC. Applies to all records in the request. |
| `usage` | UsageRecord\[] | Yes | One or more usage records. |

### Usage Record Fields

Each record requires `account`, `vendor_cost`, and `currency`. Additional fields depend on the vendor type:

| Field | Type | Required | Description |
| - | - | - | - |
| `account` | [AccountRef](/dist/docs/3.2.0-rc.7/building/by-layer/L2/accounts-and-agents#account-references) | Yes | Account for this record — by `account_id` or `{ brand, operator }`. |
| `vendor_cost` | number | Yes | Amount owed to the vendor for this record, in `currency` |
| `currency` | string | Yes | ISO 4217 currency code |
| `pricing_option_id` | string | Vendor: Yes | Pricing option from the vendor's discovery response ([`get_signals`](/dist/docs/3.2.0-rc.7/signals/tasks/get_signals), [`list_creatives`](/dist/docs/3.2.0-rc.7/creative/task-reference/list_creatives), [`list_content_standards`](/dist/docs/3.2.0-rc.7/governance/content-standards/tasks/list_content_standards), [`list_property_lists`](/dist/docs/3.2.0-rc.7/governance/property/tasks/property_lists#list_property_lists)) or execution response ([`build_creative`](/dist/docs/3.2.0-rc.7/creative/task-reference/build_creative)). The vendor uses this to verify the correct rate was applied. |
| `impressions` | number | Signals: Yes | Impressions delivered |
| `media_spend` | number | percent\_of\_media: Yes | Media spend for percent-of-media cost verification |
| `media_buy_id` | string | Revenue share: Yes | Media buy whose selected package pricing is being reconciled. |
| `conversions` | number | No | Number of attributed conversion events. Optional analytics context for revenue share. |
| `conversion_value` | number | No | Total attributed conversion value. Optional analytics context; not the revenue-share billing basis. |
| `commissionable_value` | number | Revenue share: Yes | Settled attributed value eligible for commission. The seller verifies `vendor_cost = round_currency(commissionable_value × commission_rate)`. |
| `signal_agent_segment_id` | string | Signals: Yes | Signal identifier from `get_signals` |
| `creative_id` | string | Creative: Yes | Creative identifier from `build_creative` or `list_creatives`. Links usage to a specific creative for billing verification. A `build_creative` variant leaf earns a `creative_id` only when trafficked/added to the library — discarded best-of-N or fan-out variants are never reported here; their charge is the inline per-leaf `vendor_cost` on the `build_creative` response (the authoritative record for untrafficked leaves). |
| `build_variant_id` | string | No | When the reported `creative_id` was promoted from a specific `build_creative` variant leaf but differs from that source id, carry the source `build_variant_id` for reconciliation. On the canonical path where `creative_id` is the kept `build_variant_id`, omit this field. |
| `property_list_id` | string | Property lists: Yes | Property list identifier from `list_property_lists`. Links usage to a specific property list for billing verification. |

For revenue-share records, `pricing_option_id` identifies the agreed rate and commission basis. `currency` must match the selected option, and `vendor_cost` must not exceed the package's commission budget.

## Response

| Field | Description |
| - | - |
| `accepted` | Number of usage records successfully stored |
| `errors` | Validation errors for individual records. Partial acceptance is valid — accepted records are stored even when some fail. |

## Examples

### Signal usage — single campaign

<CodeGroup>
  ```json Request theme={null}
  {
    "idempotency_key": "550e8400-e29b-41d4-a716-446655440000",
    "reporting_period": {
      "start": "2025-03-01T00:00:00Z",
      "end": "2025-03-31T23:59:59Z"
    },
    "usage": [
      {
        "account": { "account_id": "acct_pinnacle_signals" },
        "signal_agent_segment_id": "luxury_auto_intenders",
        "pricing_option_id": "po_lux_auto_cpm",
        "impressions": 4200000,
        "media_spend": 21000.00,
        "vendor_cost": 2100.00,
        "currency": "USD"
      }
    ]
  }
  ```

  ```json Response theme={null}
  {
    "accepted": 1
  }
  ```
</CodeGroup>

### Creative usage — ad server with CPM pricing

<CodeGroup>
  ```json Request theme={null}
  {
    "idempotency_key": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "reporting_period": {
      "start": "2026-03-01T00:00:00Z",
      "end": "2026-03-31T23:59:59Z"
    },
    "usage": [
      {
        "account": { "account_id": "acct_acme_creative" },
        "creative_id": "cr_88201",
        "pricing_option_id": "po_video_cpm",
        "impressions": 2400000,
        "vendor_cost": 1200.00,
        "currency": "USD"
      }
    ]
  }
  ```

  ```json Response theme={null}
  {
    "accepted": 1
  }
  ```
</CodeGroup>

### Multi-account batch

A single request spanning two campaigns across two accounts:

```json theme={null}
{
  "idempotency_key": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "reporting_period": {
    "start": "2025-03-01T00:00:00Z",
    "end": "2025-03-31T23:59:59Z"
  },
  "usage": [
    {
      "account": { "account_id": "acct_pinnacle_signals" },
      "signal_agent_segment_id": "luxury_auto_intenders",
      "pricing_option_id": "po_lux_auto_cpm",
      "impressions": 2100000,
      "vendor_cost": 1050.00,
      "currency": "USD"
    },
    {
      "account": { "account_id": "acct_nova" },
      "signal_agent_segment_id": "eco_conscious_shoppers",
      "pricing_option_id": "po_eco_cpm",
      "impressions": 800000,
      "vendor_cost": 400.00,
      "currency": "USD"
    }
  ]
}
```

### Partial acceptance

If some records fail validation, the response identifies how many were accepted:

```json theme={null}
{
  "accepted": 1,
  "errors": [
    {
      "code": "INVALID_PRICING_OPTION",
      "message": "pricing_option_id 'po_unknown' does not exist on this account",
      "field": "usage[1].pricing_option_id"
    }
  ]
}
```

## Retry Safety

Always include `idempotency_key` in production usage. If a request times out or returns a network error, retry with the same key — the server will return the original result without double-counting.

An idempotent replay is transparent: the server returns the original response unchanged and does not emit a `DUPLICATE_REQUEST` error or advisory.

Generate a fresh UUID per request, not per usage record. If you need to report additional records for the same period, submit a new request with a new key.

## Reporting cadence

Report at regular intervals — monthly at minimum. For campaigns with significant spend, weekly reporting gives vendor agents timely visibility into earned revenue.

Report upon campaign completion to close out the final period.

## Error Handling

| Error Code | Description | Resolution |
| - | - | - |
| [`ACCOUNT_NOT_FOUND`](/dist/docs/3.2.0-rc.7/building/verification/compliance-catalog#error-code-account-not-found) | Account reference in a usage record not found or not accessible | Verify via [`list_accounts`](/dist/docs/3.2.0-rc.7/accounts/tasks/list_accounts); re-run [`sync_accounts`](/dist/docs/3.2.0-rc.7/accounts/tasks/sync_accounts) if needed |
| [`INVALID_USAGE_DATA`](/dist/docs/3.2.0-rc.7/building/verification/compliance-catalog#error-code-invalid-usage-data) | A usage record has missing or invalid fields | Check required fields for your vendor type |
| [`INVALID_PRICING_OPTION`](/dist/docs/3.2.0-rc.7/building/verification/compliance-catalog#error-code-invalid-pricing-option) | `pricing_option_id` not found on this account | Verify `pricing_option_id` from the vendor's discovery response |

## Next Steps

* [sync\_accounts](/dist/docs/3.2.0-rc.7/accounts/tasks/sync_accounts) — Sync advertiser accounts with a seller before reporting
* [Accounts Protocol](/dist/docs/3.2.0-rc.7/accounts/overview) — How account establishment and settlement fit together
* [Accounts and agents](/dist/docs/3.2.0-rc.7/building/by-layer/L2/accounts-and-agents) — Billing hierarchy and operator model
