From 0995a1e7d357468acd0ef881c93be82805944c33 Mon Sep 17 00:00:00 2001 From: marcos-sinch Date: Fri, 22 May 2026 15:14:21 +0200 Subject: [PATCH 1/3] chore: update README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7d72bfc8..744b11e7 100644 --- a/README.md +++ b/README.md @@ -136,14 +136,14 @@ For handling all possible exceptions thrown by this SDK use `SinchException` (su By default, the HTTP implementation uses the `requests` library. -To use a custom HTTP client, inject your own transport during initialization: +To use a custom HTTP client, assign your transport to the client's configuration after initialization: ```python sinch_client = SinchClient( key_id="key_id", key_secret="key_secret", project_id="some_project", - transport=MyHTTPImplementation ) +sinch_client.configuration.transport = MyHTTPImplementation(sinch_client) ``` Custom client has to obey types and methods described by `HTTPTransport` abstract base class: From 1e797a386298de7ad1d59df38929dc8a1aecb744 Mon Sep 17 00:00:00 2001 From: marcos-sinch Date: Mon, 25 May 2026 12:07:50 +0200 Subject: [PATCH 2/3] chore: update README --- README.md | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 744b11e7..21d2131e 100644 --- a/README.md +++ b/README.md @@ -48,40 +48,46 @@ The Sinch client provides access to the following Sinch products: ### Client initialization - To establish a connection with the Sinch backend, you must provide the appropriate credentials based on the API you intend to use. For security best practices, avoid hardcoding credentials. Instead, retrieve them from environment variables. -#### SMS API -For the SMS API in **Australia (AU)**, **Brazil (BR)**, **Canada (CA)**, **the United States (US)**, -and **the European Union (EU)**, provide the following parameters: +#### Project auth + +The standard authentication method for all Sinch APIs. +If you plan to use more than one API, or if you need access to the Conversation API, use this method. + +When using the SMS API, also pass `sms_region`. When using the Conversation API, also pass `conversation_region`. +Both are required for their respective APIs and have no default value. ```python from sinch import SinchClient sinch_client = SinchClient( - service_plan_id="service_plan_id", - sms_api_token="api_token" + project_id="project_id", + key_id="key_id", + key_secret="key_secret", + sms_region="us", # required if using the SMS API + conversation_region="eu", # required if using the Conversation API ) ``` -#### All Other Sinch APIs -For all other Sinch APIs, including SMS in US and EU regions, use the following parameters: +#### SMS token auth + +An alternative authentication method exclusive to the SMS API. ```python from sinch import SinchClient sinch_client = SinchClient( - project_id="project_id", - key_id="key_id", - key_secret="key_secret" + service_plan_id="service_plan_id", + sms_api_token="api_token", + sms_region="us", ) ``` -### SMS and Conversation regions (V2) - -You must set `sms_region` before using the SMS API and `conversation_region` before using the Conversation API—either in the `SinchClient(...)` constructor or on `sinch_client.configuration` before the first call to that product. See [MIGRATION_GUIDE.md](MIGRATION_GUIDE.md) for examples. +> **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. ## Logging From 2a3ad230fa5d9790c832236fbbd37c266d48b54b Mon Sep 17 00:00:00 2001 From: marcos-sinch Date: Mon, 25 May 2026 17:18:49 +0200 Subject: [PATCH 3/3] chore: update README --- README.md | 125 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 100 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 21d2131e..9d3143c0 100644 --- a/README.md +++ b/README.md @@ -48,17 +48,21 @@ The Sinch client provides access to the following Sinch products: ### Client initialization -To establish a connection with the Sinch backend, you must provide the appropriate credentials based on the API -you intend to use. For security best practices, avoid hardcoding credentials. -Instead, retrieve them from environment variables. +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. + +> **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. -#### Project auth -The standard authentication method for all Sinch APIs. -If you plan to use more than one API, or if you need access to the Conversation API, use this method. +#### SMS API -When using the SMS API, also pass `sms_region`. When using the Conversation API, also pass `conversation_region`. -Both are required for their respective APIs and have no default value. +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`. ```python from sinch import SinchClient @@ -67,14 +71,14 @@ sinch_client = SinchClient( project_id="project_id", key_id="key_id", key_secret="key_secret", - sms_region="us", # required if using the SMS API - conversation_region="eu", # required if using the Conversation API + sms_region="us" ) ``` -#### SMS token auth +**Service Plan ID auth (legacy)** -An alternative authentication method exclusive to the SMS API. +Uses a static bearer token that never expires. +Support all regions: `us`, `eu`, `br`, `ca`, `au`. ```python from sinch import SinchClient @@ -82,12 +86,43 @@ from sinch import SinchClient sinch_client = SinchClient( service_plan_id="service_plan_id", sms_api_token="api_token", - sms_region="us", + sms_region="us" ) ``` -> **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. +#### 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 @@ -142,22 +177,62 @@ For handling all possible exceptions thrown by this SDK use `SinchException` (su 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: +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) -``` - -Custom client has to obey types and methods described by `HTTPTransport` abstract base class: -```python -class HTTPTransport(ABC): - @abstractmethod - def request(self, endpoint: HTTPEndpoint) -> HTTPResponse: - pass +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.