Email and SMS
Read conversations, prepare replies, send messages, and take over with an API key.
Use the same email address and SMS number configured in your workspace. Messages use the normal InboxTender delivery path, including SMS consent, STOP handling, carrier readiness, sender identity, and sending limits.
API activity is recorded internally with the key's name and ID. InboxTender does not add an agent label to message bodies or change the customer-facing sender. The caller supplies the message text. Existing business identification and SMS opt-out instructions still apply.
Set up an agent
Create a named key in Assistant → API access. Choose Read messages, Draft replies for review, or Manage and send messages. Existing keys keep their contacts-only permissions. Revoke a key there to stop new API operations.
Install the InboxTender skill in your agent's skill
folder as inboxtender/SKILL.md. Set INBOXTENDER_API_KEY in the agent's environment.
No CLI, npm package, or MCP server is required.
The skill describes a workflow; your agent must be running to execute it. This version supports polling, with no outgoing event subscriptions.
Permissions
| Scope | Allows |
|---|---|
contacts:read | Read contacts |
contacts:write | Create or merge contacts |
messages:read | Read email/SMS conversations, messages, and pending drafts |
messages:draft | Create reply drafts and dismiss drafts |
messages:send | Start messages, send replies, and approve drafts |
conversations:manage | Claim/release conversations and mark them handled |
Drafting, sending, and draft decisions also require conversations:manage.
A key without messages:send cannot approve its own drafts. A workspace member
can review and approve them in the existing dashboard.
GET /api/v1/me returns the authenticated workspaceId, keyId, and scopes.
All data belongs to that workspace; never supply a workspace ID in the body.
Read conversations
GET /api/v1/conversations?channel=sms&limit=50&cursor=…
GET /api/v1/conversations?channel=email&limit=50&cursor=…
GET /api/v1/conversations/:id
GET /api/v1/conversations/:id/messages?limit=50&cursor=…
GET /api/v1/drafts?limit=50&cursor=…Conversation IDs are opaque strings such as sms:+15555550101 or email:….
URL-encode the entire ID when inserting it into a path.
Lists return conversations, messages, or drafts, plus nextCursor.
Pass that cursor unchanged until it is null. Limits are integers from 1 to 100,
defaulting to 50. A page can be empty while its cursor still advances.
Conversation lists use stable conversation-key order, not last-activity order.
Each conversation includes id, channel, contactId, name, peer,
aiPaused, managedByApiKeyId, optedOut, system, and lastMessageAt.
The ownership fields are internal operator information.
Messages are newest first within each source. SMS includes both directions.
For email, fetch both direction=inbound and direction=outbound, keeping
a separate cursor for each, then merge by at. Email defaults to inbound.
Messages include id, conversationId, direction, text, at, and optional
subject and status. These APIs handle text; they do not upload attachments.
For polling, start a fresh conversation listing on each sweep, compare activity, and read new messages until you reach IDs already processed. Persist message IDs in your agent's own storage. Pagination cursors are for finishing a sweep, not subscriptions. Gmail access covers mail routed into InboxTender and its configured sending account; it does not synchronize the entire Gmail mailbox.
Claim a conversation
POST /api/v1/conversations/:id/takeover
{ "paused": true }This pauses the built-in assistant, stops scheduled follow-ups, and assigns the
conversation to the calling API key. Another agent or a human takeover causes a
409 conflict. A workspace member can take control using the dashboard.
Claim before writing a reply, creating a draft, deciding a draft, or marking a conversation handled. A new outbound message claims its conversation automatically. API writes check ownership again inside the transaction.
To hand control back to the built-in assistant, use the same endpoint with
{"paused": false}. Resolve pending drafts and queued or uncertain sends first.
Releasing control does not recreate cancelled follow-ups.
Draft or send a reply
POST /api/v1/conversations/:id/drafts
{ "text": "The blue model is available. Would you like to see it tomorrow?" }
POST /api/v1/conversations/:id/replies
{ "text": "The blue model is available. Would you like to see it tomorrow?" }Draft creation leaves a pending reply for review. Sending queues it immediately. Both supersede older pending replies in the conversation and stop its follow-ups. SMS replies allow up to 1,600 characters; email replies allow up to 10,000. Replying to an outbound-only email thread requires the recipient's first inbound reply; use a new email when starting another message before that happens.
POST /api/v1/drafts/:id/approve
{ "text": "Optional edited reply" }
POST /api/v1/drafts/:id/dismiss
{}
POST /api/v1/conversations/:id/handled
{}Approve with {} to keep the draft text. Approval preserves existing freshness,
appointment, consent, and delivery checks. A superseded draft can return an
operation with status: "dismissed" without sending anything. Marking handled
clears pending replies and follow-ups while keeping your claim.
Start a message
POST /api/v1/messages
{ "channel": "sms", "to": "+15555550101", "text": "Your order is ready.", "purpose": "service" }SMS requires existing consent evidence or an eligible inbound conversation.
purpose defaults to service; use marketing for promotional messages.
The API cannot grant consent. The workspace's existing consent workflow handles it.
First-contact and marketing texts retain business identification and STOP instructions.
POST /api/v1/messages
{ "channel": "email", "to": "customer@example.com", "subject": "Your order", "text": "Your order is ready." }Starting a message sends it. These endpoints do not expose bulk campaigns.
Retry and verify delivery
Every messaging POST requires an Idempotency-Key header containing 1–100
characters. Generate one unique value for each intended action, store it before
sending, and reuse it with the identical request after a timeout. Reusing a key
for another action or body returns 409 conflict. Receipts are scoped to the API
key and retained with the workspace.
curl 'https://api.inboxtender.com/api/v1/messages' \
-H "Authorization: Bearer $INBOXTENDER_API_KEY" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: order-123-ready-v1' \
--data '{"channel":"sms","to":"+15555550101","text":"Your order is ready."}'Writes return { "operation": … }. The operation has id, operation,
createdAt, actor, conversationId, status, and, when applicable, draftId
or outboundId. actor records the calling agent's API key internally.
GET /api/v1/operations/:idOnly the key that created the operation can fetch it. A retry of the original POST also returns that operation with its current status.
| Status | Meaning |
|---|---|
pending | A draft awaits review |
queued, sending | Sending is in progress; a 202 response is not proof of delivery |
sent | The sending provider accepted the message; this does not prove it was read or reached the recipient |
failed | Sending failed or the draft was reopened; inspect the dashboard before approving another attempt |
unknown | The provider may have accepted it; reconcile in the dashboard before attempting another send |
dismissed | The draft was dismissed or superseded |
completed | A management action completed |
Follow Retry-After on 429. On 401, stop and replace or restore the key.
On 403 insufficient_scope, obtain an appropriately scoped key from the owner.
On ownership conflicts, stop changing that conversation until an operator
releases it. Invalid message content and existing channel restrictions return
422 with the underlying error code and message.