Lists the rows of a media plan in their display order, paginated by cursor (limit up to 200): campaigns in a campaigns-mode plan, platform rows or account rows in the other modes (row_kind says which). Each row has platform, budget, currency, status, own flight dates if any (start_day/end_day), labels, the link to a real campaign and the known spend (last_synced_cost). Filters status and platform fill the page (the rows are read until limit rows match). 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 fields 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_campaigns_listOn the full surface; on the compact one, mb_execute_operation with id: "media_planner.campaigns.list".
Declared cost: up to 203 reads and 0 writes per call (they count against the daily quota).
Parameters
plan_idstringpathrequired
Media plan id (from media_planner.plans.list).
limitintegerqueryoptional
How many items this page brings at most (see the maximum and the default in the schema).
Default: 50
cursorstringqueryoptional
The next_cursor of the previous page, exactly as it came (only for the same list and filters); without it, the first page.
statusenumqueryoptional
Only rows in this status (draft, scheduled, active, paused, completed, cancelled).
Returns one row of a media plan (a campaign, a platform row or an account row) with its budget, currency, status, dates, labels, link to a real campaign, carryover applied, manual spend and known spend. Not found: media_plan_not_found for the plan, media_plan_row_not_found for the row. 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 fields 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_campaigns_getOn the full surface; on the compact one, mb_execute_operation with id: "media_planner.campaigns.get".
Declared cost: up to 2 reads and 0 writes per call (they count against the daily quota).
Parameters
plan_idstringpathrequired
Media plan id (from media_planner.plans.list).
campaign_idstringpathrequired
Row id inside the plan: a campaign, a platform row or an account row (from media_planner.campaigns.list).
Response
idstring
Row id.
row_kindenum
campaign (campaigns mode), platform (one per ad platform) or account (one per currency).
Values: campaign, platform, account
namestring
Row name (in platform and account modes, set by MB Suite).
platformstring
google_ads, meta_ads, tiktok_ads, linkedin_ads, twitter_ads or other.
budgetnumber
Planned budget in the row's currency (carryover included).
original_budgetnumber
The budget without the carryover applied (budget − carryover.amount).
currencystring
The row's currency (ISO code).
statusenum
draft, scheduled, active, paused, completed or cancelled.
Adds a row to a media plan and recomputes the plan's totals. What a row is depends on the plan's mode: in campaigns mode it is a planned campaign (name and platform required; it can be linked to a real campaign with mapped_campaign_id + external_customer_id, an ad account connected to this organization for that platform, to sync its spend); in platforms mode it is one row per ad platform (platform required, one row per platform except 'other', which needs platform_custom_name; MB Suite names it and its spend is the total of that platform's accounts); in account mode it is one row per currency (MB Suite names it; excluded_account_ids leaves connected accounts out of its total). manual_spend (platforms and account modes) adds spend entered by hand. Fields that do not apply to the plan's mode are rejected (field_not_in_mode). Defaults: budget 0, the plan's currency, status draft for a campaign and active for a platform or account row, no own dates (the row follows the plan window), last position. label_ids must be campaign labels of this organization or of its workspace. Errors: platform_row_exists, currency_row_exists and limit_reached (409; a plan holds up to 500 rows, details.resource media_plan_rows), external_account_not_linked (404: an ad account that is not connected to the organization; details.platform), link_incomplete and unknown_label_ids (400). Returns the row and the plan's new totals. Requires full 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 fields are left out of the response (the permissions guide lists what each platform allows).
Scope
media_planner:write
Permission
Edit in the module
MCP tool
media_planner_campaigns_createOn the full surface; on the compact one, mb_execute_operation with id: "media_planner.campaigns.create".
Updates one or more fields of a row, sent inside updates ({ plan_id, campaign_id, updates: { … } }): name, platform and platform_custom_name (campaigns mode), budget, currency, start_date/end_date (YYYY-MM-DD; null clears them so the row follows the plan), status, label_ids, the link to a real campaign (mapped_campaign_id + external_customer_id together; mapped_campaign_id null unlinks; changing the platform of a linked campaign unlinks it), manual_spend (null clears it; the known spend keeps the synced part), excluded_account_ids (account mode) and order. What a row is depends on the plan's mode: in campaigns mode it is a planned campaign (name and platform required; it can be linked to a real campaign with mapped_campaign_id + external_customer_id, an ad account connected to this organization for that platform, to sync its spend); in platforms mode it is one row per ad platform (platform required, one row per platform except 'other', which needs platform_custom_name; MB Suite names it and its spend is the total of that platform's accounts); in account mode it is one row per currency (MB Suite names it; excluded_account_ids leaves connected accounts out of its total). manual_spend (platforms and account modes) adds spend entered by hand. A platform row cannot change its platform (platform_immutable). Each change is kept in the campaign history (media_planner.changes.list); budget and currency changes recompute the plan's totals. skip_activity: true keeps the change out of the account's Activity feed, for automated syncs that name each row after its real campaign: it only goes with name and the link fields (mapped_campaign_id, mapped_campaign_name, external_customer_id); with any other field it is invalid_input (400) and nothing is saved. The change stays in the audit log and the history, and the webhook still fires. An update that changes nothing returns changed: false. Requires full 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 fields are left out of the response (the permissions guide lists what each platform allows).
Scope
media_planner:write
Permission
Edit in the module
MCP tool
media_planner_campaigns_updateOn the full surface; on the compact one, mb_execute_operation with id: "media_planner.campaigns.update".
Declared cost: up to 553 reads and 3 writes per call (they count against the daily quota).
Parameters
plan_idstringpathrequired
Media plan id (from media_planner.plans.list).
campaign_idstringpathrequired
Row id inside the plan: a campaign, a platform row or an account row (from media_planner.campaigns.list).
updatesobjectbodyrequired
The fields to change (at least one); the rest stay as they are.
skip_activitybooleanbodyoptional
true: this change does not leave an entry in the account's Activity feed (for an automated process, such as keeping row names in sync with the real campaigns). It is still recorded in the audit log and in the campaign history (media_planner.changes.list), and media_planner.campaign.changed still fires. Only with name and the link fields (mapped_campaign_id, mapped_campaign_name, external_customer_id) in updates; with any other field the call is invalid_input.
Response
campaignobject
The row as it is now.
changedboolean
false when the values sent were already the current ones: nothing was written.
Deletes one row of a media plan and recomputes the plan's totals. The row goes to the 30-day trash, where an owner or admin can restore it (platform.trash.restore; its comments stay and come back with it, and restoring recomputes the plan totals; 409 trash_restore_parent_missing if the plan no longer exists). The deletion is kept in the plan's change history. Outside the app it needs a dry run and a confirm_token, except a REST DELETE with a key allowed to delete. Requires full access to the Media Planner.
With an API key, this DELETE runs directly: the record stays 30 days in the trash and the response carries its trash_item_id. With an OAuth token, and through the MCP, it needs dry_run → confirm_token.
Scope
media_planner:writeand “Allow deletions” (media_planner:delete in OAuth)
Permission
Edit in the module
MCP tool
media_planner_campaigns_deleteOn the full surface; on the compact one, mb_execute_operation with id: "media_planner.campaigns.delete".
Sets the display order of a plan's rows: campaign_ids in the new order (position = index); rows not listed keep their relative order after them. All or nothing: an id that is not a row of the plan stops the whole reorder (404). In a platforms-mode plan the order matters: if two rows ever share a platform, the first one receives the platform's spend. Returns how many rows moved and the final order. Requires full access to the Media Planner.
Scope
media_planner:write
Permission
Edit in the module
MCP tool
media_planner_campaigns_reorderOn the full surface; on the compact one, mb_execute_operation with id: "media_planner.campaigns.reorder".
Declared cost: up to 501 reads and 500 writes per call (they count against the daily quota).
Parameters
plan_idstringpathrequired
Media plan id (from media_planner.plans.list).
campaign_idsarray<string>bodyrequired
Row ids in the new order. Rows not listed keep their relative order after these.
Applies the same change to up to 500 rows of a plan, like the selection bar of the app: status, start_date/end_date (YYYY-MM-DD; null clears), currency (not in account mode, where each row is one currency), add_label_ids and remove_label_ids. Ids that are not rows of the plan are skipped and returned in not_found; rows that would end before they start stop the whole call (date_range_invalid). Each changed row is kept in the campaign history. Outside the app it requires a dry run (which lists the rows) and a confirm_token. Requires full access to the Media Planner.
Needs confirmation: first dry_run: true (preview and confirm_token, valid 10 minutes and for one run), then the same body with confirm_token. In a few operations only with certain data: the description says when. Why and how: Dry run and confirm_token.
Scope
media_planner:write
Permission
Edit in the module
MCP tool
media_planner_campaigns_bulk_updateOn the full surface; on the compact one, mb_execute_operation with id: "media_planner.campaigns.bulk.update".
Deletes up to 500 rows of a plan and recomputes its totals; each row goes to the 30-day trash and can be restored on its own. Ids that are not rows of the plan are skipped and returned in not_found. The deletions are kept in the plan's change history. Outside the app it requires a dry run (which lists the rows) and a confirm_token. Requires full access to the Media Planner.
Needs confirmation: first dry_run: true (preview and confirm_token, valid 10 minutes and for one run), then the same body with confirm_token. In a few operations only with certain data: the description says when. Why and how: Dry run and confirm_token.
Scope
media_planner:writeand “Allow deletions” (media_planner:delete in OAuth)
Permission
Edit in the module
MCP tool
media_planner_campaigns_bulk_deleteOn the full surface; on the compact one, mb_execute_operation with id: "media_planner.campaigns.bulk.delete".
Copies campaigns from another campaigns-mode plan of this organization (source_plan_id; campaign_ids to pick some, default all, up to 200) to the end of this plan, which must be in campaigns mode too. Each copy keeps name, platform, currency and labels, takes its original budget (without carryover), the window of this plan and status draft, and drops the link to the real campaign, the spend, the carryover and the Auto-Budget bookkeeping. Recomputes the plan's totals and keeps the import in the change history with the source plan's name. Returns the new row ids. Requires full access to the Media Planner.
Scope
media_planner:write
Permission
Edit in the module
MCP tool
media_planner_campaigns_importOn the full surface; on the compact one, mb_execute_operation with id: "media_planner.campaigns.import".