Menú

Referencia de la API · Media Planner

Planes

media_planner · plans · 7 operaciones

GET/v1/media-planner/plans

List media plans

media_planner.plans.list

LecturaIdempotenteDesde 2026-11-01

Lists the organization's media plans, newest first (by start date), paginated by cursor (limit up to 200). Each plan has its window (start_date/end_date in ms and start_day/end_day as YYYY-MM-DD), currency, mode (campaigns, platforms or account), status (draft, active, archived), planned budget (total_budget in the plan's currency, or null when its rows mix currencies, and budget_by_currency, the real total by currency) and, once synced, the spend (total_spent, with the same rule, and spent_by_currency); amounts are rounded to 2 decimals. Filters: status, mode, and from/to (YYYY-MM-DD) for plans whose window overlaps that range. The mode and from filters fill the page (plans are read until limit plans match, up to 600 per call; a rare filter can bring a shorter page with has_more: follow next_cursor). It does not include the rows: use media_planner.plans.get or media_planner.campaigns.list. 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).

Alcance
media_planner:read
Permiso
Ver el módulo
Tool del MCP
media_planner_plans_listEn la superficie completa; en la compacta, mb_execute_operation con id: "media_planner.plans.list".

Costo declarado: hasta 601 lecturas y 0 escrituras por llamada (cuentan en el cupo diario).

Parámetros

limitintegerqueryopcional

How many items this page brings at most (see the maximum and the default in the schema).

Por defecto: 50

cursorstringqueryopcional

The next_cursor of the previous page, exactly as it came (only for the same list and filters); without it, the first page.

statusenumqueryopcional

Only plans in this status (default: all).

Valores: draft, active, archived

modeenumqueryopcional

Only plans of this granularity (campaigns, platforms or account).

Valores: campaigns, platforms, account

fromstringqueryopcional

Only plans whose window ends on or after this day.

tostringqueryopcional

Only plans whose window starts on or before this day.

Respuesta

dataarray<object>
has_moreboolean
next_cursorstring

Errores

Ejemplo

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

Probar con tu API key de prueba

Con una API key de prueba el pedido va siempre a tu organización de práctica: datos de ejemplo que puedes reiniciar.

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

Get one media plan with its rows

media_planner.plans.get

LecturaIdempotenteDesde 2026-11-01

Returns a media plan with its rows (campaigns, platform rows or account rows, in their display order; the first campaigns_limit, 100 by default and up to 500, with campaigns_truncated when there are more: media_planner.campaigns.list pages the rest). Each row has its platform, budget and currency, own flight dates if any, status, labels, the link to a real campaign (campaigns mode) and the known spend (last_synced_cost, last_synced_at; manual_spend in the platforms and account modes). Pass include_campaigns=false for the plan alone. total_budget is in the plan's currency (null when its rows mix currencies: read budget_by_currency); created_by_name goes next to created_by. Not found (media_plan_not_found) if the id is not a plan of this organization. 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).

Alcance
media_planner:read
Permiso
Ver el módulo
Tool del MCP
media_planner_plans_getEn la superficie completa; en la compacta, mb_execute_operation con id: "media_planner.plans.get".

Costo declarado: hasta 502 lecturas y 0 escrituras por llamada (cuentan en el cupo diario).

Parámetros

plan_idstringrutarequerido

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

include_campaignsbooleanqueryopcional

Include the plan's rows (default true), in their display order.

Por defecto: true

campaigns_limitintegerqueryopcional

How many rows come inline (default 100, up to 500); with more, campaigns_truncated is true and media_planner.campaigns.list pages the rest.

Por defecto: 100

Respuesta

idstring

Media plan id.

namestring

Plan name.

statusenum

draft, active or archived.

Valores: draft, active, archived

modeenum

campaigns, platforms or account: fixed for the life of the plan.

Valores: campaigns, platforms, account

start_datenumber

First day of the plan (epoch ms, 00:00 UTC). Send it back as start_day (YYYY-MM-DD).

end_datenumber

Last instant of the plan's last day (epoch ms, UTC).

currencystring

The plan's currency (ISO code).

total_budgetnumber | null

Planned budget of the plan in its currency; null when rows use another currency too (then read budget_by_currency, never add currencies).

created_atnumber

Epoch ms.

updated_atnumber

Epoch ms.

start_daystring

First day of the plan (YYYY-MM-DD): the format media_planner.plans.update takes.

end_daystring

Last day of the plan (YYYY-MM-DD, inclusive).

budget_by_currencyobject

Planned budget by currency (ISO code → amount): the plan's real total when it mixes currencies.

total_spentnumber | null

Known spend of the plan in its currency, after a cost sync; null when there is spend in another currency too (read spent_by_currency).

spent_by_currencyobject

Known spend by currency (ISO code → amount).

account_total_spendobject

Platforms and account modes: total spend of the connected ad accounts per platform (platform id → amount, in the currency of account_spend_meta).

account_spend_metaobject

Per platform: the currency of account_total_spend and how many ad accounts it adds up.

account_total_spend_synced_atnumber

When account_total_spend was last synced (epoch ms).

notesstring

Free notes of the plan.

carryover_enabledboolean

Whether the plan can receive the unspent balance of a finished plan.

carryover_platformsarray<string>

Platforms included in the carryover (absent or empty = all).

carryover_stateobject

The carryover this plan received or dismissed.

carryover_consumed_bystring | null

The plan that took this plan's unspent balance (null or absent: still available).

source_strategy_idstring

The Strategy Generator strategy the plan was created from, if any.

created_bystring

Who created the plan (uid).

created_by_namestring | null

That person's name (null when MB Suite does not know it: a former member).

campaignsarray<object>

The plan's rows in display order (with include_campaigns).

campaigns_truncatedboolean

true when the plan has more rows than campaigns_limit: read the rest with media_planner.campaigns.list.

Errores

Ejemplo

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

Probar con tu API key de prueba

Con una API key de prueba el pedido va siempre a tu organización de práctica: datos de ejemplo que puedes reiniciar.

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

Create a media plan

media_planner.plans.create

EscrituraDesde 2026-11-01

Creates a media plan: name, window (start_date and end_date as YYYY-MM-DD, inclusive), currency (ISO code) and mode, which is fixed for the life of the plan: campaigns (rows are planned campaigns, each can be linked to a real one to sync its spend), platforms (one row per ad platform; the spend is the total of the platform's connected accounts) or account (one row per currency; the spend adds up every connected account). Optional: notes, status (draft by default, or active), carryover_enabled and carryover_platforms (to receive the unspent balance of a finished plan), template_id (campaigns mode: seeds the campaigns of a template with budget 0) and campaigns (initial rows, with the rules of media_planner.campaigns.create). The plan's totals are computed from its rows. Returns the plan and its rows. 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).

Alcance
media_planner:write
Permiso
Editar en el módulo
Tool del MCP
media_planner_plans_createEn la superficie completa; en la compacta, mb_execute_operation con id: "media_planner.plans.create".
Eventos que puede emitir
media_planner.campaign.changed

Costo declarado: hasta 110 lecturas y 402 escrituras por llamada (cuentan en el cupo diario).

Parámetros

namestringcuerporequerido

Plan name (e.g. "November 2026").

start_datestringcuerporequerido

First day of the plan (YYYY-MM-DD).

end_datestringcuerporequerido

Last day of the plan (YYYY-MM-DD, inclusive).

currencystringcuerporequerido

The plan's currency (ISO code, e.g. USD, ARS): the default of its rows.

modeenumcuerpoopcional

Granularity, fixed for the life of the plan: campaigns (rows are planned campaigns), platforms (one row per ad platform, spend = the platform's accounts) or account (one row per currency, spend = all connected accounts).

Valores: campaigns, platforms, account · Por defecto: "campaigns"

notesstringcuerpoopcional

Free notes of the plan.

statusenumcuerpoopcional

draft (default) or active.

Valores: draft, active · Por defecto: "draft"

carryover_enabledbooleancuerpoopcional

Let this plan receive the unspent balance of a finished plan (carryover).

Por defecto: false

carryover_platformsarray<enum>cuerpoopcional

Platforms included in the carryover (empty = all).

Valores: google_ads, meta_ads, tiktok_ads, linkedin_ads, twitter_ads, other

template_idstringcuerpoopcional

Campaigns mode: seed the plan with the campaigns of a template (own, inherited from the workspace or a published system template), with budget 0.

campaignsarray<object>cuerpoopcional

Initial rows, with the same rules as media_planner.campaigns.create.

Respuesta

plan_idstring

The new plan's id.

planobject

The new plan.

campaignsarray<object>

Its rows, as created.

Errores

Ejemplo

curl -X POST "https://api.mb-suite.com/v1/media-planner/plans" \
  -H "Authorization: Bearer $MB_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "name": "NAME",
  "start_date": "START_DATE",
  "end_date": "END_DATE",
  "currency": "CURRENCY"
}'

Probar con tu API key de prueba

Con una API key de prueba el pedido va siempre a tu organización de práctica: datos de ejemplo que puedes reiniciar.

curl -X POST "https://api.mb-suite.com/v1/media-planner/plans" \
  -H "Authorization: Bearer $MB_TEST_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "name": "NAME",
  "start_date": "START_DATE",
  "end_date": "END_DATE",
  "currency": "CURRENCY"
}'
PATCH/v1/media-planner/plans/{plan_id}

Update a media plan

media_planner.plans.update

EscrituraIdempotenteDesde 2026-11-01

Updates the plan, with the fields to change inside updates ({ plan_id, updates: { … } }): name, notes, window (start_date/end_date, YYYY-MM-DD), currency, status (draft or active; active also reactivates an archived plan) and carryover settings (carryover_enabled, carryover_platforms; an empty list means all platforms). The mode cannot change (duplicate the plan instead), and archiving goes through media_planner.plans.archive, which also closes its campaigns. Changing the window does not move the rows' own flight dates. Unknown fields are rejected; 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).

Alcance
media_planner:write
Permiso
Editar en el módulo
Tool del MCP
media_planner_plans_updateEn la superficie completa; en la compacta, mb_execute_operation con id: "media_planner.plans.update".

Costo declarado: hasta 1 lecturas y 1 escrituras por llamada (cuentan en el cupo diario).

Parámetros

plan_idstringrutarequerido

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

updatesobjectcuerporequerido

The fields to change (at least one); the rest stay as they are.

Respuesta

planobject

The plan as it is now.

changedboolean

false when the values sent were already the current ones: nothing was written.

Errores

Ejemplo

curl -X PATCH "https://api.mb-suite.com/v1/media-planner/plans/{plan_id}" \
  -H "Authorization: Bearer $MB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "updates": {}
}'

Probar con tu API key de prueba

Con una API key de prueba el pedido va siempre a tu organización de práctica: datos de ejemplo que puedes reiniciar.

curl -X PATCH "https://api.mb-suite.com/v1/media-planner/plans/{plan_id}" \
  -H "Authorization: Bearer $MB_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "updates": {}
}'
POST/v1/media-planner/plans/{plan_id}/duplicate

Duplicate a media plan

media_planner.plans.duplicate

EscrituraDesde 2026-11-01

Copies a plan with its rows into a new plan (typically next month's): optional name (default '<name> (Copy)', in the caller's language: (Copia), (Cópia)), start_date/end_date (when the window changes, every row takes the new window), status (active by default), carryover_enabled, carryover_platforms (empty = all) and notes (an empty string leaves the copy without notes); whatever is not sent comes from the original plan. Rows keep platform, budget, currency, labels and their link to real campaigns, but never the spend, the carryover (each budget goes back to its original amount), the Auto-Budget bookkeeping, the manual spend or the comments. campaign_status_mode: smart (default; completed campaigns come back active), draft (all drafts) or exact. Same mode as the original. To build next month's plan with what was agreed: exclude_campaign_ids leaves rows out of the copy, and campaign_overrides sets the budget (in the row's currency) and/or the status of a row in the copy. Every id must be a row of the original plan (400 unknown_campaign_ids with details.campaign_ids), a row can be overridden once and never when it is excluded (400 campaign_override_conflict), and leaving out every row is 400 no_campaigns_to_copy; budgets are numbers from 0 (invalid_input otherwise). The plan's totals come from the copied rows. Optional dry run: with dry_run=true nothing is written (no confirm_token needed): it runs the same checks and fails with the same errors, or returns a Preview whose counts say campaigns, excluded, budget_overrides, status_overrides and total_budget, whose items are the copied rows (up to 50) and whose warnings flag rows copied paused or cancelled and rows copied with budget 0, plus plan (name, start_day, end_day, status, mode, currency, carryover_enabled, carryover_platforms, total_budget, budget_by_currency), campaigns (per copied row: source_campaign_id, name, platform, currency, budget, original_budget, status, source_status) and excluded_campaign_ids. Removing a wrong copy later needs a key allowed to delete: check the dry run first. Reads the original plan and its rows (up to 500); writes the plan and one document per copied row. Returns the new plan. 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).

Alcance
media_planner:write
Permiso
Editar en el módulo
Tool del MCP
media_planner_plans_duplicateEn la superficie completa; en la compacta, mb_execute_operation con id: "media_planner.plans.duplicate".

Costo declarado: hasta 502 lecturas y 501 escrituras por llamada (cuentan en el cupo diario).

Parámetros

plan_idstringrutarequerido

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

namestringcuerpoopcional

Default: the original name + ' (Copy)', in the caller's language.

start_datestringcuerpoopcional

The copy's first day (YYYY-MM-DD; default: the original's). When the window changes, every row takes the new window.

end_datestringcuerpoopcional

The copy's last day (YYYY-MM-DD, inclusive; default: the original's).

statusenumcuerpoopcional

Default active.

Valores: draft, active

campaign_status_modeenumcuerpoopcional

smart (default): completed campaigns come back active, the rest keep their status; draft: all drafts; exact: same statuses.

Valores: smart, draft, exact

carryover_enabledbooleancuerpoopcional

Whether the copy can receive a carryover (default: the original's).

carryover_platformsarray<enum>cuerpoopcional

Platforms included in the copy's carryover (empty = all). Default: the original plan's.

Valores: google_ads, meta_ads, tiktok_ads, linkedin_ads, twitter_ads, other

notesstringcuerpoopcional

The copy's notes (an empty string leaves it without notes). Default: the original plan's.

exclude_campaign_idsarray<string>cuerpoopcional

Rows of the original plan that the copy leaves out (row ids from media_planner.campaigns.list). Each one must be a row of that plan.

campaign_overridesarray<object>cuerpoopcional

Per-row changes in the copy: budget and/or status of a row of the original plan, at most once per row and never for an excluded row.

Respuesta

plan_idstring

The copy's id.

planobject

The copy.

campaign_countnumber

Rows copied.

Errores

Ejemplo

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

Probar con tu API key de prueba

Con una API key de prueba el pedido va siempre a tu organización de práctica: datos de ejemplo que puedes reiniciar.

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

Archive a media plan

media_planner.plans.archive

EscrituraIdempotenteDesde 2026-11-01

Archives a plan and closes its campaigns: scheduled ones become cancelled, active and paused ones become completed (drafts, completed and cancelled stay as they are); each change is kept in the campaign history and the plan.archived webhook fires. Call it with dry_run=true first to see the transitions (no confirm_token needed). Archiving is a status, not a deletion: media_planner.plans.update with status active reactivates the plan (campaign statuses do not go back). Idempotent: an archived plan with nothing to close 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).

Instrucciones para agentes

Tell the person how many campaigns changed status (transitions) when archiving.

Alcance
media_planner:write
Permiso
Editar en el módulo
Tool del MCP
media_planner_plans_archiveEn la superficie completa; en la compacta, mb_execute_operation con id: "media_planner.plans.archive".

Costo declarado: hasta 502 lecturas y 501 escrituras por llamada (cuentan en el cupo diario).

Parámetros

plan_idstringrutarequerido

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

Respuesta

planobject

The plan as it is now.

changedboolean

false when it was already archived.

transitionsarray<object>

How many rows went from each status to another.

total_campaignsnumber

Rows of the plan.

Errores

Ejemplo

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

Probar con tu API key de prueba

Con una API key de prueba el pedido va siempre a tu organización de práctica: datos de ejemplo que puedes reiniciar.

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

Delete a media plan

media_planner.plans.delete

IrreversibleDesde 2026-11-01

Deletes a plan with its rows and its campaign change history. It goes to the 30-day trash, where an owner or admin can restore it (platform.trash.restore); the comments of each campaign and the record of sent emails are kept and come back with it. The trash keeps up to 150 records with a plan, the rows first: when the history does not fit, its oldest entries are left out (the dry run warns and the trash item says linked_truncated), and a plan whose rows alone do not fit is refused before anything is deleted with 409 media_plan_too_large_for_trash (delete some rows first with media_planner.campaigns.bulk.delete). If the plan had received another plan's balance by carryover, that balance becomes available again (restoring the plan takes it again, or answers 409 carryover_source_consumed if another plan took it meanwhile). The last sync breakdown is discarded (the next sync rebuilds it). Outside the app it needs a dry run (which counts rows and history) and a confirm_token, except a REST DELETE with a key allowed to delete. Requires full access to the Media Planner.

Con una API key, este DELETE se ejecuta directo: el registro queda 30 días en la papelera y la respuesta trae su trash_item_id. Con un token OAuth, y por el MCP, pide dry_run → confirm_token.

Alcance
media_planner:write y «Permitir eliminar» (media_planner:delete en OAuth)
Permiso
Editar en el módulo
Tool del MCP
media_planner_plans_deleteEn la superficie completa; en la compacta, mb_execute_operation con id: "media_planner.plans.delete".

Costo declarado: hasta 1100 lecturas y 1100 escrituras por llamada (cuentan en el cupo diario).

Parámetros

plan_idstringrutarequerido

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

Respuesta

oktrue

Always true.

deleted_campaignsnumber

Rows deleted with the plan.

released_carryovernumber

Finished plans whose balance this plan had received: it is available to carry over again.

trash_item_idstring

The trash item this deletion left: the item_id of platform.trash.restore (POST /trash/{item_id}/restore). Missing if nothing went to the trash.

trash_item_idsarray<string>

Only when the deletion left more than one copy: all of them, the first being trash_item_id.

trash_expires_atnumber

When the copy leaves the trash for good (epoch ms): 30 days after the deletion.

Errores

Ejemplo

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

Probar con tu API key de prueba

Con una API key de prueba el pedido va siempre a tu organización de práctica: datos de ejemplo que puedes reiniciar.

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