Loading repository data…
Loading repository data…
mdsajidalam0559 / repository
Self-hosted SMS gateway that routes messages through Android devices via FCM push notifications
A transparent discovery signal based on current public GitHub metadata.
This score does not audit code, security, maintainers, documentation quality, or suitability. Verify the repository and its current documentation before adoption.
A self-hosted SMS gateway that turns Android phones into programmable SMS senders. Instead of paying per-message fees to services like Twilio or MessageBird, this system routes messages through your own Android devices using their native SMS capability.
The server receives API requests, picks the best available device, and delivers a Firebase Cloud Messaging (FCM) push notification that wakes the device and triggers SMS transmission in real time. Delivery status is reported back to the server synchronously, so the API caller gets an immediate SENT or FAILED response without polling.
Paid SMS APIs charge per message and require business verification. For internal tools, OTP delivery, notifications, or any use case where you control the sending devices, this project gives you:
The diagram above covers the complete flow:
POST /sms/dispatch. The server picks the most recently active device, sends an FCM push, and the device transmits the SMS via the native Android SMS API.You need two credential files from Firebase: a service-account.json for the backend server and a google-services.json for the Android app.
service-account.json (Backend)This file lets the server authenticate with Firebase to send push notifications.
service-account.json and place it in the project root directory (next to docker-compose.yml).Keep this file secret. It grants full admin access to your Firebase project. Do not commit it to version control.
google-services.json (Android)This file connects the Android app to your Firebase project for receiving push notifications.
com.smsgateway as the package name.google-services.json file.android/app/ directory (replacing the existing one if present).# Clone the repository
git clone <repository-url>
cd sms-gateway
# Place your service-account.json in the project root (see Firebase Setup above)
# Build and start the server
docker-compose up --build -d
The API will be available at http://localhost:9000. Interactive API docs are at http://localhost:9000/docs.
# Create and activate a virtual environment
python -m venv venv
source venv/bin/activate
# Install dependencies
pip install -r requirements.txt
# Copy the example environment file and edit if needed
cp .env.example .env
# Place your service-account.json in the project root
# Start the server
uvicorn app.main:app --host 0.0.0.0 --port 9000
http://<SERVER_IP>:9000/static/sms-gateway.apkhttp://192.168.1.100:9000). Use the server's LAN IP, not localhost.If you want to build the Android app from source, open the android/ directory in Android Studio. Make sure your google-services.json is in android/app/ before building.
This is the primary endpoint. It picks the best device, sends the message, and waits for confirmation.
curl -X POST http://localhost:9000/sms/dispatch \
-H "Content-Type: application/json" \
-d '{"to": "+1234567890", "message": "Your verification code is 4821"}'
Response (returns after device confirms delivery, up to 10 seconds):
{
"message_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "SENT"
}
Requires the X-API-Key header from device registration.
curl -X POST http://localhost:9000/sms/send \
-H "Content-Type: application/json" \
-H "X-API-Key: sg_your_api_key_here" \
-d '{
"to": "+1234567890",
"message": "Hello from a specific device",
"device_id": "device-uuid-here"
}'
curl http://localhost:9000/sms/{message_id} \
-H "X-API-Key: sg_your_api_key_here"
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"device_id": "device-uuid",
"recipient": "+1234567890",
"body": "Your verification code is 4821",
"status": "DELIVERED",
"error": null,
"created_at": "2025-01-15T10:00:00",
"sent_at": "2025-01-15T10:00:01",
"delivered_at": "2025-01-15T10:00:03",
"failed_at": null
}
curl http://localhost:9000/sms/?limit=20 \
-H "X-API-Key: sg_your_api_key_here"
curl http://localhost:9000/devices/
curl -X DELETE http://localhost:9000/devices/{device_id}
curl http://localhost:9000/health
Returns {"status": "ok"} when the server is running.
Full interactive documentation is available at http://localhost:9000/docs (Swagger UI) when the server is running.
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /sms/dispatch | None | Smart dispatch with automatic device selection and failover |
| POST | /sms/send | API Key | Send SMS through a specific device |
| POST | /sms/status | Device Token | Status callback (used internally by the Android app) |
| GET | /sms/{message_id} | API Key | Get status of a specific message |
| GET | /sms/ | API Key | List recent messages |
| POST | /devices/register | None | Register a new Android device |
| POST | /devices/heartbeat | API Key | Device heartbeat (called automatically by the Android app) |
| GET | /devices/ | None | List all registered devices |
| DELETE | /devices/{device_id} | None | Remove a registered device |
| GET | /health | None | Server health check |
Endpoints marked with "API Key" require an X-API-Key header. The key is generated when a device registers and follows the format sg_<hex>. Example:
X-API-Key: sg_a1b2c3d4e5f67890abcdef1234567890
The /sms/status endpoint is authenticated by the device's FCM token (passed in the request body) rather than an API key. This endpoint is only called by the Android app.
| Status | Meaning |
|---|---|
| PENDING | Message created, FCM push not yet sent |
| QUEUED | FCM push delivered to device, SMS not yet sent |
| SENT | Device confirmed the SMS was sent |
| DELIVERED | Carrier confirmed delivery to the recipient |
| FAILED | SMS sending failed (check the error field for details) |
| Variable | Default | Description |
|---|---|---|
FIREBASE_SERVICE_ACCOUNT_PATH | ./service-account.json | Path to the Firebase service account credentials file |
DATABASE_URL | sqlite:///./sms_gateway.db | SQLAlchemy database connection string |
API_HOST | 0.0.0.0 | Host address the server binds to |
API_PORT | 9000 | Port the server listens on |
When using Docker, these are set in docker-compose.yml. For manual setup, copy .env.example to .env and edit as needed.
sms_gateway/
├── app/
│ ├── main.py # FastAPI app, CORS, router registration, startup
│ ├── config.py # Environment variable configuration
│ ├── database.py # SQLAlchemy engine and session setup
│ ├── models.py # Device and Message database models
│ ├── schemas.py # Pydantic request/response schemas
│ ├── auth.py # API key authentication
│ ├── firebase.py # Firebase Admin SDK init and FCM push
│ └── routers/
│ ├── sms.py # SMS dispatch, send, status, and listing endpoints
│ └── devices.py # Device registration, heartbeat, listing, deletion
├── android/ # Android Studio project (Kotlin)
│ └── app/
│ └── src/main/java/com/smsgateway/
│ ├── MainActivity.kt # Registration UI
│ ├── SmsFcmService.kt # FCM message handler, triggers SMS
│ ├── SmsStatusReceiver.kt # Broadcast receiver for delivery reports
│ ├── SmsLimitManager.kt # Daily SMS limit enforcement
│ └── HeartbeatWorker.kt # Periodic heartbeat via WorkManager
├── static/
│ └── sms-gateway.apk # Pre-built Android APK
├── Dockerfile
├── docker-compose.yml
├── requirements.txt
├── .env.example
└── service-account.json # Your Firebase credentials (not committed)
Server unreachable from Android device: Make sure the phone and server are on the same network. Use the