Menu

API reference · Media Planner

Carryover

media_planner · carryover · 4 operations

GET/v1/media-planner/plans/{plan_id}/carryover/candidates

List the plans whose balance can be carried over

media_planner.carryover.candidates

ReadIdempotentSince 2026-11-01

For a plan with carryover enabled, lists the finished plans (active or archived, carryover enabled, balance not used by another plan) whose unspent balance it can receive, most recent first: each with its rows' budget, known spend and balance, the balance by currency, and needs_sync when its costs were not synced after it ended (sync it first with media_planner.costs.sync for an exact balance). Between two campaigns-mode plans only shared platforms count, and the receiving plan's carryover_platforms filter applies. Empty when carryover is off for the plan. Requires view access to the Media Planner. With Google Ads, LinkedIn or TikTok, their terms limit it through the API and the MCP: what they do not allow answers 403 platform_terms_restricted, and their records are left out of the response (the permissions guide lists what each platform allows).

Scope
media_planner:read
Permission
View the module
MCP tool
media_planner_carryover_candidatesOn the full surface; on the compact one, mb_execute_operation with id: "media_planner.carryover.candidates".

Declared cost: up to 2000 reads and 0 writes per call (they count against the daily quota).

Parameters

plan_idstringpathrequired

Media plan id (from media_planner.plans.list).

Response

candidatesarray<object>

Most recent first.

current_plan_platformsarray<string>

The receiving plan's platforms.

Errors

Example

curl "https://api.mb-suite.com/v1/media-planner/plans/{plan_id}/carryover/candidates" \
  -H "Authorization: Bearer $MB_API_KEY"

Try it with your test API key

With a test API key the request always goes to your practice organization: example data you can reset.

curl "https://api.mb-suite.com/v1/media-planner/plans/{plan_id}/carryover/candidates" \
  -H "Authorization: Bearer $MB_TEST_KEY"
POST/v1/media-planner/plans/{plan_id}/carryover/apply

Apply a carryover to a plan

media_planner.carryover.apply

WriteSince 2026-11-01

Adds a balance to the budget of rows of a plan with carryover enabled and not applied yet. source: { mode: from_plan, source_plan_id } takes the balance of a candidate (media_planner.carryover.candidates) and marks that plan as used, or { mode: manual, note, total_amounts: [{ currency, amount }] } records a balance from elsewhere. allocations: [{ campaign_id, amount }] says how much goes to each row (negative subtracts; rows with 0 are skipped). What is allocated cannot exceed the available balance in any currency (the row's currency, or the plan's): the source plan's balance by currency (balance_by_currency in media_planner.carryover.candidates) or the manual total_amounts, with a 0.5 margin for rounding; more is 400 carryover_over_allocated with details.currencies (currency, allocated, available) and nothing is written. Each row keeps the carryover it received and the change history shows the budget before and after; the plan's totals are recomputed and media_planner.carryover.applied fires. Revert it with media_planner.carryover.revert. Errors: carryover_over_allocated, carryover_allocations_empty, carryover_same_plan (400), media_plan_row_not_found (404), carryover_disabled, carryover_already_applied, carryover_source_consumed (409). Requires full access to the Media Planner.

Scope
media_planner:write
Permission
Edit in the module
MCP tool
media_planner_carryover_applyOn the full surface; on the compact one, mb_execute_operation with id: "media_planner.carryover.apply".

Declared cost: up to 1100 reads and 503 writes per call (they count against the daily quota).

Parameters

plan_idstringpathrequired

The plan that receives the balance (carryover enabled, not applied yet).

sourceobjectbodyrequired

Where the balance comes from: { mode: from_plan, source_plan_id } or { mode: manual, note, total_amounts }.

allocationsarray<object>bodyrequired

How much goes to each row of the plan; per currency, at most the available balance.

Response

applied_amountnumber

What was added to the rows' budgets (the sum of allocations; never more than the balance available).

total_amountnumber

The balance that was available to distribute.

campaign_countnumber

Rows that received an amount.

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/media-planner/plans/{plan_id}/carryover/apply" \
  -H "Authorization: Bearer $MB_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "source": "SOURCE",
  "allocations": []
}'

Try it with your test API key

With a test API key the request always goes to your practice organization: example data you can reset.

curl -X POST "https://api.mb-suite.com/v1/media-planner/plans/{plan_id}/carryover/apply" \
  -H "Authorization: Bearer $MB_TEST_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "source": "SOURCE",
  "allocations": []
}'
POST/v1/media-planner/plans/{plan_id}/carryover/revert

Revert the carryover of a plan

media_planner.carryover.revert

WriteSince 2026-11-01

Undoes an applied (or dismissed) carryover: each row's budget loses the amount it received (later manual edits are kept), the plan's carryover goes back to pending, and the source plan's balance becomes available again. Recomputes the plan's totals and keeps each change in the history. 409 carryover_nothing_to_revert if there is none. Requires full access to the Media Planner.

Scope
media_planner:write
Permission
Edit in the module
MCP tool
media_planner_carryover_revertOn the full surface; on the compact one, mb_execute_operation with id: "media_planner.carryover.revert".

Declared cost: up to 503 reads and 502 writes per call (they count against the daily quota).

Parameters

plan_idstringpathrequired

Media plan id (from media_planner.plans.list).

Response

reverted_countnumber

Rows whose carried-over amount was taken back off their budget.

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/media-planner/plans/{plan_id}/carryover/revert" \
  -H "Authorization: Bearer $MB_API_KEY"

Try it with your test API key

With a test API key the request always goes to your practice organization: example data you can reset.

curl -X POST "https://api.mb-suite.com/v1/media-planner/plans/{plan_id}/carryover/revert" \
  -H "Authorization: Bearer $MB_TEST_KEY"
POST/v1/media-planner/plans/{plan_id}/carryover/dismiss

Dismiss a carryover candidate

media_planner.carryover.dismiss

WriteIdempotentSince 2026-11-01

Dismisses the balance of a candidate plan (source_plan_id) for this plan: no budget changes, the plan stops offering it and records the balance that was available (computed now). The source's balance stays free for other plans. media_planner.carryover.revert undoes the dismissal. 409 carryover_already_applied if a carryover is applied (revert it instead). Requires full access to the Media Planner.

Scope
media_planner:write
Permission
Edit in the module
MCP tool
media_planner_carryover_dismissOn the full surface; on the compact one, mb_execute_operation with id: "media_planner.carryover.dismiss".

Declared cost: up to 503 reads and 1 writes per call (they count against the daily quota).

Parameters

plan_idstringpathrequired

Media plan id (from media_planner.plans.list).

source_plan_idstringbodyrequired

The candidate plan whose balance is dismissed.

Response

oktrue

Always true.

dismissed_balancenumber

The source plan's balance this plan chose not to receive (the sum of its rows' balances), recorded on the plan.

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/media-planner/plans/{plan_id}/carryover/dismiss" \
  -H "Authorization: Bearer $MB_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "source_plan_id": "SOURCE_PLAN_ID"
}'

Try it with your test API key

With a test API key the request always goes to your practice organization: example data you can reset.

curl -X POST "https://api.mb-suite.com/v1/media-planner/plans/{plan_id}/carryover/dismiss" \
  -H "Authorization: Bearer $MB_TEST_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "source_plan_id": "SOURCE_PLAN_ID"
}'