Menu

API reference · SEO Planner

Items

seo_planner · items · 9 operations

GET/v1/seo-planner/items

List SEO planner actions

seo_planner.items.list

ReadIdempotentSince 2026-11-01

Lists the actions (cards) of the organization's SEO Planner, paginated by cursor (limit up to 200). Pass month_key (YYYY-MM) for the actions of one month, as the planner shows them, or from_month/to_month (inclusive) for a range of months; without a month filter, every action in chronological order. Optional filters: status (pending, in_progress, completed) and type. source_key returns the action created with that key (seo_planner.items.create): an exact match, normally one action, in id order, with the other filters applied to it; it reads only what matches, so it is the cheap way to check whether an action of yours already exists. A filter the query cannot apply (type; status together with a month) is applied while reading, and the page keeps reading until it has limit actions or has looked at 1,000 (then has_more is true and next_cursor continues where it stopped). Each action carries its month, status, type, sub-actions (checklist), content brief, backlink details, the pack or template it came from, its source_key if it was created with one, comment_count (0 when it has none) and who created it (created_by, with the person's current name). Errors: 400 month_filter_conflict (month_key with from_month/to_month), invalid_month_range, invalid_input. Requires view access to the SEO Planner.

Scope
seo_planner:read
Permission
View the module
MCP tool
seo_planner_items_listOn the full surface; on the compact one, mb_execute_operation with id: "seo_planner.items.list".

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

Parameters

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.

month_keystringqueryoptional

Only the actions of this month (YYYY-MM), in the planner's order. Not together with from_month/to_month.

from_monthstringqueryoptional

From this month on (YYYY-MM, inclusive).

to_monthstringqueryoptional

Up to this month (YYYY-MM, inclusive).

statusenumqueryoptional

Only actions in this status: pending, in_progress or completed.

Values: pending, in_progress, completed

typeenumqueryoptional

Only actions of this type.

Values: blog_post, on_page_seo, speed_performance, technical_seo, website_audit, ai_geo, backlink, keyword_research, seo_analytics, international_seo, local_seo, setup_tools, competitor_analysis, link_audit, rank_tracking, client_report, custom

source_keystringqueryoptional

Only the action created with this source_key (exact match; normally one, since a key is unique in the organization). The other filters still apply to it.

Response

dataarray<object>
has_moreboolean
next_cursorstring

Errors

Example

curl "https://api.mb-suite.com/v1/seo-planner/items" \
  -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/seo-planner/items" \
  -H "Authorization: Bearer $MB_TEST_KEY"
GET/v1/seo-planner/items/{item_id}

Get one SEO planner action

seo_planner.items.get

ReadIdempotentSince 2026-11-01

Returns one action of the SEO Planner: title, subtitle, description, type, status, month (month_key YYYY-MM), sub-actions with their completed flag, content brief, backlink details, pack or template of origin, its source_key if it was created with one, comment_count and who created it. 404 seo_item_not_found if it does not exist in this organization. Requires view access to the SEO Planner.

Scope
seo_planner:read
Permission
View the module
MCP tool
seo_planner_items_getOn the full surface; on the compact one, mb_execute_operation with id: "seo_planner.items.get".

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

Parameters

item_idstringpathrequired

The action id (id of an item of seo_planner.items.list).

Response

idstring
titlestring
typestring

Action type (blog_post, on_page_seo, technical_seo…).

statusstring

pending, in_progress or completed.

comment_countnumber

Comments on the action (seo_planner.comments.list); 0 when it has none.

created_atnumber
updated_atnumber
organization_idstring | null

The organization the action belongs to.

subtitlestring | null
descriptionstring | null
month_keystring | null

The month of the action (YYYY-MM): the planner's column.

scheduled_datenumber | null

The 1st of the month at 12:00 UTC (ms), to sort; the month is month_key.

sub_actionsarray<object>

The checklist, in order.

content_briefobject | null

Content brief (target keyword, outline…), when it has one.

backlink_detailsobject | null

Backlink details (domain, DA, cost, contact status), when it has them.

ordernumber

Position inside its month column, when it was moved by hand.

pack_idstring | null

The pack it was created from (seo_planner.packs.get).

pack_sourcestring | null

Where that pack was: org, parent or system.

pack_item_idstring | null
template_idstring | null

The action template it was created from.

template_sourcestring | null

system (the MB Suite library) or org.

source_keystring | null

The source_key it was created with (seo_planner.items.create), if any.

created_byobject | null

Who created it.

Errors

Example

curl "https://api.mb-suite.com/v1/seo-planner/items/{item_id}" \
  -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/seo-planner/items/{item_id}" \
  -H "Authorization: Bearer $MB_TEST_KEY"
POST/v1/seo-planner/items

Create an SEO planner action

seo_planner.items.create

WriteSince 2026-11-01

Adds an action to the SEO Planner in a month: title, type is one of blog_post, on_page_seo, speed_performance, technical_seo, website_audit, ai_geo, backlink, keyword_research, seo_analytics, international_seo, local_seo, setup_tools, competitor_analysis, link_audit, rank_tracking, client_report, custom; month_key (YYYY-MM) is the month column where it appears. Optional: status (default pending), subtitle, description, sub_actions (an ordered checklist of titles, each optionally completed), content_brief (target keyword, outline, keywords to include…) and backlink_details (domain, DA, cost, contact status). The creator is the caller. To create it from a saved template use seo_planner.action_templates.apply; from a pack, seo_planner.packs.apply. Returns the action with created: true. Optional source_key (letters, digits and : . _ -, 1 to 200 characters, starting with a letter or digit; 400 invalid_input otherwise): a key of yours that identifies the action, unique in the organization and kept on it (returned by seo_planner.items.list and get, and seo_planner.items.list?source_key= finds it). If an action with that source_key already exists here, nothing is created, no event fires and that action is returned as it is now (its month or content may differ from what you sent) with created: false, so running a script again never duplicates it (only this operation keeps the key unique: restoring from the trash an action whose key was used again, or a write from the app, can leave two, and then the one with the lowest id is returned); without source_key every call creates a new action. The key cannot be changed afterwards. Cost: one write, plus one read to look for the key when source_key is sent. Requires full access to the SEO Planner.

Scope
seo_planner:write
Permission
Edit in the module
MCP tool
seo_planner_items_createOn the full surface; on the compact one, mb_execute_operation with id: "seo_planner.items.create".
Events it can emit
seo_planner.item.created

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

Parameters

titlestringbodyrequired

The action's title (1 to 500 characters).

typeenumbodyrequired

Action type: blog_post, on_page_seo, speed_performance, technical_seo, website_audit, ai_geo, backlink, keyword_research, seo_analytics, international_seo, local_seo, setup_tools, competitor_analysis, link_audit, rank_tracking, client_report or custom.

Values: blog_post, on_page_seo, speed_performance, technical_seo, website_audit, ai_geo, backlink, keyword_research, seo_analytics, international_seo, local_seo, setup_tools, competitor_analysis, link_audit, rank_tracking, client_report, custom

month_keystringbodyrequired

The month column it goes in (YYYY-MM).

statusenumbodyoptional

pending (default), in_progress or completed.

Values: pending, in_progress, completed

subtitlestringbodyoptional

A short line under the title.

descriptionstringbodyoptional

Longer description (plain text or simple HTML).

sub_actionsarray<object>bodyoptional

The checklist, in order (up to 100).

content_briefobjectbodyoptional

The content brief of a blog_post or on_page_seo action.

backlink_detailsobjectbodyoptional

The backlink details of a backlink action.

source_keystringbodyoptional

A key of yours that identifies this action (letters, digits and : . _ -, up to 200 characters), unique in the organization. If an action with this source_key already exists, nothing is created and that action is returned with created: false. It cannot be changed later.

Response

item_idstring
itemobject
createdboolean

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/seo-planner/items" \
  -H "Authorization: Bearer $MB_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "title": "TITLE",
  "type": "blog_post",
  "month_key": "MONTH_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/seo-planner/items" \
  -H "Authorization: Bearer $MB_TEST_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "title": "TITLE",
  "type": "blog_post",
  "month_key": "MONTH_KEY"
}'
PATCH/v1/seo-planner/items/{item_id}

Update an SEO planner action

seo_planner.items.update

WriteIdempotentSince 2026-11-01

Changes one or more fields of an action: title, subtitle, description, type, status (pending, in_progress, completed), sub_actions (the whole ordered checklist: items with the id of an existing sub-action keep it, the rest are new, missing ones are removed), content_brief and backlink_details (null removes them) and order (position in its column). To move it to another month use seo_planner.items.move. Unknown fields are rejected. Setting status to completed also fires seo_planner.item.completed. Sending the same values changes nothing (changed: false). Requires full access to the SEO Planner.

Scope
seo_planner:write
Permission
Edit in the module
MCP tool
seo_planner_items_updateOn the full surface; on the compact one, mb_execute_operation with id: "seo_planner.items.update".

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

Parameters

item_idstringpathrequired

The action id (id of an item of seo_planner.items.list).

updatesobjectbodyrequired

The fields to change (at least one). The month is not here: move it with seo_planner.items.move.

Response

itemobject
changedboolean

Errors

Example

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

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 PATCH "https://api.mb-suite.com/v1/seo-planner/items/{item_id}" \
  -H "Authorization: Bearer $MB_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "updates": {}
}'
POST/v1/seo-planner/items/{item_id}/move

Move an SEO planner action to another month

seo_planner.items.move

WriteIdempotentSince 2026-11-01

Moves an action to the month month_key (YYYY-MM), like the move-to-next/previous-month buttons of the planner, keeping its status, sub-actions and comments. Moving it to the month it is already in changes nothing (changed: false). Requires full access to the SEO Planner.

Scope
seo_planner:write
Permission
Edit in the module
MCP tool
seo_planner_items_moveOn the full surface; on the compact one, mb_execute_operation with id: "seo_planner.items.move".
Events it can emit
seo_planner.item.updated

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

Parameters

item_idstringpathrequired

The action id (id of an item of seo_planner.items.list).

month_keystringbodyrequired

The month to move it to (YYYY-MM).

Response

itemobject
changedboolean

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/seo-planner/items/{item_id}/move" \
  -H "Authorization: Bearer $MB_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "month_key": "MONTH_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/seo-planner/items/{item_id}/move" \
  -H "Authorization: Bearer $MB_TEST_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "month_key": "MONTH_KEY"
}'
POST/v1/seo-planner/items/{item_id}/complete

Complete an SEO planner action

seo_planner.items.complete

WriteIdempotentSince 2026-11-01

Marks an action as completed; with complete_sub_actions: true it also ticks every sub-action of its checklist. Idempotent: an action that is already completed (with its sub-actions ticked, if asked) changes nothing (changed: false). Fires seo_planner.item.completed when the status changes. Requires full access to the SEO Planner.

Scope
seo_planner:write
Permission
Edit in the module
MCP tool
seo_planner_items_completeOn the full surface; on the compact one, mb_execute_operation with id: "seo_planner.items.complete".

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

Parameters

item_idstringpathrequired

The action id (id of an item of seo_planner.items.list).

complete_sub_actionsbooleanbodyoptional

true also ticks every sub-action of its checklist.

Response

itemobject
changedboolean

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/seo-planner/items/{item_id}/complete" \
  -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/seo-planner/items/{item_id}/complete" \
  -H "Authorization: Bearer $MB_TEST_KEY"
DELETE/v1/seo-planner/items/{item_id}

Delete an SEO planner action

seo_planner.items.delete

IrreversibleSince 2026-11-01

Deletes an action of the SEO Planner. It goes to the 30-day trash, where an owner or admin can restore it (platform.trash.restore); its comments stay attached and come back with it. 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 SEO 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
seo_planner:write and “Allow deletions” (seo_planner:delete in OAuth)
Permission
Edit in the module
MCP tool
seo_planner_items_deleteOn the full surface; on the compact one, mb_execute_operation with id: "seo_planner.items.delete".
Events it can emit
seo_planner.item.deleted

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

Parameters

item_idstringpathrequired

The action id (id of an item of seo_planner.items.list).

Response

oktrue
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.

Errors

Example

curl -X DELETE "https://api.mb-suite.com/v1/seo-planner/items/{item_id}" \
  -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 DELETE "https://api.mb-suite.com/v1/seo-planner/items/{item_id}" \
  -H "Authorization: Bearer $MB_TEST_KEY"
POST/v1/seo-planner/items/bulk/delete

Delete many SEO planner actions

seo_planner.items.bulk.delete

IrreversibleBulk · up to 200Since 2026-11-01

Deletes up to 200 actions of the SEO Planner, like the selection bar of the table view; each one goes to the 30-day trash and can be restored on its own. Ids that do not exist in this organization are skipped and returned in not_found. Outside the app it requires a dry run (which lists what will be deleted) and a confirm_token. Requires full access to the SEO 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
seo_planner:write and “Allow deletions” (seo_planner:delete in OAuth)
Permission
Edit in the module
MCP tool
seo_planner_items_bulk_deleteOn the full surface; on the compact one, mb_execute_operation with id: "seo_planner.items.bulk.delete".
Events it can emit
seo_planner.item.deleted

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

Parameters

item_idsarray<string>bodyrequired

Action ids (from seo_planner.items.list), up to 200; ids that do not exist are skipped and returned in not_found.

Response

deletednumber
not_foundarray<string>
trash_item_idsarray<string>

The trash items this deletion left, one per record: the item_id of platform.trash.restore (POST /trash/{item_id}/restore).

trash_expires_atnumber

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

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/seo-planner/items/bulk/delete" \
  -H "Authorization: Bearer $MB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "item_ids": [
    "ITEM_ID"
  ],
  "dry_run": true
}'

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/seo-planner/items/bulk/delete" \
  -H "Authorization: Bearer $MB_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "item_ids": [
    "ITEM_ID"
  ],
  "dry_run": true
}'
POST/v1/seo-planner/items/bulk/update

Change the status or month of many SEO planner actions

seo_planner.items.bulk.update

WriteBulk · up to 200Since 2026-11-01

Applies the same change to up to 200 actions, like the selection bar of the planner: status (pending, in_progress, completed) and/or month_key (YYYY-MM, moves them all to that month). Actions that already have those values are counted in unchanged; ids that do not exist are skipped and returned in not_found. Outside the app it requires a dry run and a confirm_token. Requires full access to the SEO 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
seo_planner:write
Permission
Edit in the module
MCP tool
seo_planner_items_bulk_updateOn the full surface; on the compact one, mb_execute_operation with id: "seo_planner.items.bulk.update".

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

Parameters

item_idsarray<string>bodyrequired

Action ids (from seo_planner.items.list), up to 200; ids that do not exist are skipped and returned in not_found.

updatesobjectbodyrequired

What changes (at least one): status and/or month_key.

Response

updatednumber
unchangednumber
not_foundarray<string>

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/seo-planner/items/bulk/update" \
  -H "Authorization: Bearer $MB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "item_ids": [
    "ITEM_ID"
  ],
  "updates": {},
  "dry_run": true
}'

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/seo-planner/items/bulk/update" \
  -H "Authorization: Bearer $MB_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "item_ids": [
    "ITEM_ID"
  ],
  "updates": {},
  "dry_run": true
}'