Puzzel SMS Gateway Python Client
Copyright 2024-2026 Puzzel AS
Contents
- Contents
- Overview
- Prerequisites
- Installation
- Quick Start
- Authentication
- Usage Examples
- API Reference
- Error Handling
- Testing
- Migration from v2.x
- Publishing
- Additional Documentation
- Support
- License
Overview
This is a Python client for the Puzzel SMS Gateway API. It provides a type-safe, fluent interface for sending SMS messages and managing message batches.
The client is generated from the SMS Gateway OpenAPI specification and uses the Kiota abstractions for HTTP communication, serialization, and authentication.
Prerequisites
- Python 3.10 or higher
- pip or uv package manager
Dependencies
The package automatically installs all required dependencies when you install it from PyPI:
microsoft-kiota-abstractions>=1.0.0- Core Kiota abstractionsmicrosoft-kiota-http>=1.0.0- HTTP request handlingmicrosoft-kiota-serialization-json>=1.0.0- JSON serializationmicrosoft-kiota-serialization-text>=1.0.0- Text serializationmicrosoft-kiota-serialization-form>=1.0.0- Form serializationmicrosoft-kiota-serialization-multipart>=1.0.0- Multipart serializationhttpx>=0.24.0- Async HTTP client
You don't need to install these manually - they're included automatically. See pyproject.toml for the complete list.
Installation
Using uv (Recommended)
uv is a fast Python package installer and resolver.
Option 1: Install into Existing Project
# Install uv if you haven't already
curl -LsSf https://astral.sh/uv/install.sh | sh
# Install the SMS Gateway client from PyPI
uv pip install puzzel-sms-gateway-client
Option 2: Create New Project with uv
# Install uv if you haven't already
curl -LsSf https://astral.sh/uv/install.sh | sh
# Create a new project
uv init <projectname> --app --python 3.13.1
cd <projectname>
# Create virtual environment
uv venv --python 3.13.1 --seed
# Activate virtual environment
source .venv/bin/activate # On macOS/Linux
# or
.venv\Scripts\activate # On Windows
# Verify installation
python -V
uv pip list
# Install the SMS Gateway client from PyPI
uv pip install puzzel-sms-gateway-client
Note:
uv inittypically creates.venv/automatically, but you can use--seedto explicitly ensure that pip, setuptools, and wheel are installed.
Using pip
pip install puzzel-sms-gateway-client
Quick Start
import asyncio
from kiota_abstractions.authentication import AnonymousAuthenticationProvider
from kiota_http.httpx_request_adapter import HttpxRequestAdapter
from src.mt_http_client import MtHttpClient
from src.models.gateway_request import GatewayRequest
from src.models.message import Message
async def send_sms():
# Set up authentication and HTTP adapter
auth_provider = AnonymousAuthenticationProvider()
request_adapter = HttpxRequestAdapter(auth_provider)
request_adapter.base_url = "https://smsgw.puzzel.com"
# Create the client
client = MtHttpClient(request_adapter)
# Create a message
gateway_request = GatewayRequest(
service_id=YOUR_SERVICE_ID, # Your Puzzel service ID
username="YOUR_USERNAME", # Your Puzzel username
password="YOUR_PASSWORD", # Your Puzzel password
message=[
Message(
recipient="+47xxxxxxxxx", # Phone number with country code
content="Hello World!"
)
]
)
# Send the message
response = await client.gw.rs.send_messages.post(gateway_request)
print(f"Batch Reference: {response.batch_reference}")
for status in response.message_status:
print(f"Message ID: {status.message_id}")
print(f"Status: {status.status_message}")
# Run the async function
asyncio.run(send_sms())
Authentication
The SMS Gateway uses Basic Authentication passed through the request body. You need to provide:
service_id: Your service ID (integer)username: Your gateway username (string)password: Your gateway password (string)
These credentials are included in the GatewayRequest object for each API call.
Base URL Configuration
The Puzzel SMS Gateway base URL is: https://smsgw.puzzel.com
Important: Set only the base domain, not including any path:
# ✅ Correct
request_adapter.base_url = "https://smsgw.puzzel.com"
# ❌ Wrong - don't include the path
request_adapter.base_url = "https://smsgw.puzzel.com/gw/rs"
The client automatically constructs the full URL path based on the API method you call.
from kiota_abstractions.authentication import AnonymousAuthenticationProvider
from kiota_http.httpx_request_adapter import HttpxRequestAdapter
# Use AnonymousAuthenticationProvider since credentials are in the request body
auth_provider = AnonymousAuthenticationProvider()
request_adapter = HttpxRequestAdapter(auth_provider)
request_adapter.base_url = "https://smsgw.puzzel.com"
Usage Examples
Basic Message Sending
Send a simple SMS to a single recipient:
import asyncio
from kiota_abstractions.authentication import AnonymousAuthenticationProvider
from kiota_http.httpx_request_adapter import HttpxRequestAdapter
from src.mt_http_client import MtHttpClient
from src.models.gateway_request import GatewayRequest
from src.models.message import Message
async def send_basic_sms():
auth_provider = AnonymousAuthenticationProvider()
request_adapter = HttpxRequestAdapter(auth_provider)
request_adapter.base_url = "https://smsgw.puzzel.com"
client = MtHttpClient(request_adapter)
request = GatewayRequest(
service_id=12345,
username="your_username",
password="your_password",
message=[
Message(
recipient="+47xxxxxxxxx",
content="Hello from Puzzel SMS Gateway!"
)
]
)
response = await client.gw.rs.send_messages.post(request)
return response
asyncio.run(send_basic_sms())
Sending with Message Settings
Send an SMS with advanced settings like send window, originator, and priority:
import asyncio
from src.mt_http_client import MtHttpClient
from src.models.gateway_request import GatewayRequest
from src.models.message import Message
from src.models.settings import Settings
from src.models.send_window import SendWindow
from src.models.originator_settings import OriginatorSettings
from src.models.originator_type import OriginatorType
async def send_scheduled_sms():
from kiota_abstractions.authentication import AnonymousAuthenticationProvider
from kiota_http.httpx_request_adapter import HttpxRequestAdapter
from src.mt_http_client import MtHttpClient
auth_provider = AnonymousAuthenticationProvider()
request_adapter = HttpxRequestAdapter(auth_provider)
request_adapter.base_url = "https://smsgw.puzzel.com"
client = MtHttpClient(request_adapter)
request = GatewayRequest(
service_id=12345,
username="your_username",
password="your_password",
message=[
Message(
recipient="+47xxxxxxxxx",
content="Scheduled message",
settings=Settings(
priority=1,
validity=173,
originator_settings=OriginatorSettings(
originator="1960",
originator_type=OriginatorType.Network
),
send_window=SendWindow(
start_date="2026-03-21",
start_time="09:00:00",
stop_date="2026-03-21",
stop_time="17:00:00"
)
)
)
]
)
response = await client.gw.rs.send_messages.post(request)
return response
asyncio.run(send_scheduled_sms())
Advanced Configuration
Send an SMS with all available options:
import asyncio
from src.models.gateway_request import GatewayRequest
from src.models.message import Message
from src.models.settings import Settings
from src.models.gas_settings import GasSettings
from src.models.parameter import Parameter
async def send_advanced_sms():
from kiota_abstractions.authentication import AnonymousAuthenticationProvider
from kiota_http.httpx_request_adapter import HttpxRequestAdapter
from src.mt_http_client import MtHttpClient
auth_provider = AnonymousAuthenticationProvider()
request_adapter = HttpxRequestAdapter(auth_provider)
request_adapter.base_url = "https://smsgw.puzzel.com"
client = MtHttpClient(request_adapter)
request = GatewayRequest(
service_id=12345,
username="your_username",
password="your_password",
batch_reference="my-batch-001",
message=[
Message(
recipient="+47xxxxxxxxx",
content="Advanced message",
price=100,
client_reference="msg-ref-001",
settings=Settings(
priority=1,
validity=173,
differentiator="campaign-spring-2026",
invoice_node="marketing-dept",
age=18,
new_session=True,
session_id="session-12345",
auto_detect_encoding=True,
gas_settings=GasSettings(
service_code="02001",
description="Premium SMS"
),
parameter=[
Parameter(key="custom_key", value="custom_value")
]
)
)
]
)
response = await client.gw.rs.send_messages.post(request)
return response
asyncio.run(send_advanced_sms())
Batch Management
List, retrieve, and stop message batches:
import asyncio
async def manage_batches():
from kiota_abstractions.authentication import AnonymousAuthenticationProvider
from kiota_http.httpx_request_adapter import HttpxRequestAdapter
from src.mt_http_client import MtHttpClient
auth_provider = AnonymousAuthenticationProvider()
request_adapter = HttpxRequestAdapter(auth_provider)
request_adapter.base_url = "https://smsgw.puzzel.com"
client = MtHttpClient(request_adapter)
service_id = 12345
batch_reference = "my-batch-001"
# List all batches for a service
batch_list = await client.mgmt.rs.service.by_service_id(service_id).batch.get()
print(f"Total batches: {len(batch_list.message_batch)}")
for batch in batch_list.message_batch:
print(f"Batch: {batch.client_batch_reference}, Total: {batch.total_size}, On Hold: {batch.on_hold}")
# Get details of a specific batch
batch_details = await client.mgmt.rs.service.by_service_id(service_id).batch.by_client_batch_reference(batch_reference).get()
print(f"Batch details: {batch_details.message_batch}")
# Stop a batch
stop_response = await client.mgmt.rs.service.by_service_id(service_id).batch.by_client_batch_reference(batch_reference).delete()
print(f"Stopped {len(stop_response.stopped_messages)} messages")
asyncio.run(manage_batches())
API Reference
Main Client
MtHttpClient: The main entry point for the SDK
API Endpoints
The client provides access to different API versions and endpoints:
client.gw.rs.send_messages: Send messages (recommended endpoint)client.chimera.send_messages: Alternative send messages endpointclient.mgmt.rs.service: Batch management operationsclient.management: Alternative batch management endpoint
Models
All models are located in the src/models/ directory:
GatewayRequest: The main request object for sending messagesGatewayResponse: Response containing batch reference and message statusesMessage: Individual SMS messageSettings: Message-level settingsMessageStatus: Status information for sent messagesSendWindow: Schedule messages for specific time windowsOriginatorSettings: Configure message sender informationGasSettings: GAS (Gateway API Service) configurationParameter: Custom key-value parametersBatchListResponse: List of message batchesBatchSingleResponse: Single batch detailsStopBatchResponse: Response when stopping a batch
Request Builders
Request builders provide a fluent API for constructing requests:
SendMessagesRequestBuilder: Build and execute send message requestsBatchRequestBuilder: Build batch management requests- Various service-specific builders in the
src/directory structure
Error Handling
The client uses Kiota's error handling mechanisms. HTTP errors are mapped to specific exception types:
import asyncio
from src.models.problem_details import ProblemDetails
async def send_with_error_handling():
try:
response = await client.gw.rs.send_messages.post(request)
print(f"Success! Batch: {response.batch_reference}")
except Exception as e:
if hasattr(e, 'error') and isinstance(e.error, ProblemDetails):
print(f"API Error: {e.error.title}")
print(f"Status: {e.error.status}")
print(f"Detail: {e.error.detail}")
else:
print(f"Unexpected error: {e}")
asyncio.run(send_with_error_handling())
Common error status codes:
401 Unauthorized: Invalid credentials404 Not Found: Batch or resource not found400 Bad Request: Invalid request parameters
Testing
Install dev dependencies and run the full test suite:
uv sync
uv run pytest
Run with coverage:
uv run pytest --cov=src --cov-report=term-missing
The tests live in tests/unit/ and cover client initialization, all data models (field access, serialization, deserialization keys), and the request builders. See docs/07-testing.md for the full testing guide, including how to run specific tests, use fixtures, and write new tests.
Migration from v2.x
If you're migrating from the previous puzzel_sms_gateway_client v2.x, here are the key differences:
1. Async/Await Required
The Kiota client is fully asynchronous:
Old (v2.x):
response = client.send(messages=[message])
New (Kiota):
response = await client.gw.rs.send_messages.post(request)
2. Client Initialization
Old (v2.x):
import puzzel_sms_gateway_client as smsgw
client = smsgw.Client(
service_id=SERVICE_ID,
username=USERNAME,
password=PASSWORD,
base_address=BASE_ADDRESS,
)
New (Kiota):
from kiota_abstractions.authentication import AnonymousAuthenticationProvider
from kiota_http.httpx_request_adapter import HttpxRequestAdapter
from src.mt_http_client import MtHttpClient
auth_provider = AnonymousAuthenticationProvider()
request_adapter = HttpxRequestAdapter(auth_provider)
request_adapter.base_url = BASE_ADDRESS
client = MtHttpClient(request_adapter)
3. Credentials in Request
Credentials are now part of each request rather than the client:
Old (v2.x):
client = smsgw.Client(service_id=..., username=..., password=...)
client.send(messages=[...])
New (Kiota):
request = GatewayRequest(
service_id=SERVICE_ID,
username=USERNAME,
password=PASSWORD,
message=[...]
)
await client.gw.rs.send_messages.post(request)
4. Model Structure
Models are now dataclasses with explicit typing:
Old (v2.x):
message = smsgw.Message(
recipient="+47...",
content="Hello",
settings=smsgw.MessageSettings(...)
)
New (Kiota):
from src.models.message import Message
from src.models.settings import Settings
message = Message(
recipient="+47...",
content="Hello",
settings=Settings(...)
)
5. Fluent API
The new client uses a fluent, path-based API:
# Send messages
await client.gw.rs.send_messages.post(request)
# Manage batches
await client.mgmt.rs.service.by_service_id(123).batch.get()
await client.mgmt.rs.service.by_service_id(123).batch.by_client_batch_reference("ref").get()
await client.mgmt.rs.service.by_service_id(123).batch.by_client_batch_reference("ref").delete()
Publishing
To build and publish the package to PyPI using uv:
# 1. Bump the version in pyproject.toml, then build
uv build
# 2. Publish to TestPyPI first (optional but recommended)
uv publish \
--publish-url https://test.pypi.org/legacy/ \
--token pypi-your-test-token-here
# 3. Publish to PyPI
uv publish --token pypi-your-production-token-here
For full details — credential storage, TestPyPI validation, version conventions, and ~/.pypirc setup — see docs/08-publishing.md.
Additional Documentation
For more detailed information, see the documentation in the docs/ folder:
- Documentation Index - Complete documentation index and navigation
- uv Setup Guide - Complete guide for setting up with uv (recommended)
- Getting Started Guide - Step-by-step guide for beginners
- Quick Reference - Cheat sheet for common operations
- Complete Usage Examples - More code examples and use cases
- API Models Reference - Detailed model documentation
- Advanced Topics - Configuration, customization, and best practices
- Testing Guide - Running tests, fixtures, and writing new tests
- Publishing Guide - Building and publishing to PyPI with uv
- Example Code Files - Runnable example scripts
Support
For issues, questions, or contributions, please contact Puzzel support or refer to the main SMS Gateway documentation.
License
Released under the MIT license. See LICENSE for details.
Metadata
Release files for puzzel-sms-gateway-client 3.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| puzzel_sms_gateway_client-3.0.1.tar.gz | 79.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| puzzel_sms_gateway_client-3.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 111.5 kB
Release files / puzzel_sms_gateway_client-3.0.1.tar.gz
| Download URL | puzzel_sms_gateway_client-3.0.1.tar.gz |
|---|---|
| Size | 79.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8f3dc2f59ac02ecfe3de8afba1b4199a0077240f291c6cb1034a37f1f4ac08fd
|
|
BLAKE2b-256 checksum How to use checksums |
2d7cba857c334e5f4b92d3e153eab46c9dc2a13ea768597afa8b0225c5adbaa6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 Apr 17, 2026.
Transparency logRelease files / puzzel_sms_gateway_client-3.0.1-py3-none-any.whl
| Download URL | puzzel_sms_gateway_client-3.0.1-py3-none-any.whl |
|---|---|
| Size | 31.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b9e975b20cecfc7ff207fdd14858f0709aefa88b2167146034514a76025ebece
|
|
BLAKE2b-256 checksum How to use checksums |
3b18010fd301b4eb0865220a1723fd1b60c44e567a3e8bfde0fd038f32c18708
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 Apr 17, 2026.
Transparency log