π± SMSGate Python API Client
August 20, 2026 Β· View on GitHub
A modern Python client for seamless integration with the SMSGate API. Send SMS messages programmatically through your Android devices with this powerful yet simple-to-use library.
π About The Project
The Python client for SMSGate provides a clean, type-safe interface to interact with the SMSGate API. It's designed specifically for Python developers who need to integrate SMS functionality into their applications with minimal setup and maximum reliability.
Key value propositions:
- π Pythonic API - Designed with Python conventions and best practices in mind
- π‘οΈ Robust Security - Guidance for secure credential handling and optional endβtoβend encryption
- π Flexible Architecture - Supports both synchronous and asynchronous programming patterns
- π» Type Safety - Full type hinting for better developer experience and fewer runtime errors
- π Webhook Integration - Simplified webhook management for event-driven architectures
This client abstracts away the complexities of the underlying HTTP API while providing all the necessary functionality to send and track SMS messages through Android devices.
π Table of Contents
- π± SMSGate Python API Client
β¨ Features
- π Dual Client: Supports both synchronous (
APIClient) and asynchronous (AsyncAPIClient) interfaces - π Flexible Authentication: Supports both Basic Auth and JWT token authentication
- π End-to-End Encryption: Optional message encryption using AES-256-CBC
- π Multiple HTTP Backends: Native support for
requests,aiohttp, andhttpx - π Webhook Management: Programmatically create, query, and delete webhooks
- βοΈ Customizable Base URL: Point to different API endpoints
- π» Full Type Hinting: Fully typed for better development experience
- β οΈ Robust Error Handling: Specific exceptions and clear error messages
- π Delivery Reports: Track your message delivery status
- π Token Management: Generate, refresh, and revoke JWT tokens with custom scopes and TTL
- π Message Filtering: List messages with date range, state, and device filtering
- βοΈ Settings Management: Get, update, and patch device settings
- π Logging: Retrieve system logs with time range filtering
- π₯ Health Checks: Liveness, readiness, and startup probes
- π± Device Management: List and remove registered devices
- π₯ Inbox Refresh: Refresh device inboxes with webhook delivery (individual or batch)
βοΈ Requirements
- Python: 3.9 or higher
- HTTP Client (choose one):
Optional Dependencies:
- π pycryptodome - For end-to-end encryption support
π¦ Installation
Basic Installation
pip install android-sms-gateway
Installation with Specific HTTP Client
# Choose an HTTP client:
pip install android-sms-gateway[requests] # For synchronous use
pip install android-sms-gateway[aiohttp] # For asynchronous use
pip install android-sms-gateway[httpx] # For both synchronous and asynchronous use
Installation with Encryption
# For encrypted messages:
pip install android-sms-gateway[encryption]
# Or install everything:
pip install android-sms-gateway[requests,encryption]
π Quickstart
Initial Setup
-
Configure your credentials:
export SMSGATE_USERNAME="your_username" export SMSGATE_PASSWORD="your_password" -
Basic usage example:
import asyncio
import os
from android_sms_gateway import client, domain
# Configuration
login = os.getenv("SMSGATE_USERNAME")
password = os.getenv("SMSGATE_PASSWORD")
# Create message
message = domain.Message(
phone_numbers=["+1234567890"],
text_message=domain.TextMessage(
text="Hello! This is a test message.",
),
with_delivery_report=True,
)
# Synchronous Client
def sync_example():
with client.APIClient(login, password) as c:
# Send message
response = c.send(message)
print(f"Message sent with ID: {response.id}")
# Check status
status = c.get_state(response.id)
print(f"Status: {status.state}")
# Asynchronous Client
async def async_example():
async with client.AsyncAPIClient(login, password) as c:
# Send message
response = await c.send(message)
print(f"Message sent with ID: {response.id}")
# Check status
status = await c.get_state(response.id)
print(f"Status: {status.state}")
if __name__ == "__main__":
print("=== Synchronous Example ===")
sync_example()
print("\n=== Asynchronous Example ===")
asyncio.run(async_example())
Encryption Example
from android_sms_gateway import client, domain, Encryptor
# Encryption setup
encryptor = Encryptor("my-super-secure-secret-passphrase")
# Encrypted message
message = domain.Message(
phone_numbers=["+1234567890"],
text_message=domain.TextMessage(
text="This message will be encrypted!"
),
)
# Client with encryption
with client.APIClient(login, password, encryptor=encryptor) as c:
response = c.send(message)
print(f"Encrypted message sent: {response.id}")
JWT Authentication Example
import os
from android_sms_gateway import client, domain
# Option 1: Using an existing JWT token
jwt_token = os.getenv("ANDROID_SMS_GATEWAY_JWT_TOKEN")
# Create client with JWT token
with client.APIClient(login=None, password=jwt_token) as c:
message = domain.Message(
phone_numbers=["+1234567890"],
text_message=domain.TextMessage(
text="Hello from JWT authenticated client!",
),
)
# Option 2: Generate a new JWT token with Basic Auth
login = os.getenv("SMSGATE_USERNAME")
password = os.getenv("SMSGATE_PASSWORD")
with client.APIClient(login, password) as c:
# Generate a new JWT token with specific scopes and TTL
token_request = domain.TokenRequest(
scopes=["sms:send", "sms:read"],
ttl=3600 # Token expires in 1 hour
)
token_response = c.generate_token(token_request)
print(f"New JWT token: {token_response.access_token}")
print(f"Token expires at: {token_response.expires_at}")
# Use the new token for subsequent requests
with client.APIClient(login=None, password=token_response.access_token) as jwt_client:
message = domain.Message(
phone_numbers=["+1234567890"],
text_message=domain.TextMessage(
text="Hello from newly generated JWT token!",
),
)
response = jwt_client.send(message)
print(f"Message sent with new JWT token: {response.id}")
# Revoke the token when no longer needed
jwt_client.revoke_token(token_response.id)
print(f"Token {token_response.id} has been revoked")
π€ Client Guide
Client Configuration
Both clients (APIClient and AsyncAPIClient) support these parameters:
| Parameter | Type | Description | Default |
|---|---|---|---|
login | str | API username | Required (for Basic Auth) |
password | str | API password or JWT token | Required |
base_url | str | API base URL | "https://api.sms-gate.app/3rdparty/v1" |
encryptor | Encryptor | Encryption instance | None |
http | HttpClient/AsyncHttpClient | Custom HTTP client | Auto-detected |
Authentication Options:
-
Basic Authentication (traditional):
client.APIClient(login="username", password="password") -
JWT Token Authentication:
# Using an existing JWT token client.APIClient(login=None, password="your_jwt_token") # Or generate a token using Basic Auth first with client.APIClient(login="username", password="password") as c: token_request = domain.TokenRequest(scopes=["sms:send"], ttl=3600) token_response = c.generate_token(token_request) # Use the new token with client.APIClient(login=None, password=token_response.access_token) as jwt_client: # Make API calls with JWT authentication pass
Available Methods
Message Methods
| Method | Description | Return Type |
|---|---|---|
send(message, *, skip_phone_validation=False, device_active_within=0) | Send SMS message | domain.MessageState |
get_state(id) | Get message state by ID | domain.MessageState |
get_messages(*, query=None, pagination=None) | List messages with filtering | List[domain.MessageState] |
Inbox methods
| Method | Description | Return Type |
|---|---|---|
list_inbox_messages(*, inbox_filter=None, pagination=None) | List inbox messages | List[IncomingMessage] |
refresh_inbox(request) | Refresh inbox messages | dict |
download_attachment(message_id, part_id) | Download attachment | bytes |
Webhook Methods
| Method | Description | Return Type |
|---|---|---|
create_webhook(webhook) | Create new webhook | domain.Webhook |
get_webhooks() | List all webhooks | List[domain.Webhook] |
delete_webhook(id) | Delete webhook | None |
Device Methods
| Method | Description | Return Type |
|---|---|---|
list_devices() | List all registered devices | List[domain.Device] |
remove_device(id) | Remove a device | None |
Settings Methods
| Method | Description | Return Type |
|---|---|---|
get_settings() | Get device settings | domain.DeviceSettings |
update_settings(settings) | Replace settings | dict |
patch_settings(settings) | Partially update settings | dict |
Log Methods
| Method | Description | Return Type |
|---|---|---|
get_logs(from_=None, to=None) | Get log entries | List[domain.LogEntry] |
Health Check Methods
| Method | Description | Return Type |
|---|---|---|
health_check() | Readiness probe | domain.HealthResponse |
liveness_check() | Liveness probe | domain.HealthResponse |
readiness_check() | Readiness probe | domain.HealthResponse |
startup_check() | Startup probe | domain.HealthResponse |
Token Methods
| Method | Description | Return Type |
|---|---|---|
generate_token(token_request) | Generate JWT token | domain.TokenResponse |
refresh_token(refresh_token) | Refresh access token | domain.TokenResponse |
revoke_token(jti) | Revoke JWT token | None |
Data Structures
Message
class Message:
phone_numbers: List[str] # List of phone numbers (required)
text_message: Optional[TextMessage] = None # Text message
data_message: Optional[DataMessage] = None # Data message
priority: Optional[MessagePriority] = None # Message priority
sim_number: Optional[int] = None # SIM card number (1-3)
with_delivery_report: bool = True # Delivery report
is_encrypted: bool = False # Whether message is encrypted
ttl: Optional[int] = None # Time-to-live in seconds
valid_until: Optional[datetime] = None # Valid until timestamp
id: Optional[str] = None # Message ID
device_id: Optional[str] = None # Device ID for explicit selection
MessageState
class MessageState:
id: str # Unique message ID
state: ProcessState # Current processing state
recipients: List[RecipientState] # Per-recipient status
is_hashed: bool = False # Whether phone numbers are hashed
is_encrypted: bool = False # Whether message was encrypted
device_id: Optional[str] = None # Device ID (optional for backward compatibility)
states: Optional[Dict[str, str]] = None # History of state changes
Webhook
class Webhook:
id: Optional[str] # Webhook ID
url: str # Callback URL
event: WebhookEvent # Event type
device_id: Optional[str] = None # Associated device ID
InboxRefreshRequest
class InboxRefreshRequest:
since: datetime # Start of time range (required)
until: datetime # End of time range (required)
device_id: Optional[str] = None # Device ID to refresh messages for
message_types: Optional[List[str]] = None # SMS, DATA_SMS, MMS, MMS_DOWNLOADED
webhook_delivery: Optional[WebhookDelivery] = None # Delivery mode
Device
class Device:
id: str # Unique device identifier
name: str # Device name
created_at: Optional[datetime] = None # Creation timestamp
updated_at: Optional[datetime] = None # Last update timestamp
deleted_at: Optional[datetime] = None # Deletion timestamp
last_seen: Optional[datetime] = None # Last seen timestamp
DeviceSettings
class DeviceSettings:
gateway: Optional[SettingsGateway] = None # Gateway settings
encryption: Optional[SettingsEncryption] = None # Encryption settings
messages: Optional[SettingsMessages] = None # Message handling settings
logs: Optional[SettingsLogs] = None # Logging settings
ping: Optional[SettingsPing] = None # Ping settings
webhooks: Optional[SettingsWebhooks] = None # Webhook settings
TokenRequest
class TokenRequest:
scopes: List[str] # List of scopes for the token (required)
ttl: Optional[int] = None # Time to live in seconds
TokenResponse
class TokenResponse:
access_token: str # The JWT access token
token_type: str # Token type (e.g., 'Bearer')
id: str # Unique token identifier (jti)
expires_at: str # Expiration time in ISO format
refresh_token: Optional[str] = None # Refresh token
HealthResponse
class HealthResponse:
status: HealthStatus # Overall health status
version: Optional[str] = None # Application version
release_id: Optional[int] = None # Release ID
checks: Optional[Dict[str, HealthCheck]] = None # Individual health checks
LogEntry
class LogEntry:
id: int # Unique log entry ID
created_at: datetime # Creation timestamp
message: str # Log message
priority: LogEntryPriority # Priority level (DEBUG, INFO, WARN, ERROR)
module: Optional[str] = None # Source module
context: Optional[Dict] = None # Additional context
Enums
class ProcessState(enum.Enum):
Pending = "Pending"
Processed = "Processed"
Sent = "Sent"
Delivered = "Delivered"
Failed = "Failed"
class WebhookEvent(enum.Enum):
SMS_RECEIVED = "sms:received"
SMS_DATA_RECEIVED = "sms:data-received"
SMS_SENT = "sms:sent"
SMS_DELIVERED = "sms:delivered"
SMS_FAILED = "sms:failed"
SYSTEM_PING = "system:ping"
MMS_RECEIVED = "mms:received"
MMS_DOWNLOADED = "mms:downloaded"
SMS_BATCH_RECEIVED = "sms:batch:received"
SMS_DATA_BATCH_RECEIVED = "sms:batch:data-received"
MMS_BATCH_RECEIVED = "mms:batch:received"
MMS_BATCH_DOWNLOADED = "mms:batch:downloaded"
class WebhookDelivery(enum.Enum):
DISABLED = "Disabled"
INDIVIDUAL = "Individual"
BATCH = "Batch"
class MessagePriority(enum.IntEnum):
MINIMUM = -128
DEFAULT = 0
BYPASS_THRESHOLD = 100
MAXIMUM = 127
class LimitPeriod(enum.Enum):
DISABLED = "Disabled"
PER_MINUTE = "PerMinute"
PER_HOUR = "PerHour"
PER_DAY = "PerDay"
class SimSelectionMode(enum.Enum):
OS_DEFAULT = "OSDefault"
ROUND_ROBIN = "RoundRobin"
RANDOM = "Random"
class MessagesProcessingOrder(enum.Enum):
LIFO = "LIFO"
FIFO = "FIFO"
class HealthStatus(enum.Enum):
PASS = "pass"
WARN = "warn"
FAIL = "fail"
class LogEntryPriority(enum.Enum):
DEBUG = "DEBUG"
INFO = "INFO"
WARN = "WARN"
ERROR = "ERROR"
For more details, see domain.py.
π HTTP Clients
The library automatically detects installed HTTP clients with this priority:
| Client | Sync | Async |
|---|---|---|
| aiohttp | β | 1οΈβ£ |
| requests | 1οΈβ£ | β |
| httpx | 2οΈβ£ | 2οΈβ£ |
Using Specific Clients
from android_sms_gateway import client, http
# Force httpx usage
client.APIClient(..., http=http.HttpxHttpClient())
# Force requests usage
client.APIClient(..., http=http.RequestsHttpClient())
# Force aiohttp (async only)
async with client.AsyncAPIClient(..., http_client=http.AiohttpHttpClient()) as c:
# ...
Custom HTTP Client
Implement your own HTTP client following the http.HttpClient (sync) or ahttp.AsyncHttpClient (async) protocols.
π Security
Best Practices
β οΈ IMPORTANT: Always follow these security practices:
- π Credentials: Store credentials in environment variables
- π« Code: Never expose credentials in client-side code
- π HTTPS: Use HTTPS for all production communications
- π Encryption: Use end-to-end encryption for sensitive messages
- π Rotation: Regularly rotate your credentials
JWT Security Best Practices
When using JWT authentication, follow these additional security practices:
- β±οΈ Short TTL: Use short time-to-live (TTL) for tokens (recommended: 1 hour or less)
- π Secure Storage: Store JWT tokens securely, preferably in memory or secure storage
- π― Minimal Scopes: Request only the minimum necessary scopes for each token
- π Token Rotation: Implement token refresh mechanisms before expiration
- π Revocation: Immediately revoke compromised tokens using
revoke_token()
Secure Configuration Example
import os
from dotenv import load_dotenv
# Load environment variables
load_dotenv()
# Secure configuration
login = os.getenv("SMSGATE_USERNAME")
password = os.getenv("SMSGATE_PASSWORD")
if not login or not password:
raise ValueError("Credentials not configured!")
π API Reference
For complete API documentation including all available methods, request/response schemas, and error codes, visit: π Official API Documentation
π₯ Contributing
Contributions are very welcome! π
How to Contribute
- π΄ Fork the repository
- πΏ Create your feature branch (
git checkout -b feature/NewFeature) - πΎ Commit your changes (
git commit -m 'feat: add new feature') - π€ Push to branch (
git push origin feature/NewFeature) - π Open a Pull Request
Development Environment
# Clone repository
git clone https://github.com/android-sms-gateway/client-py.git
cd client-py
# Create virtual environment
pipenv install --dev --categories encryption,requests
pipenv shell
Pull Request Checklist
- Code follows style standards (black, isort, flake8)
- Tests pass locally
- Documentation updated
- Test coverage maintained or improved
π License
This project is licensed under the Apache License 2.0 - see LICENSE for details.
π€ Support
- π§ Email: support@sms-gate.app
- π¬ Discord: SMS Gateway Community
- π Documentation: docs.sms-gate.app
- π Issues: GitHub Issues
Note: Android is a trademark of Google LLC. This project is not affiliated with or endorsed by Google.