textbee Logotextbee.dev
Plans from $9.99/mo.View Plans
Documentation

Agent quickstart

The two textbee API endpoints an AI agent or automation needs: account-level send and account-level message history with cursor polling. Copy-paste curl and SDK examples.

Everything an AI agent or automation needs from textbee is two endpoints: one to send, one to read. Both are account-level, so there is no device id to manage. Authenticate every request with the x-api-key header using a key from the dashboard.

If your agent speaks MCP, use the MCP server instead of calling these directly. This page is for HTTP-level integrations and for LLMs writing textbee code.

Send an SMS

POST https://api.textbee.dev/api/v1/gateway/send-sms
curl -X POST https://api.textbee.dev/api/v1/gateway/send-sms \
  -H 'Content-Type: application/json' \
  -H 'x-api-key: YOUR_API_KEY' \
  -d '{
    "recipients": ["+15550100123"],
    "message": "Hello from textbee"
  }'
  • recipients (array, required): phone numbers in E.164 format with the country code.
  • message (string, required): the text to send.
  • deviceId (string, optional): omit it. textbee picks your default device, otherwise the enabled device with the most recent heartbeat. Pass it only to force a specific phone.
  • simSubscriptionId (number, optional): which SIM on a dual-SIM phone.
  • scheduledAt (ISO 8601, optional): send later instead of now.

The response includes an smsBatchId when the account uses the SMS queue. Keep it: it is how you check delivery.

With the JavaScript SDK:

pnpm add @textbee/sdk
import { Textbee } from '@textbee/sdk'

const textbee = new Textbee({ apiKey: process.env.TEXTBEE_API_KEY })

const result = await textbee.sendSms({
  recipients: ['+15550100123'],
  message: 'Hello from textbee',
})
// result.smsBatchId when the account uses the SMS queue

Read messages

GET https://api.textbee.dev/api/v1/gateway/messages

One endpoint for every device on the account. The useful filters for agents:

  • direction: received for inbound only (replies, verification codes), sent to review outgoing messages and their delivery status, all for both.
  • smsBatchId: only messages from one send, using the smsBatchId the send returned. This is the delivery-status lookup: each row carries a status (pending, dispatched, sent, delivered, failed, unknown, received). delivered, failed, and unknown are final.
  • search: free-text match across the message body and the other party's number.
  • from / to: time window, ISO 8601 with an explicit timezone. from is inclusive, to exclusive, so consecutive windows never double-count a message.
  • order: desc (default, newest first) or asc to walk forward when polling.
  • cursor: opaque position from a previous response's meta.nextCursor.
curl "https://api.textbee.dev/api/v1/gateway/messages?direction=received&limit=25" \
  -H 'x-api-key: YOUR_API_KEY'

Check the delivery of a send:

curl "https://api.textbee.dev/api/v1/gateway/messages?smsBatchId=BATCH_ID_FROM_SEND" \
  -H 'x-api-key: YOUR_API_KEY'

Poll for new messages without duplicates

Webhooks are the push option (see Webhooks); this is the reliable pull option:

  1. First call: GET /gateway/messages?direction=received&order=asc&from=2026-08-01T00:00:00Z
  2. Follow meta.nextCursor until meta.hasMore is false.
  3. On the next poll, resume from the last nextCursor you saw.

The cursor is your resume token: no re-read pages, no missed messages, no duplicates. The SDK wraps this as an async iterator:

for await (const message of textbee.iterateMessages({ direction: 'received' })) {
  handle(message)
}

Use only the endpoints on this page. Older device-scoped routes still work for existing integrations but are deprecated and should never appear in new code.

Rate limits and quotas

Sends count against your plan's daily and monthly quotas, enforced server-side. A send over quota fails with HTTP 429 and a body containing hasReachedLimit: true plus your remaining counts. Do not retry those automatically; the quota does not reset because you retried.

Next Steps

  • MCP server - The same capabilities as tools for Claude, Cursor, and other MCP clients
  • Webhooks - Get pushed incoming messages instead of polling
  • API reference - Every field of every endpoint

Need help? Check our FAQ or contact support.