3.2 KiB
3.2 KiB
sms — voip.ms SMS/MMS API façade
A small FastAPI service that wraps the voip.ms SMS/MMS REST
API (https://voip.ms/api/v1/rest.php) behind typed Python + REST endpoints,
with a per-day outbound send guard.
Files
| File | Purpose |
|---|---|
config.py |
Settings (env-loaded creds, dialing mode, daily limit, timeout) |
exceptions.py |
VoipMsError hierarchy (Auth, Api, RateLimit) |
models.py |
Pydantic request/response models |
client.py |
VoipMsSMSClient — async httpx wrappers for the 7 methods |
guard.py |
DailySendCounter — UTC-day counter + send logging |
app.py |
FastAPI app exposing the operations as REST endpoints |
requirements.txt |
Dependencies |
voip.ms prerequisites
- Enable the REST API and set an API password in the portal: Main Menu → SOAP / REST API → API Security.
- Whitelist this machine's public IP in the same API Security page.
- The DID you send from must have SMS enabled (Manage DIDs → Edit DID).
- Sending is capped at 100 SMS/MMS per day via the API. Pricing: $0.0075/SMS, $0.02/MMS, each direction.
Configure
export VOIPMS_API_USERNAME=...
export VOIPMS_API_PASSWORD=...
# optional overrides:
# export VOIPMS_BASE_URL=https://voip.ms/api/v1/rest.php
# export VOIPMS_DIALING_MODE=nanpa # or e164
# export VOIPMS_DAILY_LIMIT=100
# export VOIPMS_TIMEOUT=30
(Settings also reads a .env file in the working directory.)
Run
pip install -r sms/requirements.txt
uvicorn sms.app:app --reload
Open http://127.0.0.1:8000/docs for the Swagger UI.
Endpoints
| Method | Path | Upstream | Guarded |
|---|---|---|---|
| POST | /sms/send |
sendSMS |
✅ |
| POST | /mms/send |
sendMMS |
✅ |
| GET | /sms |
getSMS |
— |
| GET | /mms |
getMMS |
— |
| GET | /mms/{id}/media |
getMediaMMS |
— |
| DELETE | /sms/{id} |
deleteSMS |
— |
| DELETE | /mms/{id} |
deleteMMS |
— |
| GET | /health |
— | — |
Query params for GET /sms / GET /mms
from, to (YYYY-MM-DD), type (1=received / 0=sent), did, contact,
limit, timezone (-12..13), all_messages (1=SMS+MMS combined, 0=single
type; the message id must be 0 when set). For /sms the id query param is
sms; for /mms it is id.
Error mapping
| Condition | HTTP | Body |
|---|---|---|
| Daily limit exceeded | 429 | {detail, limit, used_today} |
| voip.ms returns non-success status | 502 | upstream message |
| Auth / IP-whitelist failure | 500 | upstream authentication failure (details logged server-side) |
Notes & limitations
- The daily counter is per-process. For multiple instances, swap
DailySendCounterfor a shared store (Redis, etc.). - Use
https://voip.ms(notwww.voip.ms) — thewwwhost 302-redirects and drops POST bodies, producingmissing_methoderrors. - Dialing mode normalizes
did/dston send:nanpa→ 10 digits,e164→+1+ 10 digits. - No
markSMSReadmethod exists in the voip.ms API; read state is not manageable via REST. - Inbound URL Callback receiver is not included here; it can be added
as a separate route set that replies with the literal
okand persists{TO}/{FROM}/{MESSAGE}/{ID}/{TIMESTAMP}/{MEDIA}.