Skip to content
Inkbox

Inkbox

DocsPricingBlogContact
GuidesAPI Reference

Ctrl K

GuidesAPI Reference

Jump to

Texts

List, search, and manage SMS/MMS text messages for your phone numbers. The text API is conversation-centric: 1:1 SMS/MMS and beta group MMS use the same endpoints and response objects.

All text endpoints are scoped to a phone number: /numbers/{phone_number_id}/texts/...

Path parameters

ParameterTypeDescription
phone_number_idUUIDUnique identifier of the phone number

Send text POST

POST /numbers/{phone_number_id}/texts

Send an outbound message from one of your phone numbers. Pass to as a string for 1:1 SMS/MMS, as a list of 1-8 E.164 numbers for a conversation send, or pass conversation_id to reply into an existing conversation. Lists with 2 or more resolved recipients are sent as beta group MMS.

Beta: Group MMS and conversation sends are beta. Some carriers may reject group chats or MMS from 10DLC numbers even when the sender is ready and recipients have opted in.

The legacy 1:1 request shape still works unchanged:

JSONJSON

Beta group MMS uses the same endpoint:

JSONJSON

To reply into an existing conversation, pass conversation_id instead of to. The server resolves the conversation to its participants and applies the same 1:1 or group routing based on recipient count.

JSONJSON

Preconditions

  • Sender warm-up. A newly provisioned local number can take around 10-15 minutes for its 10DLC campaign to register downstream. While sms_status is "pending", sends return 409 sender_sms_pending.
  • Recipient opt-in. Every recipient must opt in before you can text them. Sending to a recipient who has not opted in returns 403 recipient_not_opted_in; sending to a recipient who later sent STOP returns 403 recipient_opted_out.
  • Contact rules. Rules configured on the sending number still apply. Multi-recipient sends are all-or-nothing: one blocked or non-opted-in recipient rejects the request.
  • Group destination region. Group MMS recipients must be US or Canadian E.164 numbers.
  • Beta carrier behavior. Group MMS and MMS over 10DLC are still carrier-dependent; some carriers may reject group chats or MMS from 10DLC numbers.

Rate limits

A phone number on Inkbox's default 10DLC campaign can send to at most 100 recipients per rolling 24-hour window. A 3-recipient group message counts as 3 recipient sends. Registering your own brand and campaign lifts this cap to the carrier-assigned tier; see 10DLC registration.

When the cap is reached, 429 responses include:

HeaderDescription
X-RateLimit-LimitMaximum recipient sends allowed per number per 24 hours (100 on the default campaign)
X-RateLimit-RemainingRemaining recipient sends in the current window
X-RateLimit-ResetISO 8601 timestamp at which the oldest send in the window will fall off
Retry-AfterSeconds until at least one slot frees up

Request body

FieldTypeRequiredDescription
tostring | string[]ConditionalOne E.164 destination for 1:1, or a list of 1-8 E.164 destinations. Lists with 2 or more recipients send beta group MMS. Mutually exclusive with conversation_id
conversation_idUUID | nullConditionalExisting conversation to reply into. The server resolves it to the conversation participants. Mutually exclusive with to
textstring | nullNoMessage body, up to 1600 characters. Required unless media_urls has at least one item
media_urlsstring[] | nullNoPublicly fetchable media URLs to attach, up to 10 entries. Required unless text is present

Response (201)

1:1 responses keep the legacy fields populated and add conversation-aware fields:

JSONJSON

Group responses keep the same object shape. remote_phone_number and legacy timestamp/error fields are null; use conversation_id, the message-level delivery_status rollup, and recipients[].

JSONJSON

Group outbound — remote_phone_number is null (no single remote party), top-level delivery_status is the message-level rollup, legacy timestamp/error fields stay null, and recipients carries one entry per addressee:

JSONJSON

The final delivery state of every leg is reported asynchronously through text.* webhooks. For group sends, lifecycle events fire once per recipient with data.recipient_phone_number identifying the leg.

Error responses

StatusDescription
400Phone number not active
403recipient_not_opted_in - one or more recipients have not texted START to a number in your organization
403recipient_opted_out - one or more recipients texted STOP and can no longer be messaged
403Send blocked by a contact rule on the sending number
404Phone number or conversation_id not found
409sender_sms_pending - local number's 10DLC registration is still propagating
409Sending number is not eligible to send SMS/MMS
422Invalid request body, no text/media content, both/neither to and conversation_id, duplicate recipients, too many recipients, or unsupported group destination
42924-hour recipient-send limit reached on this number; respect the Retry-After header

List texts GET

GET /numbers/{phone_number_id}/texts

List text messages for a phone number, newest first. Group messages appear alongside 1:1 messages.

Query parameters

ParameterTypeDefaultDescription
limitinteger50Number of results (1-200)
offsetinteger0Pagination offset
is_readboolean-Filter by read state. Omit for all messages
is_blockedboolean-Filter by blocked state. true returns only blocked rows, false returns only non-blocked rows, and omitting it applies the caller's default visibility

Identity-scoped API keys never see contact-rule-blocked texts, regardless of is_blocked. Admin API keys and human sessions see blocked and non-blocked texts by default; use is_blocked=true for an admin-side blocked listing.

Response (200)

JSONJSON

Error responses

StatusDescription
403Phone number belongs to a different organization
404Phone number not found
422Validation failed: missing both text and media_urls, to list outside 1–8 recipients, group send to a non-US/CA number, media_urls longer than 10, or text longer than 1600 characters

Get text GET

GET /numbers/{phone_number_id}/texts/{text_id}

Get a single text message by ID.

Path parameters

ParameterTypeDescription
text_idUUIDUnique identifier of the text message

Response (200)

Returns a TextMessage object.

MMS messages have type: "mms" and a media array. Each media item includes a content_type, size in bytes, and a URL. URLs returned for stored inbound MMS media are presigned and expire after 1 hour.

Error responses

StatusDescription
404Text not found, wrong phone number, or wrong organization

Update text PATCH

PATCH /numbers/{phone_number_id}/texts/{text_id}

Update a text message, for example to mark it as read.

Path parameters

ParameterTypeDescription
text_idUUIDUnique identifier of the text message

Request body

FieldTypeRequiredDescription
is_readbooleanNoMark as read (true) or unread (false)

Request example

JSONJSON

Response (200)

Returns the updated TextMessage object.

Error responses

StatusDescription
404Text not found, wrong phone number, or wrong organization

Search texts GET

GET /numbers/{phone_number_id}/texts/search

Full-text search across text message bodies for a phone number. Results are ranked by relevance.

Query parameters

ParameterTypeDefaultDescription
qstring-Search query (required, 1-500 characters)
limitinteger50Number of results (1-200)
is_blockedboolean-Filter by blocked state. true searches only blocked rows, false searches only non-blocked rows, and omitting it applies the caller's default visibility

Identity-scoped API keys never see contact-rule-blocked texts in search results. Admin API keys and human sessions see everything by default; pass is_blocked=false to exclude blocked spam from search results or is_blocked=true to search only blocked rows.

Response (200)

Returns a list[TextMessage] matching the query.

Error responses

StatusDescription
403Phone number belongs to a different organization
404Phone number not found
422Missing or invalid q parameter

List conversations GET

GET /numbers/{phone_number_id}/texts/conversations

List conversation summaries ordered by most recent message, with latest-message preview and unread count. By default this endpoint returns only 1:1 conversations so existing clients keep the same sidebar behavior. Pass include_groups=true to include group conversations.

Query parameters

ParameterTypeDefaultDescription
limitinteger50Number of results (1-200)
offsetinteger0Pagination offset
include_groupsbooleanfalseInclude group conversations in the listing
is_blockedboolean-Filter by blocked state of messages. true summarizes blocked rows only, false summarizes non-blocked rows only, and omitting it applies the caller's default visibility

With is_blocked=false, latest previews, ordering, unread counts, and totals are computed from non-blocked rows only, so blocked-only conversations drop out. Identity-scoped API keys never see blocked rows in conversation summaries.

Response (200)

Each row carries the conversation's id, the participant list, and an is_group flag. For 1:1 rows, remote_phone_number is the single participant; for group rows it's null (the participant set is the source of truth). latest_has_media is the reliable signal that the latest message carried media — derived from the message's media column, since carriers tag many text-only messages as MMS at the wire.

JSONJSON

Error responses

StatusDescription
403Phone number belongs to a different organization
404Phone number not found

Get conversation GET

GET /numbers/{phone_number_id}/texts/conversations/{key}

Get all messages in a conversation, newest first. {key} accepts the conversation UUID for any conversation. For 1:1 threads, the key can also be the remote phone number, short code, or sender ID.

Group conversations must be addressed by UUID. Use the id from the conversation summary or conversation_id from any message in the group.

Path parameters

ParameterTypeDescription
keystringConversation UUID, or a 1:1 remote phone number / short code / sender ID

Query parameters

ParameterTypeDefaultDescription
limitinteger50Number of results (1-200)
offsetinteger0Pagination offset

Identity-scoped API keys see only non-blocked rows in the thread. Admin API keys and human sessions see blocked and non-blocked rows merged inline, with each row tagged by is_blocked.

Response (200)

Returns a list[TextMessage] for the conversation.

Error responses

StatusDescription
400Conversation key is malformed (not a UUID and not a recognized phone number)
403Phone number belongs to a different organization
404Phone number not found, or no conversation matches the key on this phone number

Update conversation PATCH

PATCH /numbers/{phone_number_id}/texts/conversations/{key}

Bulk-update the read state for all non-blocked messages in a conversation.

Path parameters

ParameterTypeDescription
keystringConversation UUID, or a 1:1 remote phone number / short code / sender ID

Request body

FieldTypeRequiredDescription
is_readbooleanYesMark all messages as read (true) or unread (false)

Request example

JSONJSON

Response (200)

JSONJSON

For 1:1 conversations, remote_phone_number is populated for legacy callers. For group conversations, it is null and conversation_id is the stable key. updated_count: 0 means no messages needed updating.

Error responses

StatusDescription
400Conversation key is malformed (not a UUID and not a recognized phone number)
403Phone number belongs to a different organization
404Phone number not found, or no conversation matches the key on this phone number
422Missing or invalid is_read

Text message object

FieldTypeDescription
idstring (UUID)Message ID
directionstring"inbound" or "outbound"
local_phone_numberstringYour Inkbox number (E.164)
remote_phone_numberstring | nullLegacy 1:1 remote party. Populated for 1:1 and inbound messages; null for outbound group messages
textstring | nullMessage body. Null for MMS-only messages
typestring"sms" or "mms". Group sends are always "mms"
mediaarray | nullMedia attachments (MMS only). Each item has content_type, size, and url
is_readbooleanWhether the message has been read
delivery_statusstring | nullFor outbound messages: "queued", "sent", "delivered", "delivery_failed", "delivery_unconfirmed", or "sending_failed". Null for inbound. On groups this is a rollup across recipients[] (the lowest lifecycle rank present; "delivered" is preferred at the terminal tier on mixed-outcome ties) — treat recipients[].delivery_status as authoritative per-leg
originstringHow the message was created. "user_initiated" for messages sent via the API
error_codestring | nullLegacy 1:1 delivery error code. Null for inbound and group messages; use recipients[].error_code for group
error_detailstring | nullLegacy 1:1 delivery error detail. Null for inbound and group messages; use recipients[].error_detail for group
sent_atstring (ISO 8601) | nullLegacy 1:1 handoff timestamp. Null for inbound and group messages; use recipients[].sent_at for group
delivered_atstring (ISO 8601) | nullLegacy 1:1 confirmed-delivery timestamp. Null for inbound and group messages; use recipients[].delivered_at for group
failed_atstring (ISO 8601) | nullLegacy 1:1 failure timestamp. Null for inbound and group messages; use recipients[].failed_at for group
conversation_idstring (UUID) | nullStable conversation key for 1:1 and group threads
sender_phone_numberstring | nullSender for inbound messages. Null for outbound messages because the sender is local_phone_number
recipientsarray | nullPer-recipient delivery state for outbound messages. One entry for 1:1; 2-8 entries for group; null for inbound
is_blockedbooleanWhether the message was rejected by a contact rule or by default-block in whitelist mode. Identity-scoped API keys never receive rows where this is true
created_atstring (ISO 8601)Creation timestamp
updated_atstring (ISO 8601)Last update timestamp

Recipient object

recipients[] is only present on outbound text messages.

FieldTypeDescription
recipient_phone_numberstringRecipient phone number in E.164 format
delivery_statusstring | nullPer-recipient delivery status
carrierstring | nullCarrier reported for the recipient, when available
line_typestring | nullCarrier-reported line type, when available
error_codestring | nullCarrier or Inkbox error code for this recipient
error_detailstring | nullHuman-readable detail accompanying error_code
sent_atstring (ISO 8601) | nullWhen this recipient was handed off for delivery
delivered_atstring (ISO 8601) | nullWhen delivery to this recipient was confirmed
failed_atstring (ISO 8601) | nullWhen delivery to this recipient failed

Conversation summary object

FieldTypeDescription
remote_phone_numberstring | nullLegacy 1:1 participant. Null for group conversations
idstring (UUID) | nullConversation UUID. Use this as the canonical key for group conversations
participantsstring[] | nullRemote participants in the conversation
is_groupboolean | nullWhether the conversation has more than one remote participant
latest_textstring | nullLatest message body preview
latest_directionstringDirection of the latest message
latest_typestring"sms" or "mms" for the latest message
latest_has_mediabooleanWhether the latest message actually has media attachments. This is separate from latest_type because group and carrier-routed messages can be "mms" without attachments
latest_message_atstring (ISO 8601)Latest message timestamp
unread_countintegerUnread message count in the summarized view
total_countintegerTotal message count in the summarized view

Inkbox

Copyright © 2026 Inkbox

This site is protected by reCAPTCHA.

Google Privacy Policy and Terms of Service apply.

Website

Inkbox

Copyright © 2026 Inkbox

This site is protected by reCAPTCHA.

Google Privacy Policy and Terms of Service apply.

Website

Y CombinatorBacked by Y Combinator
Texts