Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 102 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,40 +48,81 @@ The Sinch client provides access to the following Sinch products:

### 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.

> **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.

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:

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

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`.

```python
from sinch import SinchClient

sinch_client = SinchClient(
service_plan_id="service_plan_id",
sms_api_token="api_token"
sms_api_token="api_token",
sms_region="us"
)
```

#### All Other Sinch APIs
For all other Sinch APIs, including SMS in US and EU regions, use the following parameters:
#### 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"
key_secret="key_secret",
conversation_region="eu"
)
```

### SMS and Conversation regions (V2)
> **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)

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.
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

Expand Down Expand Up @@ -136,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, inject your own transport during 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",
transport=MyHTTPImplementation
)
```

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.
Expand Down
Loading