Give any AI agent (LangChain or anything else) full iMessage capabilities: send texts, read attachments and screenshots, react with tapbacks, show typing indicators, and schedule cron check-ins. One interface, four swappable hosted providers — no Mac required.
Build things like an accountability coach that texts you to hit the gym, checks in on schedule, and judges your workout screenshots.
your iPhone ⇄ Apple ⇄ provider ── webhook/WS ──▶ FastAPI (Railway) ──▶ your agent
▲ │
└────────────── send / media / react ◀──────────┘
Set TEXTDM_PROVIDER and the matching credentials in .env (see
.env.example). Switching providers changes nothing above the transport.
| Provider | Free tier | Notes |
|---|---|---|
messagesdev |
50 msgs/day sandbox (your own paired number) | Best API: reply threading, audio transcription, HMAC webhooks. $99/mo per production line. |
sendblue |
Free API plan / AI-agent plan | Proven; tapbacks + typing verified. Inbound tapbacks are heuristic (arrive as Loved "..." text). |
loopmessage |
Sandbox: 5 contacts, unlimited msgs | Contact must text the sandbox number first (24h reply windows). $59.99/mo Light. |
clawmessenger |
7-day trial, $5/mo for 250 msgs | Text send is REST; media/reactions/typing/receiving are WebSocket (runs as a background listener, no webhook needed). |
python3 -m venv .venv && .venv/bin/pip install -e ".[clawmessenger,langchain]"
cp .env.example .env # fill in provider credentials
.venv/bin/python test_textdm.py # sanity check, no networkRun the example gym-coach agent:
TEXTDM_PROVIDER=sendblue uvicorn examples.gym_coach:app --port 8000Point the provider's webhook at https://<host>/webhooks/<provider>.
On Railway: deploy this repo, add env vars, use the generated domain.
from textdm import create_app, get_transport, InboundMessage, Scheduler
from textdm.langchain_tools import build_tools
transport = get_transport("messagesdev")
tools = build_tools(transport, scheduler) # LangChain tools: send/media/react/schedule
async def on_message(msg: InboundMessage):
... # feed msg.text / msg.attachments / msg.reaction to your agent
app = create_app(on_message, [transport]) # FastAPI; run with uvicornEvery provider normalizes into the same InboundMessage: text, attachments
(url + mime + voice transcription when available), tapback reactions, group
flag, and the raw payload if you need provider-specific fields.
textdm/
models.py # InboundMessage / Attachment / Reaction / SendResult
server.py # FastAPI webhook receiver + dedup + WS listener startup
scheduler.py # cron pushes that invoke your agent with a prompt
langchain_tools.py # ready-made LangChain tools
transports/ # base.py + one adapter per provider
examples/gym_coach.py # end-to-end accountability-coach agent
- Adapters are written against each provider's current docs; only webhook parsing is unit-tested. First live send per provider needs real credentials.
- Sendblue inbound-tapback detection is undocumented behavior — verify with a live tapback before relying on it.
- Claw Messenger webhooks are unadvertised/undocumented; its adapter uses their WebSocket instead.
- Dedup is in-memory (fine for one replica; move to Postgres to scale out).