Documentation

Outbound SMS

Send production SMS through suppression, compliance, spend, and provider checks.

Message debugging
msg_123 Delivered
  1. API request received
  2. Message queued
  3. Sent to carrier
  4. Delivered
  5. Webhook delivered

Outbound sends move through the same safety path whether they originate from the API, message composer, campaign builder, or workflow engine.

Request examples

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 appointment is tomorrow at 9 AM.",
    "metadata": {
      "workflow": "appointment-reminder"
    }
  }'

JavaScript

const response = await fetch("https://api.texttree.ai/api/v1/messages", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.TEXTREE_ACCESS_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    phone_number: "+15551234567",
    body: "Your appointment is tomorrow at 9 AM.",
    metadata: { workflow: "appointment-reminder" },
  }),
});

const result = await response.json();

Python

import os
import requests

result = requests.post(
    "https://api.texttree.ai/api/v1/messages",
    headers={"Authorization": f"Bearer {os.environ['TEXTREE_ACCESS_TOKEN']}"},
    json={
        "phone_number": "+15551234567",
        "body": "Your appointment is tomorrow at 9 AM.",
        "metadata": {"workflow": "appointment-reminder"},
    },
    timeout=10,
).json()

Elixir

Mix.install([:req])

result =
  Req.post!(
    "https://api.texttree.ai/api/v1/messages",
    auth: {:bearer, System.fetch_env!("TEXTREE_ACCESS_TOKEN")},
    json: %{
      phone_number: "+15551234567",
      body: "Your appointment is tomorrow at 9 AM.",
      metadata: %{workflow: "appointment-reminder"}
    }
  ).body

Every send is checked for workspace suppressions, environment, compliance, and spend before provider execution. Campaign sends also check campaign-specific suppressions before they enqueue a Textree message.

Failure behavior

If a send is blocked, the API returns a structured failure and the message log shows the same reason in the timeline.

{
  "error": {
    "code": "recipient_not_verified",
    "message": "Recipient number is not verified in test mode.",
    "fix": "Verify this recipient number or switch to live mode after compliance approval."
  }
}