Menu

API reference · Phones

SMS

crm_phones · sms · 2 operations

GET/v1/phones/sms

List the SMS sent and received on the organization's lines

crm_phones.sms.list

ReadIdempotentSince 2026-11-01

Lists the text messages sent and received on the organization's phone lines, newest first, paginated by cursor (limit up to 200): line, direction (inbound or outbound), from, to, body, segments, delivery status (queued, sent, delivered, undelivered, failed, received), the CRM person matched by number (person_id), who sent it and what it cost the Phones balance in USD cents. Filter by one of line_id, person_id or direction, plus a since/until range on the creation time (ms). Requires view access to Phones.

Scope
crm_phones:read
Permission
View the module
MCP tool
crm_phones_sms_listOn the full surface; on the compact one, mb_execute_operation with id: "crm_phones.sms.list".

Declared cost: up to 202 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.

line_idstringqueryoptional

Only the messages of this line. The phone line: an id from crm_phones.lines.list.

person_idstringqueryoptional

Only the messages with this CRM person (crm.persons.list), linked by their number when the message came or went.

directionenumqueryoptional

inbound or outbound.

Values: inbound, outbound

sinceintegerqueryoptional

Only the messages from this time on (epoch ms, inclusive).

untilintegerqueryoptional

Only the messages up to this time (epoch ms, inclusive).

Response

dataarray<object>
has_moreboolean
next_cursorstring

Errors

Example

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

Send an SMS from a phone line

crm_phones.sms.send

WriteSince 2026-11-01

Sends a text message (body, 1 to 1600 characters; long messages go as several billed segments) from one of the organization's lines (line_id) to a number in E.164 format (to, e.g. +5491155551234). The line must be active (line_not_active) and able to send SMS (sms_not_supported). The estimated cost (segments × the destination country's rate) is charged to the Phones balance, which must cover it (insufficient_balance, with the estimate in details); the network can still reject it (external_rejected, with Twilio's code in details.provider_code), throttle it (external_rate_limited) or fail without a clear answer (external_outcome_unknown: the SMS may have gone out, check crm_phones.sms.list before sending it again). An SMS starts the contact: when the number belongs to a CRM person marked «Do not contact» or unsubscribed (found by the number, in all its forms), nothing is sent or charged and the answer is 409 do_not_contact, with the number and why in details.recipients and details.overridable. Only a person of the team can confirm it, on a closed basis (do_not_contact_override: about their account, a charge or support, or because the person asked us to write), with a reason outside the app (400 do_not_contact_reason_required); an AI agent's API key cannot (403 do_not_contact_override_not_allowed, and details.overridable is false). When their last SMS to this line, from that number, came after they were marked (within the last 24 hours for a mark from before 2026-10-16), it is a reply and goes out without confirmation. When it goes out to one of them, the response carries do_not_contact (the recipients and allowed_as: reply or override). The message is stored as outbound, linked to the CRM person with that number, and fires the crm_phones.sms.sent webhook event. The dry run checks the line, its SMS capability, the balance and «Do not contact» (the same 409, or why it goes out anyway), and says the segments and the estimated cost, without calling the phone network. This reaches a real phone and costs money: send only what the person asked for, and retry with the same Idempotency-Key, never as a new request. Returns the stored message (id, segments, cost). Requires edit access to Phones.

Instructions for agents

Confirm the destination number and the exact text with the person before sending: an SMS cannot be recalled.

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_phones:write
Permission
Edit in the module
MCP tool
crm_phones_sms_sendOn the full surface; on the compact one, mb_execute_operation with id: "crm_phones.sms.send".
Events it can emit
crm_phones.sms.sent

Declared cost: up to 46 reads and 3 writes per call (they count against the daily quota). Touches an external platform (twilio): it counts against the external operations quota.

Parameters

line_idstringbodyrequired

The line it goes out from (active, with SMS). The phone line: an id from crm_phones.lines.list.

tostringbodyrequired

The destination number in E.164 (+5491155551234).

bodystringbodyrequired

The message (up to 1600 characters; every 160 or so is one billed segment).

do_not_contact_overrideobjectbodyoptional

Only for a recipient marked «Do not contact» or unsubscribed (409 do_not_contact names them): a person of the team confirms the message, on one of two bases. An AI agent's API key cannot confirm it (403 do_not_contact_override_not_allowed) and a WhatsApp marketing template never goes to them. Without it nothing is sent to them; a reply to what they wrote after being marked needs no confirmation (each send says when).

Response

idstring

The carrier's message id (SM…).

line_idstring
line_phone_numberstring
directionstring
fromstring
tostring
bodystring
num_segmentsnumber
statusstring
error_codenumber | null

When it failed: the carrier's error code.

error_messagestring | null
person_idstring | null
sent_by_user_idstring | null
client_cost_centsnumber
created_atnumber
updated_atnumber
do_not_contactobject

Only when it went out to a person marked «Do not contact» or unsubscribed: who, why, and whether it answered their last SMS to this line or a person of the team confirmed it.

Errors

Example

curl -X POST "https://api.mb-suite.com/v1/phones/sms" \
  -H "Authorization: Bearer $MB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "line_id": "LINE_ID",
  "to": "TO",
  "body": "BODY",
  "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. In the practice organization this operation is not simulated (it reaches another platform): it answers 409 sandbox_external_unavailable.