SMS API in Python: Full Integration Tutorial
Most Python SMS guides rank because they answer fast: import requests, requests.post, done. This tutorial covers everything those pages skip.
What breaks real Python SMS integrations:
No default timeout in requests
A stalled socket blocks a Gunicorn worker or Celery process forever. Always pass timeout=(connect, read).
json= versus data=
The SMSGatewayCenter endpoint expects application/x-www-form-urlencoded. Passing json= sets the wrong Content-Type and fails like an auth error.
statusCode type instability
Quoted string on SMSApi/send, integer on WAApi/send. Use pydantic models at the boundary.
urllib3 Retry on POST
Automatic retries on non-idempotent POST double-sends and double-bills.
asyncio.gather pitfalls
Unbounded fan-out plus first-exception cancellation discards successful results.
Celery acks_late without idempotency
Worker crash redelivers tasks and sends duplicate OTPs.
Form-encoded webhooks in FastAPI
Pydantic JSON body models do not apply to form-encoded DLR pushes.
GSM-7 vs UCS-2
One curly apostrophe can triple SMS cost. Count segments before send.
India DLT
Mandatory for Indian A2P traffic. Positional variable substitution in one pass, not chained str.replace.
Configuration and credentials (.env, apiKey)
HTTP client (httpx or requests Session with timeouts)
Typed responses (pydantic)
Celery for production async sending
Also covered:
OTP sending, failure classification before retry, DLR polling, official Python SDK, security checklist, pytest with respx.
Prerequisites: Python 3.11+, approved sender ID, DLT registration for India.
pip install httpx pydantic tenacity celery redis fastapi uvicorn python-dotenv
Full walkthrough with copy-paste code:
https://www.smsgatewaycenter.com/blog/sms-api-python-integration-tutorial/