Files
sms-api-wrapper/sms/README.md
chelsea db5bde0a70 first commit
Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-04 04:39:53 +00:00

91 lines
3.2 KiB
Markdown

# sms — voip.ms SMS/MMS API façade
A small FastAPI service that wraps the [voip.ms](https://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
1. Enable the REST API and set an API password in the portal:
**Main Menu → SOAP / REST API → API Security**.
2. **Whitelist this machine's public IP** in the same API Security page.
3. The DID you send from must have **SMS enabled** (Manage DIDs → Edit DID).
4. Sending is capped at **100 SMS/MMS per day** via the API. Pricing:
$0.0075/SMS, $0.02/MMS, each direction.
## Configure
```sh
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
```sh
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
`DailySendCounter` for a shared store (Redis, etc.).
- Use `https://voip.ms` (not `www.voip.ms`) — the `www` host 302-redirects
and drops POST bodies, producing `missing_method` errors.
- Dialing mode normalizes `did`/`dst` on send: `nanpa` → 10 digits,
`e164``+1` + 10 digits.
- No `markSMSRead` method 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 `ok` and persists
`{TO}/{FROM}/{MESSAGE}/{ID}/{TIMESTAMP}/{MEDIA}`.