Send SMS with FastAPI
Send a text from a FastAPI endpoint with the TextKit Python SDK.
Prompt for your AI agent
Paste this into Claude Code, Cursor or any coding agent to have it do the integration:
Add SMS sending to this FastAPI project with TextKit.
- Docs for this stack: https://jointextkit.com/docs/send-with-fastapi.md
- API: POST https://api.jointextkit.com/v1/messages with `Authorization: Bearer
<key>` and a JSON body `{"to": "+1...", "body": "..."}`.
- Use the official SDK: `pip install jointextkit`, then
`TextKit().messages.send(to=..., body=...)` in a sync (`def`) endpoint so
FastAPI runs it in its thread pool.
- Read the key from the `TEXTKIT_API_KEY` environment variable. Never hardcode
it or send it to the browser.
- Phone numbers are E.164 and US or Canada only (`+1` followed by 10 digits).
- A test key (`ssms_sk_test_`) simulates: `+15005550006` always ends `delivered`
and no phone gets a text.
- Errors are JSON: `{"error": {"code", "message", "param"}}` with a 4xx status.
On `429`, wait `Retry-After` seconds and retry.
- Send only from server code that runs after a real event (a signup, an order).
Never expose an endpoint that texts any number a visitor types.Before you start
- An API key. Create a free account and copy the test key
(
ssms_sk_test_...) from Home in the console. It works at once, no card. - Python 3.8 or later and FastAPI.
- Put the key in an environment variable:
export TEXTKIT_API_KEY=ssms_sk_test_...1. Install
pip install "fastapi[standard]" jointextkit2. Add an endpoint
Create main.py:
from fastapi import FastAPI, HTTPException
from jointextkit import TextKit, TextKitError
from pydantic import BaseModel
app = FastAPI()
client = TextKit() # reads TEXTKIT_API_KEY
class Sms(BaseModel):
to: str
body: str
@app.post("/send-sms")
def send_sms(sms: Sms):
try:
message = client.messages.send(to=sms.to, body=sms.body)
except TextKitError as err:
raise HTTPException(status_code=err.status, detail={"code": err.code, "message": str(err)})
return {"id": message["id"], "status": message["status"]}The endpoint is a plain def: the SDK is synchronous, and FastAPI runs sync
endpoints in a thread pool so they never block the event loop.
3. Try it
fastapi dev main.py
curl -X POST http://localhost:8000/send-sms \
-H "Content-Type: application/json" \
-d '{"to": "+15005550006", "body": "Hello from TextKit"}'It returns {"id": "msg_...", "status": "delivered"}.
This endpoint texts whatever number it receives. Put it behind your own sign-in before you deploy it, or call
sendfrom code that runs after a real event (a signup, an order). An open endpoint lets anyone text through your account.
What the test key did
+15005550006 is a sandbox number: the send comes back delivered and no
phone gets a text (the response says "simulated": true). Put your own
verified phone in to and the test key texts it for real. See
Sandbox & test numbers.
Handle errors
The SDK raises TextKitError with the API's code and status (plus
param for a bad field and retry_after on a rate limit). It retries network
failures and 429s for you, with an idempotency key, so a retry never sends twice.
| Status | Code | What to do |
|---|---|---|
| 400 | invalid_request | A field is missing or malformed; param names it. |
| 401 | invalid_api_key | The key is missing, revoked or mistyped. |
| 402 | insufficient_credits | Add credits; nothing was sent or charged. |
| 403 | recipient_opted_out | They texted STOP. Do not retry. |
| 429 | rate_limited | Wait Retry-After seconds, then retry. |
Every code is in Errors.
Go live
- Add a number in the console.
- Register your use case. We file your 10DLC registration; toll-free numbers use a guided verification form. Until carriers approve it, the number texts only your verified numbers. See Compliance & registration.
- Swap in a live key (
ssms_sk_live_...). The code stays the same.
Next steps
- Webhooks: delivery receipts and replies, pushed to your server.
- Verify: one-time codes in two calls, billed only when verified.
- Send an SMS: every field the endpoint takes.
- All quickstarts: the same guide for other languages and frameworks.