Skip to content

Repository files navigation

Puzzel SMS Gateway Python Client

GitHub LicenseLatest VersionSupported Python versionsDownloadsCoverageGitHub issuesGitHub last commit

Copyright 2024-2026 Puzzel AS

Contents

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 abstractions
  • microsoft-kiota-http>=1.0.0 - HTTP request handling
  • microsoft-kiota-serialization-json>=1.0.0 - JSON serialization
  • microsoft-kiota-serialization-text>=1.0.0 - Text serialization
  • microsoft-kiota-serialization-form>=1.0.0 - Form serialization
  • microsoft-kiota-serialization-multipart>=1.0.0 - Multipart serialization
  • httpx>=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 environmentsource .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 init typically creates .venv/ automatically, but you can use --seed to explicitly ensure that pip, setuptools, and wheel are installed.

Using pip

pip install puzzel-sms-gateway-client

Quick Start

importasynciofromkiota_abstractions.authenticationimportAnonymousAuthenticationProviderfromkiota_http.httpx_request_adapterimportHttpxRequestAdapterfromsrc.mt_http_clientimportMtHttpClientfromsrc.models.gateway_requestimportGatewayRequestfromsrc.models.messageimportMessageasyncdefsend_sms():
# Set up authentication and HTTP adapterauth_provider=AnonymousAuthenticationProvider()
request_adapter=HttpxRequestAdapter(auth_provider)
request_adapter.base_url="https://smsgw.puzzel.com"# Create the clientclient=MtHttpClient(request_adapter)
# Create a messagegateway_request=GatewayRequest(
service_id=YOUR_SERVICE_ID, # Your Puzzel service IDusername="YOUR_USERNAME", # Your Puzzel usernamepassword="YOUR_PASSWORD", # Your Puzzel passwordmessage=[
Message(
recipient="+47xxxxxxxxx", # Phone number with country codecontent="Hello World!"
)
]
)
# Send the messageresponse=awaitclient.gw.rs.send_messages.post(gateway_request)
print(f"Batch Reference: {response.batch_reference}")
forstatusinresponse.message_status:
print(f"Message ID: {status.message_id}")
print(f"Status: {status.status_message}")
# Run the async functionasyncio.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:

# ✅ Correctrequest_adapter.base_url="https://smsgw.puzzel.com"# ❌ Wrong - don't include the pathrequest_adapter.base_url="https://smsgw.puzzel.com/gw/rs"

The client automatically constructs the full URL path based on the API method you call.

fromkiota_abstractions.authenticationimportAnonymousAuthenticationProviderfromkiota_http.httpx_request_adapterimportHttpxRequestAdapter# Use AnonymousAuthenticationProvider since credentials are in the request bodyauth_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:

importasynciofromkiota_abstractions.authenticationimportAnonymousAuthenticationProviderfromkiota_http.httpx_request_adapterimportHttpxRequestAdapterfromsrc.mt_http_clientimportMtHttpClientfromsrc.models.gateway_requestimportGatewayRequestfromsrc.models.messageimportMessageasyncdefsend_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=awaitclient.gw.rs.send_messages.post(request)
returnresponseasyncio.run(send_basic_sms())

Sending with Message Settings

Send an SMS with advanced settings like send window, originator, and priority:

importasynciofromsrc.mt_http_clientimportMtHttpClientfromsrc.models.gateway_requestimportGatewayRequestfromsrc.models.messageimportMessagefromsrc.models.settingsimportSettingsfromsrc.models.send_windowimportSendWindowfromsrc.models.originator_settingsimportOriginatorSettingsfromsrc.models.originator_typeimportOriginatorTypeasyncdefsend_scheduled_sms():
fromkiota_abstractions.authenticationimportAnonymousAuthenticationProviderfromkiota_http.httpx_request_adapterimportHttpxRequestAdapterfromsrc.mt_http_clientimportMtHttpClientauth_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=awaitclient.gw.rs.send_messages.post(request)
returnresponseasyncio.run(send_scheduled_sms())

Advanced Configuration

Send an SMS with all available options:

importasynciofromsrc.models.gateway_requestimportGatewayRequestfromsrc.models.messageimportMessagefromsrc.models.settingsimportSettingsfromsrc.models.gas_settingsimportGasSettingsfromsrc.models.parameterimportParameterasyncdefsend_advanced_sms():
fromkiota_abstractions.authenticationimportAnonymousAuthenticationProviderfromkiota_http.httpx_request_adapterimportHttpxRequestAdapterfromsrc.mt_http_clientimportMtHttpClientauth_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=awaitclient.gw.rs.send_messages.post(request)
returnresponseasyncio.run(send_advanced_sms())

Batch Management

List, retrieve, and stop message batches:

importasyncioasyncdefmanage_batches():
fromkiota_abstractions.authenticationimportAnonymousAuthenticationProviderfromkiota_http.httpx_request_adapterimportHttpxRequestAdapterfromsrc.mt_http_clientimportMtHttpClientauth_provider=AnonymousAuthenticationProvider()
request_adapter=HttpxRequestAdapter(auth_provider)
request_adapter.base_url="https://smsgw.puzzel.com"client=MtHttpClient(request_adapter)
service_id=12345batch_reference="my-batch-001"# List all batches for a servicebatch_list=awaitclient.mgmt.rs.service.by_service_id(service_id).batch.get()
print(f"Total batches: {len(batch_list.message_batch)}")
forbatchinbatch_list.message_batch:
print(f"Batch: {batch.client_batch_reference}, Total: {batch.total_size}, On Hold: {batch.on_hold}")
# Get details of a specific batchbatch_details=awaitclient.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 batchstop_response=awaitclient.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 endpoint
  • client.mgmt.rs.service: Batch management operations
  • client.management: Alternative batch management endpoint

Models

All models are located in the src/models/ directory:

  • GatewayRequest: The main request object for sending messages
  • GatewayResponse: Response containing batch reference and message statuses
  • Message: Individual SMS message
  • Settings: Message-level settings
  • MessageStatus: Status information for sent messages
  • SendWindow: Schedule messages for specific time windows
  • OriginatorSettings: Configure message sender information
  • GasSettings: GAS (Gateway API Service) configuration
  • Parameter: Custom key-value parameters
  • BatchListResponse: List of message batches
  • BatchSingleResponse: Single batch details
  • StopBatchResponse: Response when stopping a batch

Request Builders

Request builders provide a fluent API for constructing requests:

  • SendMessagesRequestBuilder: Build and execute send message requests
  • BatchRequestBuilder: 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:

importasynciofromsrc.models.problem_detailsimportProblemDetailsasyncdefsend_with_error_handling():
try:
response=awaitclient.gw.rs.send_messages.post(request)
print(f"Success! Batch: {response.batch_reference}")
exceptExceptionase:
ifhasattr(e, 'error') andisinstance(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 credentials
  • 404 Not Found: Batch or resource not found
  • 400 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=awaitclient.gw.rs.send_messages.post(request)

2. Client Initialization

Old (v2.x):

importpuzzel_sms_gateway_clientassmsgwclient=smsgw.Client(
service_id=SERVICE_ID,
username=USERNAME,
password=PASSWORD,
base_address=BASE_ADDRESS,
)

New (Kiota):

fromkiota_abstractions.authenticationimportAnonymousAuthenticationProviderfromkiota_http.httpx_request_adapterimportHttpxRequestAdapterfromsrc.mt_http_clientimportMtHttpClientauth_provider=AnonymousAuthenticationProvider()
request_adapter=HttpxRequestAdapter(auth_provider)
request_adapter.base_url=BASE_ADDRESSclient=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=[...]
)
awaitclient.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):

fromsrc.models.messageimportMessagefromsrc.models.settingsimportSettingsmessage=Message(
recipient="+47...",
content="Hello",
settings=Settings(...)
)

5. Fluent API

The new client uses a fluent, path-based API:

# Send messagesawaitclient.gw.rs.send_messages.post(request)
# Manage batchesawaitclient.mgmt.rs.service.by_service_id(123).batch.get()
awaitclient.mgmt.rs.service.by_service_id(123).batch.by_client_batch_reference("ref").get()
awaitclient.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:

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.

About

Python client library for Puzzel SMS Gateway

Resources

Stars

1 star

Watchers

6 watching

Forks

Releases

Packages

Used by

Contributors

Languages