From 48f8f507987ca5eded56ae0c018f8612d7b5e67f Mon Sep 17 00:00:00 2001 From: Marcos Lozano Romero Date: Wed, 10 Jun 2026 09:09:48 +0200 Subject: [PATCH 1/5] chore: unify README structure and content --- README copy.md | 361 +++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 45 ++++-- 2 files changed, 398 insertions(+), 8 deletions(-) create mode 100644 README copy.md diff --git a/README copy.md b/README copy.md new file mode 100644 index 00000000..fc30858a --- /dev/null +++ b/README copy.md @@ -0,0 +1,361 @@ +# Sinch Python SDK + +[![Python 3.9](https://img.shields.io/badge/python-3.9-blue.svg)](https://www.python.org/downloads/release/python-390/) +[![Python 3.10](https://img.shields.io/badge/python-3.10-blue.svg)](https://www.python.org/downloads/release/python-3100/) +[![Python 3.11](https://img.shields.io/badge/python-3.11-blue.svg)](https://www.python.org/downloads/release/python-3110/) +[![Python 3.12](https://img.shields.io/badge/python-3.12-blue.svg)](https://www.python.org/downloads/release/python-3120/) +[![Python 3.13](https://img.shields.io/badge/python-3.13-blue.svg)](https://www.python.org/downloads/release/python-3130/) +[![Python 3.14](https://img.shields.io/badge/python-3.14-blue.svg)](https://www.python.org/downloads/release/python-3140/) + +[![Latest Release](https://img.shields.io/pypi/v/sinch?label=sinch&labelColor=FFC658)](https://pypi.org/project/sinch/) + + +[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://github.com/sinch/sinch-sdk-python/blob/main/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](https://dashboard.sinch.com). + +For more information on the SDK, refer to the dedicated [Python SDK documentation](https://developers.sinch.com/docs/sdks/python) section and for the Sinch APIs on which this SDK is based,official [developer documentation portal](https://developers.sinch.com). + +## Table of contents: + +- [Prerequisites](#prerequisites) +- [Installation](#installation) +- [Getting started](#getting-started) +- [Supported APIs](#supported-apis) +- [Logging](#logging) +- [Handling Exceptions](#handling-exceptions) +- [Third-party dependencies](#third-party-dependencies) +- [Examples](#examples) +- [Changelog and Migration](#changelog--migration) +- [Licence](#licence) +- [Contact](#contact) + + +## Prerequisites + +- [Python](https://www.python.org/) in one of the supported versions - 3.9, 3.10, 3.11, 3.12, 3.13, 3.14 +- [pip](https://pip.pypa.io/en/stable/) +- [Sinch account](https://dashboard.sinch.com/) + +## Installation + +You can install this package by typing: + +```bash +pip install sinch +``` + +## Getting Started + +To start using the SDK, you need to initialize the main client class with your credentials from your Sinch dashboard. It's highly recommended to not hardcode these credentials and to load them from environment variables instead. + + + +## Products + +The Sinch client provides access to the following Sinch products: +- Numbers API +- SMS API +- Conversation API (beta release) + + +## Getting started + + +### Client initialization + +To establish a connection with the Sinch backend, you must provide credentials based on the API you intend to use. +For security best practices, avoid hardcoding credentials — retrieve them from environment variables instead. + +```python +from sinch import SinchClient + +sinch_client = SinchClient( + project_id="project_id", + key_id="key_id", + key_secret="key_secret", +) +``` + +### Authentication + + +#### Project-level Authentication +This is the recommended, default method and the one most Sinch APIs rely on. It uses your project-level [access key](https://dashboard.sinch.com/settings/access-keys). The SDK exchanges them for a short-lived OAuth2 access token and refreshes it automatically. + + +```python +import os +from sinch import SinchClient + +sinch_client = SinchClient( + project_id=os.environ["SINCH_PROJECT_ID"], + key_id=os.environ["SINCH_KEY_ID"], + key_secret=os.environ["SINCH_KEY_SECRET"], + # Set the region for the regionalized API(s) + conversation_region="eu", + sms_region="eu", +) +``` + +**Region parameters** + +Some APIs are regionalized and require you to set their region explicitly. Since +v2.0.0 these parameters have no default, and the SDK raises a runtime error if +you call the API without setting them first (see [MIGRATION_GUIDE.md](MIGRATION_GUIDE.md) +for the upgrade details): + +- `conversation_region` — required for the Conversation API. +- `sms_region` — required for the SMS API (detailed under [SMS Authentication](#sms-authentication)). + +Pass them when you initialize `SinchClient` (as above). They can also be set +afterwards on the `configuration` object, but this must be done **before** the +first call to that API: + +> **Note:** if you use both the SMS and Conversation APIs, `sms_region` and +> `conversation_region` must point to the same region. Mismatched regions +> cause delivery failures. + + +#### SMS authentication + +The SMS API supports two authentication schemes depending on your region: + +- **OAuth2 (US and EU)** — Uses the same project-level [access keys](https://dashboard.sinch.com/settings/access-keys) as above (`projectId`, `keyId`, `keySecret`). + +```python +from sinch import SinchClient + +sinch_client = SinchClient( + project_id="project_id", + key_id="key_id", + key_secret="key_secret", + sms_region="us" +) +``` + +- **Service plan (AU, BR, CA, US and EU)** — Uses a `servicePlanId` and `apiToken` from the [Service APIs dashboard](https://dashboard.sinch.com/sms/api/services). + + +```python +from sinch import SinchClient + +sinch_client = SinchClient( + service_plan_id="service_plan_id", + sms_api_token="api_token", + sms_region="us" +) +``` + +> **SMS authentication for new accounts** +> +> Accounts created after the SMS API end-of-sale (``) cannot use +> project auth (OAuth2) for the SMS API requests return `401 Unauthorized`. +> +> If you hit this error, you have three options: +> +> 1. Use service-plan auth (`servicePlanId` + `apiToken`) +> 2. Use the Conversation API, which supports OAuth2. +> 3. Contact your account manager + + + + + + + +#### SMS API + +The SMS API supports two authentication methods. `sms_region` is required for both and has no default. + +**Project auth (OAuth2)** + +The SDK automatically exchanges your key ID and key secret for a short-lived OAuth2 token and refreshes it automatically on expiry. +Supported regions: `us`, `eu`, `br`. + +In your [Account dashboard](https://dashboard.sinch.com/settings/access-keys), you will find your `projectId` and access keys composed of pairs of `keyId` / `keySecret`. + +> **Note:** the `keySecret` is visible only when you create the Access Key. Store it safely and create a new Access Key if you have lost it. + +```python +from sinch import SinchClient + +sinch_client = SinchClient( + project_id="project_id", + key_id="key_id", + key_secret="key_secret", + sms_region="us" +) +``` + +**Service Plan ID auth (legacy)** + +Uses a static bearer token that never expires. +Support all regions: `us`, `eu`, `br`, `ca`, `au`. + +In your [Service APIs dashboard](https://dashboard.sinch.com/sms/api/services), you will find your `servicePlanId` and `apiToken` (bearer token). + +```python +from sinch import SinchClient + +sinch_client = SinchClient( + service_plan_id="service_plan_id", + sms_api_token="api_token", + sms_region="us" +) +``` + +#### Conversation API - Project auth (OAuth2) + +`conversation_region` is required and has no default. +Supported regions: `us`, `eu`, `br`. + +> **Why region matters:** The Conversation API stores and routes data within the selected region for regulatory compliance. Choose the region that matches your data residency requirements. + +```python +from sinch import SinchClient + +sinch_client = SinchClient( + project_id="project_id", + key_id="key_id", + key_secret="key_secret", + conversation_region="eu" +) +``` + +> **SMS integration note:** If you also use the SMS API, `sms_region` and `conversation_region` **must match**. Mismatched regions will cause delivery failures. + +#### Other APIs - Project auth (OAuth2) + +These APIs are not regionalized and use project-based auth. + +```python +from sinch import SinchClient + +sinch_client = SinchClient( + project_id="project_id", + key_id="key_id", + key_secret="key_secret", +) +``` + +## 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. + + + +## Sample apps + +Usage example of the Numbers API via [`VirtualNumbers`](sinch/domains/numbers/virtual_numbers.py) on the client (`sinch_client.numbers`)—`list()` returns your project’s active virtual numbers: + +```python +paginator = sinch_client.numbers.list( + region_code="US", + number_type="LOCAL", +) +for active_number in paginator.iterator(): + print(active_number) +``` + +Returned values are [Pydantic](https://docs.pydantic.dev/) model instances (for example [`ActiveNumber`](sinch/domains/numbers/models/v1/response/active_number.py)), including fields such as `phone_number`, `region_code`, `type`, and `capabilities`. + +More examples live under [examples/snippets](examples/snippets) on the `main` branch. + +### Handling exceptions + +Each API throws a custom, API related exception for an unsuccessful backed call. + +Example for Numbers API: + +```python +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: + +```python +import httpx +from sinch import SinchClient +from sinch.core.ports.http_transport import HTTPTransport +from sinch.core.endpoint import HTTPEndpoint +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(self, endpoint: HTTPEndpoint) -> HTTPResponse: + request_data = self.prepare_request(endpoint) + request_data = self.authenticate(endpoint, request_data) + + 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. + +## License + +This project is licensed under the Apache License. See the [LICENSE](LICENSE) file for the license text. diff --git a/README.md b/README.md index 92811ffa..18dc93f7 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,5 @@ # Sinch Python SDK -[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://github.com/sinch/sinch-sdk-python/blob/main/LICENSE) - - [![Python 3.9](https://img.shields.io/badge/python-3.9-blue.svg)](https://www.python.org/downloads/release/python-390/) [![Python 3.10](https://img.shields.io/badge/python-3.10-blue.svg)](https://www.python.org/downloads/release/python-3100/) [![Python 3.11](https://img.shields.io/badge/python-3.11-blue.svg)](https://www.python.org/downloads/release/python-3110/) @@ -10,30 +7,52 @@ [![Python 3.13](https://img.shields.io/badge/python-3.13-blue.svg)](https://www.python.org/downloads/release/python-3130/) [![Python 3.14](https://img.shields.io/badge/python-3.14-blue.svg)](https://www.python.org/downloads/release/python-3140/) +[![Latest Release](https://img.shields.io/pypi/v/sinch?label=sinch&labelColor=FFC658)](https://pypi.org/project/sinch/) + + +[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://github.com/sinch/sinch-sdk-python/blob/main/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](https://dashboard.sinch.com). -For more information on the Sinch APIs on which this SDK is based, refer to the official [developer documentation portal](https://developers.sinch.com). +For more information on the SDK, refer to the dedicated [Python SDK documentation](https://developers.sinch.com/docs/sdks/python) section and for the Sinch APIs on which this SDK is based,official [developer documentation portal](https://developers.sinch.com). +## Table of contents: - [Prerequisites](#prerequisites) - [Installation](#installation) - [Getting started](#getting-started) +- [Supported APIs](#supported-apis) - [Logging](#logging) +- [Handling Exceptions](#handling-exceptions) +- [Third-party dependencies](#third-party-dependencies) +- [Examples](#examples) +- [Changelog and Migration](#changelog--migration) +- [Licence](#licence) +- [Contact](#contact) + ## Prerequisites -- Python in one of the supported versions - 3.9, 3.10, 3.11, 3.12, 3.13, 3.14 -- pip -- Sinch account +- [Python](https://www.python.org/) in one of the supported versions - 3.9, 3.10, 3.11, 3.12, 3.13, 3.14 +- [pip](https://pip.pypa.io/en/stable/) +- [Sinch account](https://dashboard.sinch.com/) ## Installation You can install this package by typing: -`pip install sinch` + +```bash +pip install sinch +``` + +## Getting Started + +To start using the SDK, you need to initialize the main client class with your credentials from your Sinch dashboard. It's highly recommended to not hardcode these credentials and to load them from environment variables instead. + + ## Products @@ -51,6 +70,16 @@ The Sinch client provides access to the following Sinch products: To establish a connection with the Sinch backend, you must provide credentials based on the API you intend to use. For security best practices, avoid hardcoding credentials — retrieve them from environment variables instead. +```python +from sinch import SinchClient + +sinch_client = SinchClient( + project_id="project_id", + key_id="key_id", + key_secret="key_secret", +) +``` + > **Note:** `sms_region` and `conversation_region` no longer have defaults and **must** be set before > calling those APIs—omitting them will cause a runtime error. See [MIGRATION_GUIDE.md](MIGRATION_GUIDE.md) for details. From 3ecc6b6148b3ceb17415053ecd11c2331cb51f8f Mon Sep 17 00:00:00 2001 From: Marcos Lozano Romero Date: Wed, 10 Jun 2026 11:27:57 +0200 Subject: [PATCH 2/5] chore: unify README structure and content --- README copy.md | 361 ------------------------------------------------- README.md | 188 ++++++++++++++----------- 2 files changed, 111 insertions(+), 438 deletions(-) delete mode 100644 README copy.md diff --git a/README copy.md b/README copy.md deleted file mode 100644 index fc30858a..00000000 --- a/README copy.md +++ /dev/null @@ -1,361 +0,0 @@ -# Sinch Python SDK - -[![Python 3.9](https://img.shields.io/badge/python-3.9-blue.svg)](https://www.python.org/downloads/release/python-390/) -[![Python 3.10](https://img.shields.io/badge/python-3.10-blue.svg)](https://www.python.org/downloads/release/python-3100/) -[![Python 3.11](https://img.shields.io/badge/python-3.11-blue.svg)](https://www.python.org/downloads/release/python-3110/) -[![Python 3.12](https://img.shields.io/badge/python-3.12-blue.svg)](https://www.python.org/downloads/release/python-3120/) -[![Python 3.13](https://img.shields.io/badge/python-3.13-blue.svg)](https://www.python.org/downloads/release/python-3130/) -[![Python 3.14](https://img.shields.io/badge/python-3.14-blue.svg)](https://www.python.org/downloads/release/python-3140/) - -[![Latest Release](https://img.shields.io/pypi/v/sinch?label=sinch&labelColor=FFC658)](https://pypi.org/project/sinch/) - - -[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://github.com/sinch/sinch-sdk-python/blob/main/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](https://dashboard.sinch.com). - -For more information on the SDK, refer to the dedicated [Python SDK documentation](https://developers.sinch.com/docs/sdks/python) section and for the Sinch APIs on which this SDK is based,official [developer documentation portal](https://developers.sinch.com). - -## Table of contents: - -- [Prerequisites](#prerequisites) -- [Installation](#installation) -- [Getting started](#getting-started) -- [Supported APIs](#supported-apis) -- [Logging](#logging) -- [Handling Exceptions](#handling-exceptions) -- [Third-party dependencies](#third-party-dependencies) -- [Examples](#examples) -- [Changelog and Migration](#changelog--migration) -- [Licence](#licence) -- [Contact](#contact) - - -## Prerequisites - -- [Python](https://www.python.org/) in one of the supported versions - 3.9, 3.10, 3.11, 3.12, 3.13, 3.14 -- [pip](https://pip.pypa.io/en/stable/) -- [Sinch account](https://dashboard.sinch.com/) - -## Installation - -You can install this package by typing: - -```bash -pip install sinch -``` - -## Getting Started - -To start using the SDK, you need to initialize the main client class with your credentials from your Sinch dashboard. It's highly recommended to not hardcode these credentials and to load them from environment variables instead. - - - -## Products - -The Sinch client provides access to the following Sinch products: -- Numbers API -- SMS API -- Conversation API (beta release) - - -## Getting started - - -### Client initialization - -To establish a connection with the Sinch backend, you must provide credentials based on the API you intend to use. -For security best practices, avoid hardcoding credentials — retrieve them from environment variables instead. - -```python -from sinch import SinchClient - -sinch_client = SinchClient( - project_id="project_id", - key_id="key_id", - key_secret="key_secret", -) -``` - -### Authentication - - -#### Project-level Authentication -This is the recommended, default method and the one most Sinch APIs rely on. It uses your project-level [access key](https://dashboard.sinch.com/settings/access-keys). The SDK exchanges them for a short-lived OAuth2 access token and refreshes it automatically. - - -```python -import os -from sinch import SinchClient - -sinch_client = SinchClient( - project_id=os.environ["SINCH_PROJECT_ID"], - key_id=os.environ["SINCH_KEY_ID"], - key_secret=os.environ["SINCH_KEY_SECRET"], - # Set the region for the regionalized API(s) - conversation_region="eu", - sms_region="eu", -) -``` - -**Region parameters** - -Some APIs are regionalized and require you to set their region explicitly. Since -v2.0.0 these parameters have no default, and the SDK raises a runtime error if -you call the API without setting them first (see [MIGRATION_GUIDE.md](MIGRATION_GUIDE.md) -for the upgrade details): - -- `conversation_region` — required for the Conversation API. -- `sms_region` — required for the SMS API (detailed under [SMS Authentication](#sms-authentication)). - -Pass them when you initialize `SinchClient` (as above). They can also be set -afterwards on the `configuration` object, but this must be done **before** the -first call to that API: - -> **Note:** if you use both the SMS and Conversation APIs, `sms_region` and -> `conversation_region` must point to the same region. Mismatched regions -> cause delivery failures. - - -#### SMS authentication - -The SMS API supports two authentication schemes depending on your region: - -- **OAuth2 (US and EU)** — Uses the same project-level [access keys](https://dashboard.sinch.com/settings/access-keys) as above (`projectId`, `keyId`, `keySecret`). - -```python -from sinch import SinchClient - -sinch_client = SinchClient( - project_id="project_id", - key_id="key_id", - key_secret="key_secret", - sms_region="us" -) -``` - -- **Service plan (AU, BR, CA, US and EU)** — Uses a `servicePlanId` and `apiToken` from the [Service APIs dashboard](https://dashboard.sinch.com/sms/api/services). - - -```python -from sinch import SinchClient - -sinch_client = SinchClient( - service_plan_id="service_plan_id", - sms_api_token="api_token", - sms_region="us" -) -``` - -> **SMS authentication for new accounts** -> -> Accounts created after the SMS API end-of-sale (``) cannot use -> project auth (OAuth2) for the SMS API requests return `401 Unauthorized`. -> -> If you hit this error, you have three options: -> -> 1. Use service-plan auth (`servicePlanId` + `apiToken`) -> 2. Use the Conversation API, which supports OAuth2. -> 3. Contact your account manager - - - - - - - -#### SMS API - -The SMS API supports two authentication methods. `sms_region` is required for both and has no default. - -**Project auth (OAuth2)** - -The SDK automatically exchanges your key ID and key secret for a short-lived OAuth2 token and refreshes it automatically on expiry. -Supported regions: `us`, `eu`, `br`. - -In your [Account dashboard](https://dashboard.sinch.com/settings/access-keys), you will find your `projectId` and access keys composed of pairs of `keyId` / `keySecret`. - -> **Note:** the `keySecret` is visible only when you create the Access Key. Store it safely and create a new Access Key if you have lost it. - -```python -from sinch import SinchClient - -sinch_client = SinchClient( - project_id="project_id", - key_id="key_id", - key_secret="key_secret", - sms_region="us" -) -``` - -**Service Plan ID auth (legacy)** - -Uses a static bearer token that never expires. -Support all regions: `us`, `eu`, `br`, `ca`, `au`. - -In your [Service APIs dashboard](https://dashboard.sinch.com/sms/api/services), you will find your `servicePlanId` and `apiToken` (bearer token). - -```python -from sinch import SinchClient - -sinch_client = SinchClient( - service_plan_id="service_plan_id", - sms_api_token="api_token", - sms_region="us" -) -``` - -#### Conversation API - Project auth (OAuth2) - -`conversation_region` is required and has no default. -Supported regions: `us`, `eu`, `br`. - -> **Why region matters:** The Conversation API stores and routes data within the selected region for regulatory compliance. Choose the region that matches your data residency requirements. - -```python -from sinch import SinchClient - -sinch_client = SinchClient( - project_id="project_id", - key_id="key_id", - key_secret="key_secret", - conversation_region="eu" -) -``` - -> **SMS integration note:** If you also use the SMS API, `sms_region` and `conversation_region` **must match**. Mismatched regions will cause delivery failures. - -#### Other APIs - Project auth (OAuth2) - -These APIs are not regionalized and use project-based auth. - -```python -from sinch import SinchClient - -sinch_client = SinchClient( - project_id="project_id", - key_id="key_id", - key_secret="key_secret", -) -``` - -## 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. - - - -## Sample apps - -Usage example of the Numbers API via [`VirtualNumbers`](sinch/domains/numbers/virtual_numbers.py) on the client (`sinch_client.numbers`)—`list()` returns your project’s active virtual numbers: - -```python -paginator = sinch_client.numbers.list( - region_code="US", - number_type="LOCAL", -) -for active_number in paginator.iterator(): - print(active_number) -``` - -Returned values are [Pydantic](https://docs.pydantic.dev/) model instances (for example [`ActiveNumber`](sinch/domains/numbers/models/v1/response/active_number.py)), including fields such as `phone_number`, `region_code`, `type`, and `capabilities`. - -More examples live under [examples/snippets](examples/snippets) on the `main` branch. - -### Handling exceptions - -Each API throws a custom, API related exception for an unsuccessful backed call. - -Example for Numbers API: - -```python -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: - -```python -import httpx -from sinch import SinchClient -from sinch.core.ports.http_transport import HTTPTransport -from sinch.core.endpoint import HTTPEndpoint -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(self, endpoint: HTTPEndpoint) -> HTTPResponse: - request_data = self.prepare_request(endpoint) - request_data = self.authenticate(endpoint, request_data) - - 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. - -## License - -This project is licensed under the Apache License. See the [LICENSE](LICENSE) file for the license text. diff --git a/README.md b/README.md index 18dc93f7..171ff2d2 100644 --- a/README.md +++ b/README.md @@ -27,10 +27,11 @@ For more information on the SDK, refer to the dedicated [Python SDK documentatio - [Supported APIs](#supported-apis) - [Logging](#logging) - [Handling Exceptions](#handling-exceptions) +- [Custom HTTP client implementation](#custom-http-client-implementation) - [Third-party dependencies](#third-party-dependencies) - [Examples](#examples) - [Changelog and Migration](#changelog--migration) -- [Licence](#licence) +- [License](#license) - [Contact](#contact) @@ -42,60 +43,78 @@ For more information on the SDK, refer to the dedicated [Python SDK documentatio ## Installation -You can install this package by typing: +Run the following command to install the SDK: ```bash pip install sinch ``` -## Getting Started -To start using the SDK, you need to initialize the main client class with your credentials from your Sinch dashboard. It's highly recommended to not hardcode these credentials and to load them from environment variables instead. +## Getting started +### Client initialization -## Products +To start using the SDK, you need to initialize the main client class with your credentials from your Sinch dashboard. +It's highly recommended to not hardcode these credentials and to load them from environment variables instead. -The Sinch client provides access to the following Sinch products: -- Numbers API -- SMS API -- Conversation API (beta release) +From this client, you have access to all the SDK services: +```python +from sinch import SinchClient -## Getting started +sinch_client = SinchClient( + project_id="project_id", + key_id="key_id", + key_secret="key_secret", +) +``` +### Authentication -### Client initialization -To establish a connection with the Sinch backend, you must provide credentials based on the API you intend to use. -For security best practices, avoid hardcoding credentials — retrieve them from environment variables instead. +#### Project-level Authentication +This is the recommended, default method and the one most Sinch APIs rely on. It uses your project-level [access key](https://dashboard.sinch.com/settings/access-keys). The SDK exchanges them for a short-lived OAuth2 access token and refreshes it automatically. + ```python +import os from sinch import SinchClient sinch_client = SinchClient( - project_id="project_id", - key_id="key_id", - key_secret="key_secret", + project_id=os.environ["SINCH_PROJECT_ID"], + key_id=os.environ["SINCH_KEY_ID"], + key_secret=os.environ["SINCH_KEY_SECRET"], + # Set the region for the regionalized API(s) + conversation_region="eu", + sms_region="eu", ) ``` -> **Note:** `sms_region` and `conversation_region` no longer have defaults and **must** be set before -> calling those APIs—omitting them will cause a runtime error. See [MIGRATION_GUIDE.md](MIGRATION_GUIDE.md) for details. +**Region parameters** + +Some APIs are regionalized and require you to set their region explicitly. Since +v2.0.0 these parameters have no default, and the SDK raises a runtime error if +you call the API without setting them first (see [MIGRATION_GUIDE.md](MIGRATION_GUIDE.md) +for the upgrade details): +- `conversation_region` — required for the Conversation API. +- `sms_region` — required for the SMS API (detailed under [SMS Authentication](#sms-authentication)). -#### SMS API +Pass them when you initialize `SinchClient` (as above). They can also be set +afterwards on the `configuration` object, but this must be done before the +first call to that API: -The SMS API supports two authentication methods. `sms_region` is required for both and has no default. +> **Note:** if you use both the SMS and Conversation APIs, `sms_region` and +> `conversation_region` must point to the same region. Mismatched regions +> cause delivery failures. -**Project auth (OAuth2)** -The SDK automatically exchanges your key ID and key secret for a short-lived OAuth2 token and refreshes it automatically on expiry. -Supported regions: `us`, `eu`, `br`. +#### SMS authentication -In your [Account dashboard](https://dashboard.sinch.com/settings/access-keys), you will find your `projectId` and access keys composed of pairs of `keyId` / `keySecret`. +The SMS API supports two authentication schemes depending on your region: -> **Note:** the `keySecret` is visible only when you create the Access Key. Store it safely and create a new Access Key if you have lost it. +- **OAuth2 (US and EU)** — Uses the same project-level [access keys](https://dashboard.sinch.com/settings/access-keys) as above (`projectId`, `keyId`, `keySecret`). ```python from sinch import SinchClient @@ -108,12 +127,8 @@ sinch_client = SinchClient( ) ``` -**Service Plan ID auth (legacy)** +- **Service plan (AU, BR, CA, US and EU)** — Uses a `servicePlanId` and `apiToken` from the [Service APIs dashboard](https://dashboard.sinch.com/sms/api/services). -Uses a static bearer token that never expires. -Support all regions: `us`, `eu`, `br`, `ca`, `au`. - -In your [Service APIs dashboard](https://dashboard.sinch.com/sms/api/services), you will find your `servicePlanId` and `apiToken` (bearer token). ```python from sinch import SinchClient @@ -125,39 +140,52 @@ sinch_client = SinchClient( ) ``` -#### Conversation API - Project auth (OAuth2) +> **SMS authentication for new accounts** +> +> Accounts created after the SMS API end-of-sale (`15/04/26`) cannot use +> project-level authentication the SMS API requests return `401 Unauthorized`. +> +> If you encounter this issue, consider the following options: +> +> 1. Use service-plan authentication (`servicePlanId` + `apiToken`) +> 2. Use the Conversation API, which supports project-level authentication. +> 3. Contact your account manager -`conversation_region` is required and has no default. -Supported regions: `us`, `eu`, `br`. -> **Why region matters:** The Conversation API stores and routes data within the selected region for regulatory compliance. Choose the region that matches your data residency requirements. -```python -from sinch import SinchClient +### Your First Request -sinch_client = SinchClient( - project_id="project_id", - key_id="key_id", - key_secret="key_secret", - conversation_region="eu" +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 RCS. Replace CONVERSATION_APP_ID with your app ID and RECIPIENT_PHONE_NUMBER with the recipient's phone number: + +```python +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": "RCS", + "identity": "RECIPIENT_PHONE_NUMBER", + } + ], ) + +print(f"Successfully sent message.\n{response}") ``` -> **SMS integration note:** If you also use the SMS API, `sms_region` and `conversation_region` **must match**. Mismatched regions will cause delivery failures. +## Supported APIs -#### Other APIs - Project auth (OAuth2) -These APIs are not regionalized and use project-based auth. +| API Category | API Name | Authentication | +|-------------------|------------------------|----------------| +| Messaging | Conversation API | OAuth2 | +| Messaging | SMS | OAuth2, APP | +| Numbers | Numbers API | OAuth2 | +| Verification | Number Lookup API | OAuth2 | -```python -from sinch import SinchClient - -sinch_client = SinchClient( - project_id="project_id", - key_id="key_id", - key_secret="key_secret", -) -``` ## Logging @@ -168,26 +196,7 @@ Logging configuration for this SDK utilizes following hierarchy: If all logging returned by this SDK needs to be disabled, usage of `NullHandler` provided by the standard `logging` module is advised. - - -## Sample apps - -Usage example of the Numbers API via [`VirtualNumbers`](sinch/domains/numbers/virtual_numbers.py) on the client (`sinch_client.numbers`)—`list()` returns your project’s active virtual numbers: - -```python -paginator = sinch_client.numbers.list( - region_code="US", - number_type="LOCAL", -) -for active_number in paginator.iterator(): - print(active_number) -``` - -Returned values are [Pydantic](https://docs.pydantic.dev/) model instances (for example [`ActiveNumber`](sinch/domains/numbers/models/v1/response/active_number.py)), including fields such as `phone_number`, `region_code`, `type`, and `capabilities`. - -More examples live under [examples/snippets](examples/snippets) on the `main` branch. - -### Handling exceptions +## Handling exceptions Each API throws a custom, API related exception for an unsuccessful backed call. @@ -207,7 +216,6 @@ except NumbersException as err: 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. @@ -270,9 +278,35 @@ sinch_client.configuration.transport = MyHTTPImplementation( ) ``` -Note: Asynchronous HTTP clients are not supported. -The transport must be a synchronous implementation. +> **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](https://requests.readthedocs.io/): HTTP client used as the default transport for all API calls. +- [pydantic](https://docs.pydantic.dev/): Data validation and serialization for request and response models. + +## Examples + +You can find: + - a Python example of each request in the [examples/snippets](./examples/snippets) folder. + - getting started guides for specific use cases in the [examples/getting-started](./examples/getting-started) folder. + - server-side event handling examples in the [examples/sinch_events](./examples/sinch_events) folder. + +## Changelog & Migration + +For information about the latest changes in the SDK, please refer to the [CHANGELOG](CHANGELOG.md) file +and the [MIGRATION-GUIDE](MIGRATION-GUIDE.md) 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](LICENSE) file for the license text. +This project is licensed under the Apache License. + +See the [LICENSE](LICENSE) file for the license text. + + +## Contact + +Developer Experience engineering team: [team-developer-experience@sinch.com](mailto:team-developer-experience@sinch.com) + From 7cd2a9e0983a5db42f8189dd6712d4c2f60a3481 Mon Sep 17 00:00:00 2001 From: Marcos Lozano Romero Date: Tue, 16 Jun 2026 16:56:49 +0200 Subject: [PATCH 3/5] chore: unify README content and structure --- README.md | 184 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 103 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index 171ff2d2..261a6365 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,21 @@ # Sinch Python SDK -[![Python 3.9](https://img.shields.io/badge/python-3.9-blue.svg)](https://www.python.org/downloads/release/python-390/) -[![Python 3.10](https://img.shields.io/badge/python-3.10-blue.svg)](https://www.python.org/downloads/release/python-3100/) -[![Python 3.11](https://img.shields.io/badge/python-3.11-blue.svg)](https://www.python.org/downloads/release/python-3110/) -[![Python 3.12](https://img.shields.io/badge/python-3.12-blue.svg)](https://www.python.org/downloads/release/python-3120/) -[![Python 3.13](https://img.shields.io/badge/python-3.13-blue.svg)](https://www.python.org/downloads/release/python-3130/) -[![Python 3.14](https://img.shields.io/badge/python-3.14-blue.svg)](https://www.python.org/downloads/release/python-3140/) - -[![Latest Release](https://img.shields.io/pypi/v/sinch?label=sinch&labelColor=FFC658)](https://pypi.org/project/sinch/) - - -[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://github.com/sinch/sinch-sdk-python/blob/main/LICENSE) +[![Python](https://img.shields.io/badge/python-blue.svg)](https://www.python.org/) [![Latest Release](https://img.shields.io/pypi/v/sinch?label=sinch&labelColor=FFC658)](https://pypi.org/project/sinch/) [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://github.com/sinch/sinch-sdk-python/blob/main/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](https://dashboard.sinch.com). -For more information on the SDK, refer to the dedicated [Python SDK documentation](https://developers.sinch.com/docs/sdks/python) section and for the Sinch APIs on which this SDK is based,official [developer documentation portal](https://developers.sinch.com). +For more information on the SDK, refer to the dedicated [Python SDK documentation](https://developers.sinch.com/docs/sdks/python) section, and for the Sinch APIs on which this SDK is based, refer to the official [developer documentation portal](https://developers.sinch.com). + ## Table of contents: - [Prerequisites](#prerequisites) - [Installation](#installation) -- [Getting started](#getting-started) - [Supported APIs](#supported-apis) +- [Getting started](#getting-started) - [Logging](#logging) - [Handling Exceptions](#handling-exceptions) - [Custom HTTP client implementation](#custom-http-client-implementation) @@ -37,10 +28,13 @@ For more information on the SDK, refer to the dedicated [Python SDK documentatio ## Prerequisites -- [Python](https://www.python.org/) in one of the supported versions - 3.9, 3.10, 3.11, 3.12, 3.13, 3.14 +- [Python](https://www.python.org/) in one of the supported versions - [3.9](https://www.python.org/downloads/release/python-390/), [3.10](https://www.python.org/downloads/release/python-3100/), [3.11](https://www.python.org/downloads/release/python-3110/), [3.12](https://www.python.org/downloads/release/python-3120/), [3.13](https://www.python.org/downloads/release/python-3130/), [3.14](https://www.python.org/downloads/release/python-3140/) - [pip](https://pip.pypa.io/en/stable/) - [Sinch account](https://dashboard.sinch.com/) +> **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. + ## Installation Run the following command to install the SDK: @@ -50,112 +44,151 @@ pip install sinch ``` +## Supported APIs + + +| API Category | API Name | +|-------------------|-----------------------------| +| Messaging | [Conversation API](#conversation-api) [[link]](https://developers.sinch.com/docs/conversation/) | +| Messaging | [SMS](#sms-api) [[link]](https://developers.sinch.com/docs/sms/) | +| Numbers | [Numbers API](#numbers-api) [[link]](https://developers.sinch.com/docs/numbers/) | +| Verification | [Number Lookup API](#number-lookup-api) [[link]](https://developers.sinch.com/docs/number-lookup/) | + + ## Getting started ### Client initialization -To start using the SDK, you need to initialize the main client class with your credentials from your Sinch dashboard. -It's highly recommended to not hardcode these credentials and to load them from environment variables instead. - -From this client, you have access to all the SDK services: +To start using the SDK, initialize the main client class. This client gives you access to all the SDK services: ```python +import os from sinch import SinchClient +# Warning: project authentication, check if the API used supports it or has additional parameters sinch_client = SinchClient( - project_id="project_id", - key_id="key_id", - key_secret="key_secret", + project_id=os.environ["SINCH_PROJECT_ID"], + key_id=os.environ["SINCH_KEY_ID"], + key_secret=os.environ["SINCH_KEY_SECRET"], ) ``` -### Authentication +Get `project_id`, `key_id` and `key_secret` from the [Access keys](https://dashboard.sinch.com/settings/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. -#### Project-level Authentication -This is the recommended, default method and the one most Sinch APIs rely on. It uses your project-level [access key](https://dashboard.sinch.com/settings/access-keys). The SDK exchanges them for a short-lived OAuth2 access token and refreshes it automatically. +### Conversation API +The Conversation API is regionalized. To use this API, the `conversation_region` parameter is required: ```python -import os -from sinch import SinchClient - sinch_client = SinchClient( project_id=os.environ["SINCH_PROJECT_ID"], key_id=os.environ["SINCH_KEY_ID"], key_secret=os.environ["SINCH_KEY_SECRET"], - # Set the region for the regionalized API(s) conversation_region="eu", - sms_region="eu", ) ``` -**Region parameters** +#### Sinch Events -Some APIs are regionalized and require you to set their region explicitly. Since -v2.0.0 these parameters have no default, and the SDK raises a runtime error if -you call the API without setting them first (see [MIGRATION_GUIDE.md](MIGRATION_GUIDE.md) -for the upgrade details): +The Conversation API delivers asynchronous Sinch Events to the Event Destination URL you configure for your app in the [Conversation dashboard](https://dashboard.sinch.com/convapi/apps). `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: -- `conversation_region` — required for the Conversation API. -- `sms_region` — required for the SMS API (detailed under [SMS Authentication](#sms-authentication)). +```python +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) +``` -Pass them when you initialize `SinchClient` (as above). They can also be set -afterwards on the `configuration` object, but this must be done before the -first call to that API: +`SINCH_EVENT_SECRET` is optional and set per app in the [Conversation dashboard](https://dashboard.sinch.com/convapi/apps). `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. -> **Note:** if you use both the SMS and Conversation APIs, `sms_region` and -> `conversation_region` must point to the same region. Mismatched regions -> cause delivery failures. +You can find a complete example in [examples/sinch_events/conversation_api](./examples/sinch_events/conversation_api). +### SMS API -#### SMS authentication +> **Warning:** the SMS API is end-of-sale. For new integrations, prefer the [Conversation API](#conversation-api). -The SMS API supports two authentication schemes depending on your region: +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: -- **OAuth2 (US and EU)** — Uses the same project-level [access keys](https://dashboard.sinch.com/settings/access-keys) as above (`projectId`, `keyId`, `keySecret`). +- **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`: ```python -from sinch import SinchClient - sinch_client = SinchClient( - project_id="project_id", - key_id="key_id", - key_secret="key_secret", - sms_region="us" + project_id=os.environ["SINCH_PROJECT_ID"], + key_id=os.environ["SINCH_KEY_ID"], + key_secret=os.environ["SINCH_KEY_SECRET"], + sms_region="us", ) ``` -- **Service plan (AU, BR, CA, US and EU)** — Uses a `servicePlanId` and `apiToken` from the [Service APIs dashboard](https://dashboard.sinch.com/sms/api/services). +> **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 -```python -from sinch import SinchClient +- **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](https://dashboard.sinch.com/sms/api/services): +```python sinch_client = SinchClient( - service_plan_id="service_plan_id", - sms_api_token="api_token", - sms_region="us" + service_plan_id=os.environ["SINCH_SERVICE_PLAN_ID"], + sms_api_token=os.environ["SINCH_SMS_API_TOKEN"], + sms_region="us", ) ``` -> **SMS authentication for new accounts** -> -> Accounts created after the SMS API end-of-sale (`15/04/26`) cannot use -> project-level authentication the SMS API requests return `401 Unauthorized`. -> -> If you encounter this issue, consider the following options: -> -> 1. Use service-plan authentication (`servicePlanId` + `apiToken`) -> 2. Use the Conversation API, which supports project-level authentication. -> 3. Contact your account manager +> **Note:** if you use both the SMS and the [Conversation API](#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: + +```python +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](https://developers.sinch.com/docs/sms/api-reference/sms/tag/Webhooks/#tag/Webhooks/section/Callbacks). + +You can find a complete example in [examples/sinch_events/sms_api](./examples/sinch_events/sms_api). + +### Numbers API + +The Numbers API needs no extra parameters, use the [common client](#client-initialization) 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: + +```python +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](./examples/sinch_events/numbers_api). + +### Number Lookup API + +The Number Lookup API needs no extra parameters, use the [common client](#client-initialization) 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 RCS. Replace CONVERSATION_APP_ID with your app ID and RECIPIENT_PHONE_NUMBER with the recipient's phone number: +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: ```python response = sinch_client.conversation.messages.send( @@ -167,7 +200,7 @@ response = sinch_client.conversation.messages.send( }, recipient_identities=[ { - "channel": "RCS", + "channel": "SMS", "identity": "RECIPIENT_PHONE_NUMBER", } ], @@ -176,17 +209,6 @@ response = sinch_client.conversation.messages.send( print(f"Successfully sent message.\n{response}") ``` -## Supported APIs - - -| API Category | API Name | Authentication | -|-------------------|------------------------|----------------| -| Messaging | Conversation API | OAuth2 | -| Messaging | SMS | OAuth2, APP | -| Numbers | Numbers API | OAuth2 | -| Verification | Number Lookup API | OAuth2 | - - ## Logging Logging configuration for this SDK utilizes following hierarchy: @@ -297,7 +319,7 @@ You can find: ## Changelog & Migration For information about the latest changes in the SDK, please refer to the [CHANGELOG](CHANGELOG.md) file -and the [MIGRATION-GUIDE](MIGRATION-GUIDE.md) for instructions on how to update your code when upgrading to a new major version of the SDK. +and the [MIGRATION_GUIDE](MIGRATION_GUIDE.md) for instructions on how to update your code when upgrading to a new major version of the SDK. ## License From d7f012bdc246d9c4c65f23d5918b49c185e9c676 Mon Sep 17 00:00:00 2001 From: Marcos Lozano Romero Date: Tue, 16 Jun 2026 17:26:51 +0200 Subject: [PATCH 4/5] chore: update API links in README for consistency --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 261a6365..c82c8ee6 100644 --- a/README.md +++ b/README.md @@ -49,10 +49,10 @@ pip install sinch | API Category | API Name | |-------------------|-----------------------------| -| Messaging | [Conversation API](#conversation-api) [[link]](https://developers.sinch.com/docs/conversation/) | -| Messaging | [SMS](#sms-api) [[link]](https://developers.sinch.com/docs/sms/) | -| Numbers | [Numbers API](#numbers-api) [[link]](https://developers.sinch.com/docs/numbers/) | -| Verification | [Number Lookup API](#number-lookup-api) [[link]](https://developers.sinch.com/docs/number-lookup/) | +| Messaging | [Conversation API](https://developers.sinch.com/docs/conversation/) | +| Messaging | [SMS](https://developers.sinch.com/docs/sms/) | +| Numbers | [Numbers API](https://developers.sinch.com/docs/numbers/) | +| Verification | [Number Lookup API](https://developers.sinch.com/docs/number-lookup/) | ## Getting started From 4acf7b298e47f1b47a83c852bab34232f72f7371 Mon Sep 17 00:00:00 2001 From: Marcos Lozano Romero Date: Wed, 17 Jun 2026 17:06:54 +0200 Subject: [PATCH 5/5] chore: update SMS link to include 'API' for clarity and improve warning message in README --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c82c8ee6..707f1aa3 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ pip install sinch | API Category | API Name | |-------------------|-----------------------------| | Messaging | [Conversation API](https://developers.sinch.com/docs/conversation/) | -| Messaging | [SMS](https://developers.sinch.com/docs/sms/) | +| Messaging | [SMS API](https://developers.sinch.com/docs/sms/) | | Numbers | [Numbers API](https://developers.sinch.com/docs/numbers/) | | Verification | [Number Lookup API](https://developers.sinch.com/docs/number-lookup/) | @@ -66,7 +66,8 @@ To start using the SDK, initialize the main client class. This client gives you import os from sinch import SinchClient -# Warning: project authentication, check if the API used supports it or has additional parameters +# 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"],