Skip to main content

📱 SMSGate Python API Client

License PyPI Version Python Version Downloads GitHub Issues GitHub Stars GitHub Forks CodeRabbit Pull Request Reviews

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

✨ 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, and httpx
  • 🔗 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:

📦 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

  1. Configure your credentials:

    export SMSGATE_USERNAME="your_username"
    export SMSGATE_PASSWORD="your_password"
    
  2. 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:

  1. Basic Authentication (traditional):

    client.APIClient(login="username", password="password")
    
  2. 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

  1. 🍴 Fork the repository
  2. 🌿 Create your feature branch (git checkout -b feature/NewFeature)
  3. 💾 Commit your changes (git commit -m 'feat: add new feature')
  4. 📤 Push to branch (git push origin feature/NewFeature)
  5. 🔄 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


Note: Android is a trademark of Google LLC. This project is not affiliated with or endorsed by Google.

Metadata

Release files for android-sms-gateway 4.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for android-sms-gateway 4.2.0
File Size Uploaded
android_sms_gateway-4.2.0.tar.gz 46.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for android-sms-gateway 4.2.0
File Interpreter ABI Platform
android_sms_gateway-4.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 78.5 kB

Release files / android_sms_gateway-4.2.0.tar.gz

Download URL android_sms_gateway-4.2.0.tar.gz
Size 46.5 kB
Tags Source
SHA-256 checksum
How to use checksums
0e26db2bbb7a1504621d6b955d5e0def07a6c15f3f63ca2fedcf876bfa5f3605
BLAKE2b-256 checksum
How to use checksums
0cd9c2dd0ca84d0d292cb842b586c86e24d1fc77681e991eb17482e293259edf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 20, 2026.

Transparency log

Release files / android_sms_gateway-4.2.0-py3-none-any.whl

Download URL android_sms_gateway-4.2.0-py3-none-any.whl
Size 32.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3c4670b370407c985f06003462dadaf0c6c629f26aad980856ef242e18835169
BLAKE2b-256 checksum
How to use checksums
f16857cefb5e0d6ad9ab06c10b0d667f2c966ff580d08651837cd17372a291ab
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 20, 2026.

Transparency log

Release history Release notifications | RSS feed

4.3.0

2 release files

4.2.1

2 release files

This release

4.2.0 This release

2 release files

4.1.0

2 release files

4.0.0

2 release files

3.3.0

2 release files

3.2.2

2 release files

3.1.1

2 release files

3.1.0

2 release files

3.0.0

2 release files

2.1.0

2 release files

2.0.0

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.0.3

2 release files

0.0.2

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page