Skip to content

Repository files navigation

Sinch Python SDK

Python Latest Release License

Here you'll find documentation related to the Sinch Python SDK, including how to install it, initialize it, and start developing Python code using Sinch services.

To use Sinch services, you'll need a Sinch account and access keys. You can sign up for an account and create access keys at dashboard.sinch.com.

Table of contents:

Prerequisites

Warning: This SDK is intended for server-side (backend) use only. Do not use it in front-end or client-side applications (web, mobile, or desktop), regardless of language or framework. Doing so can expose your Sinch credentials to end-users.

Version support

This SDK follows Semantic Versioning for version numbering. SemVer defines what changes are allowed in each type of release (major, minor, patch) but does not define a support or patching policy.

This section describes the support policy for this project.

Release cadence

A new major version will not be released until at least 6 months after the previous major version.

Support policy

Patches are published only for the latest minor release within each supported major version. For example: if version 2.0 exists and 2.1.0 is released, patches will be applied to 2.1.x only. Users on 2.0.x will no longer receive patches and must upgrade to 2.1.x to get bug fixes and security updates.

Version Status Support Timeline
Current major (latest released) Fully supported All new features, bug fixes, and security fixes Ongoing
Previous major Maintenance Critical bug fixes and security fixes only, no new features Begins when current major is released; ends when next major is released or 1 year from current release, whichever comes first
Older majors End-of-Life (EOL) No patches or support —

What are critical bug fixes?

For the previous major version, we apply patches for:

  • Security vulnerabilities
  • Data loss risks
  • Breaking compatibility issues

If you're using an unsupported version

We recommend upgrading to a supported version to receive ongoing security and stability updates. Bug reports against unsupported versions are not prioritized and may not be addressed.

Dependency security updates

We assess dependency vulnerabilities by severity level. High and Critical vulnerabilities (CVSS score ≥ 7.0) are backported to the latest minor release of both the current and previous major versions. Medium and Low severity vulnerabilities (CVSS < 7.0) are applied to the current major version only.

Documentation

For more information on the SDK, refer to the dedicated Python SDK documentation.

For the SDK's programmatic API surface, see the online SDK reference.

For broader Sinch product documentation, including the underlying REST APIs, visit the official Sinch developer portal.

Installation

Run the following command to install the SDK:

pip install sinch

Supported APIs

API Category API Name
Messaging Conversation API
SMS API
Numbers Numbers API
Verification Number Lookup API
Voice Voice API v2 (preview/beta)

Note: The SMS API is end-of-sale. New integrations should use the Conversation API instead, which supports SMS and many other channels.

Getting started

Client initialization

To start using the SDK, initialize the main client class. This client gives you access to all the SDK services:

import os
from sinch import SinchClient

# Warning: not all APIs support project authentication. Check the section for each API before using this snippet.

sinch_client = SinchClient(
    project_id=os.environ["SINCH_PROJECT_ID"],
    key_id=os.environ["SINCH_KEY_ID"],
    key_secret=os.environ["SINCH_KEY_SECRET"],
)

Get project_id, key_id and key_secret from the Access keys page in your Sinch dashboard (key_secret is shown only once, at creation time). It's highly recommended to not hardcode these credentials: load them from environment variables for local development, and from a secret manager in production.

This snippet is the common starting point for every API. Some APIs have a different initialization or need extra parameters (for example, a region), see the section for each API.

Extra fields casing conversion

Every request and response model in the SDK only declares the fields defined by the Sinch APIs. Any other key you pass in on a request, or that the API returns in a response, is considered an extra field. Extra fields are always accepted: on a request they are always sent in the request body, and on a response model they are exposed as regular attributes.

By default, these extra fields are automatically converted to the API's casing standard. So for camelCase APIs, extra fields are converted to camelCase, and for snake_case APIs, extra fields are converted to snake_case.

From version 2.2.0, you can disable this conversion by setting transform_kwargs_casing to False, so extra fields pass through exactly as given in both directions: the field set on a request is sent as-is in the request body, and the field name returned by the API is exposed as-is on the response model.

sinch_client = SinchClient(
    project_id=os.environ["SINCH_PROJECT_ID"],
    key_id=os.environ["SINCH_KEY_ID"],
    key_secret=os.environ["SINCH_KEY_SECRET"],
    transform_kwargs_casing=False,
)

Recommendation: Set transform_kwargs_casing=False in new integrations. This will become the only behavior in 3.0, where extra fields will always pass through unchanged and the flag will be removed.

Conversation API

The Conversation API is regionalized. To use this API, the conversation_region parameter is required:

sinch_client = SinchClient(
    project_id=os.environ["SINCH_PROJECT_ID"],
    key_id=os.environ["SINCH_KEY_ID"],
    key_secret=os.environ["SINCH_KEY_SECRET"],
    conversation_region="eu",
)

Sinch Events

The Conversation API delivers asynchronous Sinch Events to the Event Destination URL you configure for your app in the Conversation dashboard. validate_authentication_header confirms a request comes from Sinch and parse_event turns its payload into a typed event object; headers and raw_body are the incoming request's headers and raw body:

sinch_events = sinch_client.conversation.sinch_events(SINCH_EVENT_SECRET)
is_valid = sinch_events.validate_authentication_header(headers=headers, json_payload=raw_body)
event = sinch_events.parse_event(raw_body, headers)

SINCH_EVENT_SECRET is optional and set per app in the Conversation dashboard. parse_event works without validating the request, but then its origin can't be verified, so calling validate_authentication_header (which returns True/False) is recommended in production.

You can find a complete example in examples/sinch_events/conversation_api.

SMS API

Warning: the SMS API is end-of-sale. For new integrations, prefer the Conversation API.

The SMS API is regionalized: set sms_region to the region where your SMS account is hosted. The accepted values are us, eu, au, br and ca, and the region also determines which credentials you can use:

  • Project access keys — available only in the us and eu regions. Use the same project_id, key_id and key_secret as the common client, plus sms_region:
sinch_client = SinchClient(
    project_id=os.environ["SINCH_PROJECT_ID"],
    key_id=os.environ["SINCH_KEY_ID"],
    key_secret=os.environ["SINCH_KEY_SECRET"],
    sms_region="us",
)

SMS authentication for new projects

Projects created after the SMS API end-of-sale (15/04/26) cannot use project access keys — the SMS API requests return 401 Unauthorized.

If you encounter this issue, consider the following options:

  1. Use service plan credentials (service_plan_id + sms_api_token)
  2. Use the Conversation API, which works with project access keys.
  3. Contact your account manager
  • Service plan — available in all regions (us, eu, au, br, ca). Use a service_plan_id and sms_api_token, both available on the Service APIs dashboard:
sinch_client = SinchClient(
    service_plan_id=os.environ["SINCH_SERVICE_PLAN_ID"],
    sms_api_token=os.environ["SINCH_SMS_API_TOKEN"],
    sms_region="us",
)

Note: if you use both the SMS and the Conversation API from the same client, set sms_region and conversation_region to the same region. Mismatched regions cause delivery failures.

Sinch Events

The SMS API delivers asynchronous Sinch Events to an Event Destination, whose URL is set per batch with the event_destination_target parameter on the send, update and replace operations (for example sinch_client.sms.batches.send_sms). validate_authentication_header confirms a request comes from Sinch and parse_event turns its payload into a typed event object; headers and raw_body are the incoming request's headers and raw body:

sinch_events = sinch_client.sms.sinch_events(SINCH_EVENT_SECRET)
is_valid = sinch_events.validate_authentication_header(headers=headers, json_payload=raw_body)
event = sinch_events.parse_event(raw_body, headers)

Signature authentication for SMS events must be enabled for your account by your account manager; until then the signature headers are absent and parse_event can be used on its own. See the SMS events documentation.

You can find a complete example in examples/sinch_events/sms_api.

Numbers API

The Numbers API needs no extra parameters, use the common client based in project authentication shown above.

Sinch Events

The Numbers API delivers asynchronous Sinch Events to the Event Destination you configure through sinch_client.numbers.event_destinations. validate_authentication_header confirms a request comes from Sinch and parse_event turns its payload into a typed event object; headers and raw_body are the incoming request's headers and raw body:

sinch_events = sinch_client.numbers.sinch_events(SINCH_EVENT_SECRET)
is_valid = sinch_events.validate_authentication_header(headers=headers, json_payload=raw_body)
event = sinch_events.parse_event(raw_body, headers)

SINCH_EVENT_SECRET is the value configured on the Event Destination. parse_event works without validating the request, but then its origin can't be verified, so calling validate_authentication_header is recommended in production.

You can find a complete example in examples/sinch_events/numbers_api.

Number Lookup API

The Number Lookup API needs no extra parameters, use the common client based in project authentication shown above.

Voice API

Note: Support for the Voice API v2 is currently in preview/beta.

The Voice API needs no extra parameters, use the common client based in project authentication shown above.

Your First Request

Once your client is configured, you can send your first message. The example below uses the Conversation API to send a simple text message over SMS. Replace CONVERSATION_APP_ID with your app ID and RECIPIENT_PHONE_NUMBER with the recipient's phone number:

response = sinch_client.conversation.messages.send(
    app_id="CONVERSATION_APP_ID",
    message={
        "text_message": {
            "text": "[Python SDK: Conversation Message] Sample text message",
        },
    },
    recipient_identities=[
        {
            "channel": "SMS",
            "identity": "RECIPIENT_PHONE_NUMBER",
        }
    ],
)

print(f"Successfully sent message.\n{response}")

Logging

Logging configuration for this SDK utilizes following hierarchy:

  1. If no configuration was provided via logger_name or logger configurable, SDK will inherit configuration from the root logger with the Sinch prefix.
  2. If logger_name configurable was provided, SDK will use logger related to that name. For example: myapp.sinch will inherit configuration from the myapp logger.
  3. If logger (logger instance) configurable was provided, SDK will use that particular logger for all its logging operations.

If all logging returned by this SDK needs to be disabled, usage of NullHandler provided by the standard logging module is advised.

Retry configuration

When an API call or OAuth token request returns HTTP 429 (Too Many Requests), the SDK retries automatically. Configure this via RetryConfiguration, passed to SinchClient as retry_configuration; the same settings apply to product API calls and token fetches.

Field Type Default Description
retry_policy RetryPolicy RetryPolicy.DEFAULT DEFAULT: honor Retry-After when present, otherwise exponential backoff. RETRY_AFTER: retry only when a usable Retry-After header is present. BACKOFF: ignore Retry-After and use full-jitter exponential backoff. NONE: disable automatic retries.
max_retries int 3 Maximum retries after the first attempt before the error is surfaced to the caller. Must be zero or greater.
backoff_growth int 4 Growth factor for the backoff ceiling (1000ms * backoff_growth^attempt). The wait is a random value between 0 and that ceiling. Must be one or greater.

Retry-After may be a delay in seconds or an HTTP-date (RFC 7231). A small jitter (0–250 ms) is added so concurrent clients do not retry in lockstep. Invalid values are rejected.

Retry settings

from sinch import SinchClient
from sinch.core.clients.retry_configuration import RetryConfiguration
from sinch.core.enums import RetryPolicy

sinch = SinchClient(
    ...,
    retry_configuration=RetryConfiguration(
        retry_policy=RetryPolicy.BACKOFF,
        max_retries=5,
        backoff_growth=2,
    ),
)

Disable Retry Policy

To disable automatic retries (for example when an outer HTTP layer already honors Retry-After):

from sinch import SinchClient
from sinch.core.clients.retry_configuration import RetryConfiguration
from sinch.core.enums import RetryPolicy

sinch = SinchClient(
    ...,
    retry_configuration=RetryConfiguration(retry_policy=RetryPolicy.NONE),
)

Handling exceptions

Each API throws a custom, API related exception for an unsuccessful backed call.

Example for Numbers API:

from sinch.domains.numbers.api.v1.exceptions import NumbersException

try:
    paginator = sinch_client.numbers.list(
        region_code="US",
        number_type="LOCAL",
    )
except NumbersException as err:
    pass

For handling all possible exceptions thrown by this SDK use SinchException (superclass of all Sinch exceptions) from sinch.core.exceptions.

Custom HTTP client implementation

By default, the HTTP implementation uses the requests library.

To use a custom HTTP client, assign your transport to the client's configuration after initialization.

Custom transports must extend HTTPTransport and implement the send method. The base class provides prepare_request and authenticate helpers, and handles OAuth token refresh automatically.

The following example replaces the default requests backend with httpx and routes traffic through an authenticated proxy:

import httpx
from sinch import SinchClient
from sinch.core.ports.http_transport import HTTPTransport
from sinch.core.models.http_request import HttpRequest
from sinch.core.models.http_response import HTTPResponse


class MyHTTPImplementation(HTTPTransport):
    def __init__(self, sinch, proxy_url, proxy_user, proxy_password):
        super().__init__(sinch)
        self.http_client = httpx.Client(
            proxy=f"http://{proxy_user}:{proxy_password}@{proxy_url}"
        )

    def send_request(self, request_data: HttpRequest) -> HTTPResponse:

        body = request_data.request_body
        response = self.http_client.request(
            method=request_data.http_method,
            url=request_data.url,
            json=body if isinstance(body, dict) else None,
            content=body if not isinstance(body, dict) else None,
            auth=request_data.auth,
            headers=request_data.headers,
            params=request_data.query_params,
            timeout=self.sinch.configuration.connection_timeout,
        )
        response_body = self.deserialize_json_response(response)

        return HTTPResponse(
            status_code=response.status_code,
            body=response_body,
            headers=dict(response.headers),
        )


sinch_client = SinchClient(
    key_id="key_id",
    key_secret="key_secret",
    project_id="some_project",
)
sinch_client.configuration.transport = MyHTTPImplementation(
    sinch_client,
    proxy_url="proxy.example.com:8080",
    proxy_user="proxy_user",
    proxy_password="proxy_password",
)

Note: Asynchronous HTTP clients are not supported. The transport must be a synchronous implementation.

Third-party dependencies

The SDK relies on the following third-party dependencies:

  • requests: HTTP client used as the default transport for all API calls.
  • pydantic: Data validation and serialization for request and response models.

Examples

You can find:

Changelog & Migration

For information about the latest changes in the SDK, please refer to the CHANGELOG file and the MIGRATION_GUIDE for instructions on how to update your code when upgrading to a new major version of the SDK.

License

This project is licensed under the Apache License.

See the LICENSE file for the license text.

Contact

Developer Experience engineering team: team-developer-experience@sinch.com

About

Sinch Python SDK for SMS, Numbers and ConversationAPI

Resources

Stars

8 stars

Watchers

9 watching

Forks

Releases

Packages

Used by

Contributors

Languages