Documentation
Developer API
Message send and status contracts for the current Textree alpha API.
curl https://api.texttree.ai/api/v1/messages \
-H "Authorization: Bearer $TEXTREE_KEY" \
-H "Content-Type: application/json" \
-d '{"phone_number":"+15551234567","body":"Hello"}' Developer API
The current JSON API is intentionally narrow. It is focused on one production-critical path: queueing outbound SMS and checking its status.
Base URL
Local Phoenix development runs at http://localhost:4001.
All documented developer endpoints live under /api/v1.
Authentication
Authenticated API calls require a Textree-issued bearer access token. The same local identity model is used for the browser app, developer API, and MCP routes.
Authorization: Bearer <textree_access_token>
Accept: application/json
POST /api/v1/messages requires messages:write. Number inventory endpoints
require numbers:read or numbers:write. Email, Google, wallet, and agent
identities are normalized into the same local Textree identity before
authorization.
Health
GET /api/v1/health
This route is public and is useful for deployment checks and local smoke tests.
Queue an outbound message
POST /api/v1/messages
Request body
{
"phone_number": "+15551234567",
"body": "Your verification code is 482019",
"estimated_cost_cents": 2,
"idempotency_key": "msg_2026_04_26_0001",
"metadata": {
"campaign": "alpha-invite",
"source": "api"
}
}
Fields
phone_number: required E.164 recipient phone numberbody: required string, 1 to 1600 charsestimated_cost_cents: optional positive integer, defaults to the configured SMS costidempotency_key: optional string, 8 to 128 chars, scoped per usermetadata: optional JSON object
phone_number is the V1 recipient field. Do not send to unless a future API version explicitly documents it.
curl
curl https://api.texttree.ai/api/v1/messages \
-H "Authorization: Bearer $TEXTREE_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"phone_number": "+15551234567",
"body": "Your verification code is 482019",
"idempotency_key": "msg_2026_04_26_0001"
}'
Success responses
Newly queued messages return 202 Accepted:
{
"message": {
"id": "8f3d0f4f-5ab3-4db9-bf6a-92c72bc1f2bb",
"status": "queued",
"phone_number": "+15551234567",
"body": "Your verification code is 482019",
"provider": "messaging_provider",
"consent_status": "missing",
"external_id": null,
"estimated_cost_cents": 2,
"idempotency_key": "msg_2026_04_26_0001",
"metadata": {
"campaign": "alpha-invite",
"source": "api"
},
"inserted_at": "2026-04-26T20:44:12Z",
"updated_at": "2026-04-26T20:44:12Z",
"links": {
"self": "/api/v1/messages/8f3d0f4f-5ab3-4db9-bf6a-92c72bc1f2bb"
}
},
"replayed": false
}
If the same user replays the same idempotency_key with the same message payload, Textree returns
200 OK with the existing message and "replayed": true.
Error responses
422with{"error":"validation_failed","details":...}when the body is malformed403with{"error":"workspace_suppressed"}when the recipient is blocked by a workspace suppression402with{"error":"spend_limit_exceeded"}when the current spend cap would be exceeded409with{"error":"idempotency_conflict"}when an idempotency key is reused with a different recipient, body, or cost
Fetch message status
GET /api/v1/messages/:id
This returns the same message envelope used in create responses.
The current message status lifecycle is:
queueddispatchingsentdeliveredfailedblocked
external_id is populated once provider-facing execution has a stable provider identifier.
Status example
curl https://api.texttree.ai/api/v1/messages/8f3d0f4f-5ab3-4db9-bf6a-92c72bc1f2bb \
-H "Authorization: Bearer $TEXTREE_ACCESS_TOKEN"
{
"message": {
"id": "8f3d0f4f-5ab3-4db9-bf6a-92c72bc1f2bb",
"status": "delivered",
"phone_number": "+15551234567",
"estimated_cost_cents": 2,
"links": {
"self": "/api/v1/messages/8f3d0f4f-5ab3-4db9-bf6a-92c72bc1f2bb"
}
}
}
Before you send
The message API is not self-bootstrapping yet. Before this endpoint can succeed for a new workspace, an operator must:
- authenticate through Textree and include a token with
messages:write - confirm the recipient is not under an active workspace suppression
- set an active spend limit in
/app - configure a test sender or live sender number
Numbers API
GET /api/v1/numbers requires numbers:read.
POST /api/v1/numbers requires numbers:write and buys a number through
the Textree messaging provider boundary. Live buys remain blocked unless the deployment
explicitly enables the live-number-buy guardrail.
curl https://api.texttree.ai/api/v1/numbers \
-H "Authorization: Bearer $TEXTREE_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"area_code": "415",
"friendly_name": "Support line"
}'
Successful buys return 201 Created:
{
"number": {
"id": "b86fbe4d-2b92-4664-8e91-d2ed1d37f827",
"number": "+14155550123",
"friendly_name": "Support line",
"capabilities": ["sms"],
"status": "connected",
"inbound_webhook_url": "https://app.texttree.ai/webhooks/provider/incoming",
"compliance_status": "pending"
},
"webhook_configured": true
}
Current alpha boundaries
The developer API does not currently expose:
- legacy consent/contact metadata CRUD endpoints
- workspace-suppression CRUD endpoints
- spend-limit CRUD endpoints
- public funding-session creation