Menu

API reference · CRM

Prospects

crm · prospects · 15 operations

GET/v1/crm/prospects

List prospects (inbox)

crm.prospects.list

ReadIdempotentSince 2026-11-01

Lists prospects newest first, paginated by cursor. status: active (new + reviewing, the inbox; default), archived, converted or all. person_id keeps the prospects of one person and owner_id those of one owner (a member, or an AI agent's ai-… id); with both, the owner is applied to the page read. A seller with restricted scope only gets their own, the unassigned ones and the AI's, applied to the page read, so a page can bring fewer than limit while has_more is true: follow next_cursor until has_more is false. 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 or fields are left out of the response (the permissions guide lists what each platform allows).

Scope
crm:read
Permission
View the module
MCP tool
crm_prospects_listOn the full surface; on the compact one, mb_execute_operation with id: "crm.prospects.list".

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

Parameters

limitintegerqueryoptional

How many items this page brings at most (default 20, up to 200).

Default: 20

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

active (new and reviewing, the default), archived, converted or all.

Values: active, archived, converted, all

person_idstringqueryoptional

Only the prospects of this person.

owner_idstringqueryoptional

Only the prospects of this owner (a member's user id, or an AI agent's ai-… id).

Response

dataarray<object>
has_moreboolean
next_cursorstring

Errors

Example

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

Get one prospect

crm.prospects.get

ReadIdempotentSince 2026-11-01

Returns a prospect with its status (lifecycle), interest, linked person and company, value, owner, source, attribution, labels and custom fields. Not found if the id does not exist or the seller's scope hides it. 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
crm:read
Permission
View the module
MCP tool
crm_prospects_getOn the full surface; on the compact one, mb_execute_operation with id: "crm.prospects.get".

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

Parameters

prospect_idstringpathrequired

The prospect, by id (crm.prospects.list or crm.search).

Response

idstring
org_idstring
titlestring
statusenum

The lifecycle in the inbox: new, reviewing, converted (to a deal) or archived.

Values: new, reviewing, converted, archived

created_atnumber
updated_atnumber
interest_idstring | null

Its status as the inbox shows it (crm.prospects.interests.list); for prospects from before the migration, the old tag.

interest_namestring | null

The name of that status.

tagstring | null

Deprecated: the status of prospects from before 2026-08 (same ids as the default interests). Use interest_id.

person_idstring | null
company_idstring | null
valuenumber | null
currencystring | null
expected_close_datenumber | null

Expected close date, epoch ms.

owner_idstring | null

The owner: a member's user id (members.members.list), or an AI position's ai-… id.

owner_namestring | null

The name of the owner, resolved when the record is read.

source_idstring | null

The lead source (crm.lead_sources.list).

source_channelstring | null
external_lead_idstring | null

The lead id of the ads platform (Meta leadgen id, TikTok lead id).

submitted_atnumber | null

When the person submitted the lead form (platform time), epoch ms.

attributionobject | null
label_idsarray<string>
custom_fieldsobject
is_starredboolean
ai_scorenumber | null

The AI score 0-100 (ai_scoring.score).

ai_scoringobject | null
open_activity_countnumber | null

Pending tasks, calls and meetings of the prospect.

overdue_activity_countnumber | null

Of those, the ones already past their due date.

last_activity_atnumber | null
last_inbound_atnumber | null

Last contact FROM the lead, epoch ms.

last_outbound_atnumber | null

Last contact TO the lead, epoch ms.

next_booking_atnumber | null

The nearest confirmed meeting ahead, epoch ms.

action_stateenum | null

Whose move it is (see crm.deals.get).

Values: waiting_us, act_new, overdue_task, scheduled, waiting_them, none

action_sincenumber | null

Since when the prospect is in its action_state, epoch ms; for scheduled, the time of the meeting.

converted_to_deal_idstring | null
converted_atnumber | null
archived_atnumber | null
archived_reasonstring | null
reengaged_activeboolean | null

true while the banner of a prospect that came back (archived and the person wrote again) is unresolved.

reengaged_atnumber | null
merged_into_idstring | null

Set on a duplicate absorbed by a merge: the prospect that kept it.

created_by_idstring | null

Who created the prospect: a member's user id (members.members.list), or an AI position's ai-… id.

created_by_namestring | null

The name of who created the prospect, resolved when the record is read.

Errors

Example

curl "https://api.mb-suite.com/v1/crm/prospects/{prospect_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/crm/prospects/{prospect_id}" \
  -H "Authorization: Bearer $MB_TEST_KEY"
POST/v1/crm/prospects

Create a prospect

crm.prospects.create

WriteSince 2026-11-01

Creates a prospect in the inbox (status new). Link it to an existing person/company by id, or pass person {full_name, email, phone, company_name} and the person and company are created or reused (dedup by email and phone). Without an owner, the Manual source's assignment rule applies if there is one; without a rule, the prospect goes to the owner of its person when they are a member of the organization (not a viewer), and otherwise it is left unassigned (owner_id null), visible to the whole team. Requires create_prospect. A seller with restricted scope can only link, by id, a person and a company they can already see (their own, unassigned, or of a deal of theirs); any other is not found (person_not_found, company_not_found), before anything is written. If they end up as the owner (chosen, or by the Manual source's assignment rule) and the person or company found by person belongs to someone else, outside what they can see, it is denied with 403 prospect_contact_not_visible and no prospect is created; and the response leaves out the person_id and company_id of a contact they cannot see. With an AI position as owner (owner_id ai-…) the agent answers the lead's messages by itself (AI on each one) and may write to them: outside the app that needs a dry run and its confirm_token, like handing a prospect to an AI position with crm.prospects.update; any other owner runs directly.

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. In this one, only when: the owner is an AI position (owner_id ai-…): from then on the agent answers the lead's messages by itself, with AI on each one, and may write to them (as when crm.prospects.update hands a prospect to an AI position).

Scope
crm:write
Permission
Edit in the module · CRM action: create_prospect
MCP tool
crm_prospects_createOn the full surface; on the compact one, mb_execute_operation with id: "crm.prospects.create".
Events it can emit
crm.lead.created

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

Parameters

titlestringbodyrequired

The prospect's title (up to 200 characters).

interest_idstringbodyoptional

Its status in the inbox (crm.prospects.interests.list): interest_not_found otherwise.

person_idstringbodyoptional

Its person (crm.persons.list); or send person to create or reuse one.

company_idstringbodyoptional

Its company (crm.companies.list).

valuenumberbodyoptional

The estimated amount, in currency.

currencystringbodyoptional

ISO 4217 code of value (by default, the inbox's currency).

expected_close_dateintegerbodyoptional

Expected close date, epoch ms.

owner_idstringbodyoptional

The owner: a member's user id or an AI position's ai-… id (an AI owner starts working the lead). Without it, an assignment rule of the manual source may assign one.

source_channelenumbodyoptional

Where it came from (manual by default).

Values: meta, google, tiktok, linkedin, whatsapp, web, manual, csv, generic

source_idstringbodyoptional

The lead source (crm.lead_sources.list).

label_idsarray<string>bodyoptional

Prospect labels (crm.labels.list with entity prospect).

custom_fieldsobjectbodyoptional

Custom fields: slug (crm.custom_fields.list with entity prospect) → value of the field's type.

personobjectbodyoptional

Create or reuse the prospect's person (and their company) from these fields, instead of person_id.

Response

prospect_idstring
person_idstring
company_idstring

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/crm/prospects" \
  -H "Authorization: Bearer $MB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "TITLE",
  "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/crm/prospects" \
  -H "Authorization: Bearer $MB_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "TITLE",
  "dry_run": true
}'
PATCH/v1/crm/prospects/{prospect_id}

Update a prospect

crm.prospects.update

WriteSince 2026-11-01

Updates one or more fields of a prospect: title, interest (its visible status), value, currency, expected close date, owner (only a Manager can transfer; others' owner_id is ignored), labels, custom fields, the ad platform's external_lead_id (null clears it) and is_starred. Changes go to the prospect's changelog. Making an AI position (ai-…) the owner starts its first turn right away (it may write to the lead; not when the prospect's person is marked «Do not contact» or unsubscribed: the AI never writes first to them and waits, with next_run_reason do_not_contact, until they write) and counts as one AI call: outside the app that change needs a dry run and its confirm_token (any other update runs directly), and in the practice organization of test keys it fails with 409 sandbox_external_unavailable and nothing changes. Without AI credits for that first turn in the organization's pool (or with the subscription that pays them blocked), the turn does not call the AI and writes to no one: the prospect goes at once to the position's escalation person (or to whoever the lead source's assignment rule picks), and the prospect returned already shows that person as its owner. Requires edit_prospect (a seller edits their own and the unassigned ones). 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).

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. In this one, only when: the owner changes to an AI position (owner_id ai-…): its first turn runs right away and it may write to the lead.

Scope
crm:write
Permission
Edit in the module
MCP tool
crm_prospects_updateOn the full surface; on the compact one, mb_execute_operation with id: "crm.prospects.update".

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

Parameters

prospect_idstringpathrequired

The prospect, by id (crm.prospects.list or crm.search).

updatesobjectbodyrequired

The fields to change; the rest stay as they are.

Response

prospectobject

Errors

Example

curl -X PATCH "https://api.mb-suite.com/v1/crm/prospects/{prospect_id}" \
  -H "Authorization: Bearer $MB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "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 PATCH "https://api.mb-suite.com/v1/crm/prospects/{prospect_id}" \
  -H "Authorization: Bearer $MB_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "updates": {},
  "dry_run": true
}'
POST/v1/crm/prospects/{prospect_id}/archive

Archive a prospect

crm.prospects.archive

WriteSince 2026-11-01

Archives a prospect (status archived, optional reason): it leaves the inbox and keeps everything; crm.prospects.restore brings it back. Idempotent: changed is false when it already was archived (with that reason). Requires archive_prospect.

Scope
crm:write
Permission
Edit in the module
MCP tool
crm_prospects_archiveOn the full surface; on the compact one, mb_execute_operation with id: "crm.prospects.archive".

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

Parameters

prospect_idstringpathrequired

The prospect, by id (crm.prospects.list or crm.search).

reasonstringbodyoptional

Why it is archived (up to 500 characters): saved on the prospect.

Response

oktrue
changedboolean

false when it already was that way: nothing was written.

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/crm/prospects/{prospect_id}/archive" \
  -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/crm/prospects/{prospect_id}/archive" \
  -H "Authorization: Bearer $MB_TEST_KEY"
POST/v1/crm/prospects/{prospect_id}/restore

Restore an archived prospect to the inbox

crm.prospects.restore

WriteIdempotentSince 2026-11-01

Brings an archived prospect back to the inbox (status reviewing) and clears the archive data. Idempotent: a prospect that is not archived is left as is (changed: false). Requires archive_prospect.

Scope
crm:write
Permission
Edit in the module
MCP tool
crm_prospects_restoreOn the full surface; on the compact one, mb_execute_operation with id: "crm.prospects.restore".

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

Parameters

prospect_idstringpathrequired

The prospect, by id (crm.prospects.list or crm.search).

Response

oktrue
changedboolean

false when it was not archived: nothing was written.

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/crm/prospects/{prospect_id}/restore" \
  -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/crm/prospects/{prospect_id}/restore" \
  -H "Authorization: Bearer $MB_TEST_KEY"
POST/v1/crm/prospects/{prospect_id}/convert

Convert a prospect into a deal

crm.prospects.convert

WriteIdempotentSince 2026-11-01

Creates a deal from the prospect in the given pipeline and stage, assigned to owner_id (a member), with optional title/value/currency overrides; the prospect becomes converted and its activities and conversations move to the deal. Idempotent: an already converted prospect returns its deal. Requires convert_prospect. A seller with restricted scope cannot convert a prospect that is not theirs when its person or company belongs to someone else and is outside what they can see (their own, unassigned, or of a deal of theirs): 403 prospect_contact_not_visible and no deal is created; a Manager or an Admin converts it, or assigns it to them first.

Scope
crm:write
Permission
Edit in the module
MCP tool
crm_prospects_convertOn the full surface; on the compact one, mb_execute_operation with id: "crm.prospects.convert".
Events it can emit
crm.deal.created

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

Parameters

prospect_idstringpathrequired

The prospect, by id (crm.prospects.list or crm.search).

pipeline_idstringbodyrequired

The pipeline of the new deal (crm.pipelines.list).

stage_idstringbodyrequired

A stage of that pipeline: stage_not_in_pipeline otherwise.

owner_idstringbodyrequired

The deal's owner: a member's user id.

titlestringbodyoptional

The deal's title (by default, the prospect's).

valuenumberbodyoptional

The deal's amount (by default, the prospect's).

currencystringbodyoptional

ISO 4217 code of value.

Response

deal_idstring

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/crm/prospects/{prospect_id}/convert" \
  -H "Authorization: Bearer $MB_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "pipeline_id": "PIPELINE_ID",
  "stage_id": "STAGE_ID",
  "owner_id": "OWNER_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/crm/prospects/{prospect_id}/convert" \
  -H "Authorization: Bearer $MB_TEST_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "pipeline_id": "PIPELINE_ID",
  "stage_id": "STAGE_ID",
  "owner_id": "OWNER_ID"
}'
DELETE/v1/crm/prospects/{prospect_id}

Delete a prospect

crm.prospects.delete

IrreversibleSince 2026-11-01

Deletes a prospect; it goes to the 30-day trash. Its person, company and activities are kept. Prefer crm.prospects.archive to just take it out of the inbox. Requires delete_prospect.

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
crm:write and “Allow deletions” (crm:delete in OAuth)
Permission
Edit in the module
MCP tool
crm_prospects_deleteOn the full surface; on the compact one, mb_execute_operation with id: "crm.prospects.delete".

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

Parameters

prospect_idstringpathrequired

The prospect, by id (crm.prospects.list or crm.search).

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/crm/prospects/{prospect_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/crm/prospects/{prospect_id}" \
  -H "Authorization: Bearer $MB_TEST_KEY"
POST/v1/crm/prospects/bulk/archive

Archive many prospects

crm.prospects.bulk.archive

WriteBulk · up to 500Since 2026-11-01

Archives up to 500 prospects with an optional reason. Prospects already archived are left as they are (unchanged) and ids that do not exist are skipped (not_found). A Manager archives any; a seller only their own and the unassigned ones (one foreign id rejects the whole batch with prospects_not_owned). The dry run reads the same prospects and names those that would be archived. Outside the screen it requires a dry run and a confirm_token.

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
crm:write
Permission
Edit in the module
MCP tool
crm_prospects_bulk_archiveOn the full surface; on the compact one, mb_execute_operation with id: "crm.prospects.bulk.archive".

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

Parameters

prospect_idsarray<string>bodyrequired

The prospects (up to 500), by id (crm.prospects.list).

reasonstringbodyoptional

Why they are archived: saved on each prospect.

Response

updatednumber

How many prospects changed.

unchangednumber

How many prospects already were that way: not written.

not_foundarray<string>

The ids that do not exist in the organization (or are merged-away duplicates): skipped.

skippednumber

unchanged + not_found (kept for older clients).

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/crm/prospects/bulk/archive" \
  -H "Authorization: Bearer $MB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "prospect_ids": [
    "PROSPECT_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/crm/prospects/bulk/archive" \
  -H "Authorization: Bearer $MB_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "prospect_ids": [
    "PROSPECT_ID"
  ],
  "dry_run": true
}'
POST/v1/crm/prospects/bulk/interest

Set the interest (visible status) of many prospects

crm.prospects.bulk.update_interest

WriteBulk · up to 500Since 2026-11-01

Sets the interest (the status the inbox shows) of up to 500 prospects. interest_id must be one of crm.prospects.interests.list (any other is interest_not_found). Prospects that already have it are left as they are (unchanged) and ids that do not exist are skipped (not_found). A Manager updates any; a seller only their own and the unassigned ones (prospects_not_owned otherwise). The dry run reads the same prospects. Outside the screen it requires a dry run and a confirm_token.

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
crm:write
Permission
Edit in the module
MCP tool
crm_prospects_bulk_update_interestOn the full surface; on the compact one, mb_execute_operation with id: "crm.prospects.bulk.update_interest".

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

Parameters

prospect_idsarray<string>bodyrequired

The prospects (up to 500), by id (crm.prospects.list).

interest_idstringbodyrequired

Its status in the inbox (crm.prospects.interests.list): interest_not_found otherwise.

Response

updatednumber

How many prospects changed.

unchangednumber

How many prospects already were that way: not written.

not_foundarray<string>

The ids that do not exist in the organization (or are merged-away duplicates): skipped.

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/crm/prospects/bulk/interest" \
  -H "Authorization: Bearer $MB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "prospect_ids": [
    "PROSPECT_ID"
  ],
  "interest_id": "INTEREST_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/crm/prospects/bulk/interest" \
  -H "Authorization: Bearer $MB_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "prospect_ids": [
    "PROSPECT_ID"
  ],
  "interest_id": "INTEREST_ID",
  "dry_run": true
}'
POST/v1/crm/prospects/bulk/owner

Assign many prospects to an owner

crm.prospects.bulk.update_owner

WriteBulk · up to 500Since 2026-11-01

Assigns up to 500 prospects to a member (owner_id, from members.members.list or crm.team.list; null clears the owner) and notifies the new owner once. An AI position is assigned one prospect at a time with crm.prospects.update (it starts its first turn). Prospects that already have that owner are left as they are (unchanged) and ids that do not exist are skipped (not_found). The dry run reads the same prospects. Manager-tier only. Outside the screen it requires a dry run and a confirm_token.

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
crm:write
Permission
Edit in the module
MCP tool
crm_prospects_bulk_update_ownerOn the full surface; on the compact one, mb_execute_operation with id: "crm.prospects.bulk.update_owner".

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

Parameters

prospect_idsarray<string>bodyrequired

The prospects (up to 500), by id (crm.prospects.list).

owner_idstring | nullbodyrequired

The new owner: a member's user id; null leaves them without one.

Response

updatednumber

How many prospects changed.

unchangednumber

How many prospects already were that way: not written.

not_foundarray<string>

The ids that do not exist in the organization (or are merged-away duplicates): skipped.

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/crm/prospects/bulk/owner" \
  -H "Authorization: Bearer $MB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "prospect_ids": [
    "PROSPECT_ID"
  ],
  "owner_id": "OWNER_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/crm/prospects/bulk/owner" \
  -H "Authorization: Bearer $MB_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "prospect_ids": [
    "PROSPECT_ID"
  ],
  "owner_id": "OWNER_ID",
  "dry_run": true
}'
POST/v1/crm/prospects/bulk/labels

Add or remove labels on many prospects

crm.prospects.bulk.update_labels

WriteBulk · up to 500Since 2026-11-01

Adds and/or removes labels (ids from crm.labels.list with entity prospect) on up to 500 prospects. A label that is not a prospect label of the organization is label_not_found. Prospects that already have exactly those labels are left as they are (unchanged) and ids that do not exist are skipped (not_found). A Manager updates any; a seller only their own and the unassigned ones. The dry run reads the same prospects. Outside the screen it requires a dry run and a confirm_token.

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
crm:write
Permission
Edit in the module
MCP tool
crm_prospects_bulk_update_labelsOn the full surface; on the compact one, mb_execute_operation with id: "crm.prospects.bulk.update_labels".

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

Parameters

prospect_idsarray<string>bodyrequired

The prospects (up to 500), by id (crm.prospects.list).

to_addarray<string>bodyoptional

Label ids to add (crm.labels.list with entity prospect), up to 20; send to_add, to_remove or both.

to_removearray<string>bodyoptional

Label ids to remove (crm.labels.list with entity prospect), up to 20; send to_add, to_remove or both.

Response

updatednumber

How many prospects changed.

unchangednumber

How many prospects already were that way: not written.

not_foundarray<string>

The ids that do not exist in the organization (or are merged-away duplicates): skipped.

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/crm/prospects/bulk/labels" \
  -H "Authorization: Bearer $MB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "prospect_ids": [
    "PROSPECT_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/crm/prospects/bulk/labels" \
  -H "Authorization: Bearer $MB_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "prospect_ids": [
    "PROSPECT_ID"
  ],
  "dry_run": true
}'
POST/v1/crm/prospects/bulk/delete

Delete many prospects

crm.prospects.bulk.delete

IrreversibleBulk · up to 500Since 2026-11-01

Deletes up to 500 prospects; each goes to the 30-day trash and can be restored one by one. Requires bulk_delete_prospects (Manager-tier). Outside the screen it requires a dry run and a confirm_token.

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
crm:write and “Allow deletions” (crm:delete in OAuth)
Permission
Edit in the module
MCP tool
crm_prospects_bulk_deleteOn the full surface; on the compact one, mb_execute_operation with id: "crm.prospects.bulk.delete".

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

Parameters

prospect_idsarray<string>bodyrequired

The prospects (up to 500), by id (crm.prospects.list).

Response

deletednumber

How many prospects were deleted (each one goes to the 30-day trash).

not_foundarray<string>

The ids that do not exist in the organization: nothing to delete.

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/crm/prospects/bulk/delete" \
  -H "Authorization: Bearer $MB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "prospect_ids": [
    "PROSPECT_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/crm/prospects/bulk/delete" \
  -H "Authorization: Bearer $MB_TEST_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "prospect_ids": [
    "PROSPECT_ID"
  ],
  "dry_run": true
}'
GET/v1/crm/prospects/interests

List the prospect statuses (interests)

crm.prospects.interests.list

ReadIdempotentSince 2026-11-01

Lists the statuses a prospect can have in the inbox (called interests in the API: interested, cold… and the ones the organization added), in their order, with id, name and color. interest_id of crm.prospects.create, crm.prospects.update and crm.prospects.bulk.update_interest is one of these ids.

Scope
crm:read
Permission
View the module
MCP tool
crm_prospects_interests_listOn the full surface; on the compact one, mb_execute_operation with id: "crm.prospects.interests.list".

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

Parameters

No parameters.

Response

dataarray<object>

Errors

Example

curl "https://api.mb-suite.com/v1/crm/prospects/interests" \
  -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/crm/prospects/interests" \
  -H "Authorization: Bearer $MB_TEST_KEY"