Skip to content

Commit fbe65fb

Browse files
authored
Feature/merge main with v2.1 next (#164)
* Unify README structure and content
1 parent 77581ff commit fbe65fb

2 files changed

Lines changed: 177 additions & 88 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ All notable changes to the **Sinch Python SDK** are documented in this file.
2626
- **[deprecation notice]** `HTTPTransport.send(endpoint)` is deprecated in favour of `send_request(request_data)`; the legacy method still works for backward compatibility, but will be removed in 3.0 (#156).
2727
- **[deprecation notice]** `TokenManagerBase.invalidate_expired_token()` and `handle_invalid_token()` (and the `TokenState.EXPIRED` value) are deprecated and will be removed in 3.0, as token renewal now goes through `refresh_auth_token()` (#156).
2828
- **[tech]** Removed unused GitHub environment secrets from CI workflow and simplified test fixtures to use hardcoded test values (#162).
29+
- **[doc]** Improve README structure and content(#155).
2930

3031

3132
### SMS

README.md

Lines changed: 176 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,164 +1,227 @@
11
# Sinch Python SDK
22

3-
[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://github.com/sinch/sinch-sdk-python/blob/main/LICENSE)
4-
5-
6-
[![Python 3.9](https://img.shields.io/badge/python-3.9-blue.svg)](https://www.python.org/downloads/release/python-390/)
7-
[![Python 3.10](https://img.shields.io/badge/python-3.10-blue.svg)](https://www.python.org/downloads/release/python-3100/)
8-
[![Python 3.11](https://img.shields.io/badge/python-3.11-blue.svg)](https://www.python.org/downloads/release/python-3110/)
9-
[![Python 3.12](https://img.shields.io/badge/python-3.12-blue.svg)](https://www.python.org/downloads/release/python-3120/)
10-
[![Python 3.13](https://img.shields.io/badge/python-3.13-blue.svg)](https://www.python.org/downloads/release/python-3130/)
11-
[![Python 3.14](https://img.shields.io/badge/python-3.14-blue.svg)](https://www.python.org/downloads/release/python-3140/)
12-
3+
[![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)
134

145

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

178
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).
189

19-
For more information on the Sinch APIs on which this SDK is based, refer to the official [developer documentation portal](https://developers.sinch.com).
10+
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).
2011

2112

13+
## Table of contents:
14+
2215
- [Prerequisites](#prerequisites)
2316
- [Installation](#installation)
17+
- [Supported APIs](#supported-apis)
2418
- [Getting started](#getting-started)
2519
- [Logging](#logging)
20+
- [Handling Exceptions](#handling-exceptions)
21+
- [Custom HTTP client implementation](#custom-http-client-implementation)
22+
- [Third-party dependencies](#third-party-dependencies)
23+
- [Examples](#examples)
24+
- [Changelog and Migration](#changelog--migration)
25+
- [License](#license)
26+
- [Contact](#contact)
27+
2628

2729
## Prerequisites
2830

29-
- Python in one of the supported versions - 3.9, 3.10, 3.11, 3.12, 3.13, 3.14
30-
- pip
31-
- Sinch account
31+
- [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/)
32+
- [pip](https://pip.pypa.io/en/stable/)
33+
- [Sinch account](https://dashboard.sinch.com/)
34+
35+
> **Warning**:
36+
> 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.
3237
3338
## Installation
3439

35-
You can install this package by typing:
36-
`pip install sinch`
40+
Run the following command to install the SDK:
41+
42+
```bash
43+
pip install sinch
44+
```
45+
46+
47+
## Supported APIs
3748

38-
## Products
3949

40-
The Sinch client provides access to the following Sinch products:
41-
- Numbers API
42-
- SMS API
43-
- Conversation API (beta release)
50+
| API Category | API Name |
51+
|-------------------|-----------------------------|
52+
| Messaging | [Conversation API](https://developers.sinch.com/docs/conversation/) |
53+
| | [SMS API](https://developers.sinch.com/docs/sms/) |
54+
| Numbers | [Numbers API](https://developers.sinch.com/docs/numbers/) |
55+
| Verification | [Number Lookup API](https://developers.sinch.com/docs/number-lookup/) |
56+
57+
> **Note:** The SMS API is end-of-sale. New integrations should use the [Conversation API](https://developers.sinch.com/docs/conversation/) instead, which supports SMS and many other channels.
4458
4559

4660
## Getting started
4761

4862

4963
### Client initialization
5064

51-
To establish a connection with the Sinch backend, you must provide credentials based on the API you intend to use.
52-
For security best practices, avoid hardcoding credentials — retrieve them from environment variables instead.
53-
54-
> **Note:** `sms_region` and `conversation_region` no longer have defaults and **must** be set before
55-
> calling those APIs—omitting them will cause a runtime error. See [MIGRATION_GUIDE.md](MIGRATION_GUIDE.md) for details.
65+
To start using the SDK, initialize the main client class. This client gives you access to all the SDK services:
5666

67+
```python
68+
import os
69+
from sinch import SinchClient
5770

58-
#### SMS API
71+
# Warning: not all APIs support project authentication. Check the section for each API before using this snippet.
5972

60-
The SMS API supports two authentication methods. `sms_region` is required for both and has no default.
73+
sinch_client = SinchClient(
74+
project_id=os.environ["SINCH_PROJECT_ID"],
75+
key_id=os.environ["SINCH_KEY_ID"],
76+
key_secret=os.environ["SINCH_KEY_SECRET"],
77+
)
78+
```
6179

62-
**Project auth (OAuth2)**
80+
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.
6381

64-
The SDK automatically exchanges your key ID and key secret for a short-lived OAuth2 token and refreshes it automatically on expiry.
65-
Supported regions: `us`, `eu`, `br`.
82+
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.
6683

67-
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`.
84+
### Conversation API
6885

69-
> **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.
86+
The Conversation API is regionalized. To use this API, the `conversation_region` parameter is required:
7087

7188
```python
72-
from sinch import SinchClient
73-
7489
sinch_client = SinchClient(
75-
project_id="project_id",
76-
key_id="key_id",
77-
key_secret="key_secret",
78-
sms_region="us"
90+
project_id=os.environ["SINCH_PROJECT_ID"],
91+
key_id=os.environ["SINCH_KEY_ID"],
92+
key_secret=os.environ["SINCH_KEY_SECRET"],
93+
conversation_region="eu",
7994
)
8095
```
8196

82-
**Service Plan ID auth (legacy)**
83-
84-
Uses a static bearer token that never expires.
85-
Support all regions: `us`, `eu`, `br`, `ca`, `au`.
97+
#### Sinch Events
8698

87-
In your [Service APIs dashboard](https://dashboard.sinch.com/sms/api/services), you will find your `servicePlanId` and `apiToken` (bearer token).
99+
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:
88100

89101
```python
90-
from sinch import SinchClient
102+
sinch_events = sinch_client.conversation.sinch_events(SINCH_EVENT_SECRET)
103+
is_valid = sinch_events.validate_authentication_header(headers=headers, json_payload=raw_body)
104+
event = sinch_events.parse_event(raw_body, headers)
105+
```
106+
107+
`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.
108+
109+
You can find a complete example in [examples/sinch_events/conversation_api](./examples/sinch_events/conversation_api).
110+
111+
### SMS API
112+
113+
> **Warning:** the SMS API is end-of-sale. For new integrations, prefer the [Conversation API](#conversation-api).
114+
115+
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:
91116

117+
- **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`:
118+
119+
```python
92120
sinch_client = SinchClient(
93-
service_plan_id="service_plan_id",
94-
sms_api_token="api_token",
95-
sms_region="us"
121+
project_id=os.environ["SINCH_PROJECT_ID"],
122+
key_id=os.environ["SINCH_KEY_ID"],
123+
key_secret=os.environ["SINCH_KEY_SECRET"],
124+
sms_region="us",
96125
)
97126
```
98127

99-
#### Conversation API - Project auth (OAuth2)
128+
> **SMS authentication for new projects**
129+
>
130+
> Projects created after the SMS API end-of-sale (`15/04/26`) cannot use
131+
> project access keys — the SMS API requests return `401 Unauthorized`.
132+
>
133+
> If you encounter this issue, consider the following options:
134+
>
135+
> 1. Use service plan credentials (`service_plan_id` + `sms_api_token`)
136+
> 2. Use the Conversation API, which works with project access keys.
137+
> 3. Contact your account manager
100138
101-
`conversation_region` is required and has no default.
102-
Supported regions: `us`, `eu`, `br`.
103139

104-
> **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.
140+
- **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):
105141

106142
```python
107-
from sinch import SinchClient
108-
109143
sinch_client = SinchClient(
110-
project_id="project_id",
111-
key_id="key_id",
112-
key_secret="key_secret",
113-
conversation_region="eu"
144+
service_plan_id=os.environ["SINCH_SERVICE_PLAN_ID"],
145+
sms_api_token=os.environ["SINCH_SMS_API_TOKEN"],
146+
sms_region="us",
114147
)
115148
```
116149

117-
> **SMS integration note:** If you also use the SMS API, `sms_region` and `conversation_region` **must match**. Mismatched regions will cause delivery failures.
150+
> **Note:** if you use both the SMS and the [Conversation API](#conversation-api)
151+
> from the same client, set `sms_region` and `conversation_region` to the same
152+
> region. Mismatched regions cause delivery failures.
118153
119-
#### Other APIs - Project auth (OAuth2)
154+
#### Sinch Events
120155

121-
These APIs are not regionalized and use project-based auth.
156+
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:
122157

123158
```python
124-
from sinch import SinchClient
159+
sinch_events = sinch_client.sms.sinch_events(SINCH_EVENT_SECRET)
160+
is_valid = sinch_events.validate_authentication_header(headers=headers, json_payload=raw_body)
161+
event = sinch_events.parse_event(raw_body, headers)
162+
```
125163

126-
sinch_client = SinchClient(
127-
project_id="project_id",
128-
key_id="key_id",
129-
key_secret="key_secret",
130-
)
164+
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).
165+
166+
You can find a complete example in [examples/sinch_events/sms_api](./examples/sinch_events/sms_api).
167+
168+
### Numbers API
169+
170+
The Numbers API needs no extra parameters, use the [common client](#client-initialization) based in project authentication shown above.
171+
172+
#### Sinch Events
173+
174+
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:
175+
176+
```python
177+
sinch_events = sinch_client.numbers.sinch_events(SINCH_EVENT_SECRET)
178+
is_valid = sinch_events.validate_authentication_header(headers=headers, json_payload=raw_body)
179+
event = sinch_events.parse_event(raw_body, headers)
131180
```
132181

133-
## Logging
182+
`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.
134183

135-
Logging configuration for this SDK utilizes following hierarchy:
136-
1. If no configuration was provided via `logger_name` or `logger` configurable, SDK will inherit configuration from the root logger with the `Sinch` prefix.
137-
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.
138-
3. If `logger` (logger instance) configurable was provided, SDK will use that particular logger for all its logging operations.
184+
You can find a complete example in [examples/sinch_events/numbers_api](./examples/sinch_events/numbers_api).
139185

140-
If all logging returned by this SDK needs to be disabled, usage of `NullHandler` provided by the standard `logging` module is advised.
186+
### Number Lookup API
187+
188+
The Number Lookup API needs no extra parameters, use the [common client](#client-initialization) based in project authentication shown above.
141189

142190

143-
144-
## Sample apps
145191

146-
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:
192+
### Your First Request
193+
194+
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:
147195

148196
```python
149-
paginator = sinch_client.numbers.list(
150-
region_code="US",
151-
number_type="LOCAL",
197+
response = sinch_client.conversation.messages.send(
198+
app_id="CONVERSATION_APP_ID",
199+
message={
200+
"text_message": {
201+
"text": "[Python SDK: Conversation Message] Sample text message",
202+
},
203+
},
204+
recipient_identities=[
205+
{
206+
"channel": "SMS",
207+
"identity": "RECIPIENT_PHONE_NUMBER",
208+
}
209+
],
152210
)
153-
for active_number in paginator.iterator():
154-
print(active_number)
211+
212+
print(f"Successfully sent message.\n{response}")
155213
```
156214

157-
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`.
215+
## Logging
216+
217+
Logging configuration for this SDK utilizes following hierarchy:
218+
1. If no configuration was provided via `logger_name` or `logger` configurable, SDK will inherit configuration from the root logger with the `Sinch` prefix.
219+
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.
220+
3. If `logger` (logger instance) configurable was provided, SDK will use that particular logger for all its logging operations.
158221

159-
More examples live under [examples/snippets](examples/snippets) on the `main` branch.
222+
If all logging returned by this SDK needs to be disabled, usage of `NullHandler` provided by the standard `logging` module is advised.
160223

161-
### Handling exceptions
224+
## Handling exceptions
162225

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

@@ -178,7 +241,6 @@ except NumbersException as err:
178241

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

181-
182244
## Custom HTTP client implementation
183245

184246
By default, the HTTP implementation uses the `requests` library.
@@ -239,9 +301,35 @@ sinch_client.configuration.transport = MyHTTPImplementation(
239301
)
240302
```
241303

242-
Note: Asynchronous HTTP clients are not supported.
243-
The transport must be a synchronous implementation.
304+
> **Note:** Asynchronous HTTP clients are not supported. The transport must be
305+
> a synchronous implementation.
306+
307+
308+
## Third-party dependencies
309+
The SDK relies on the following third-party dependencies:
310+
- [requests](https://requests.readthedocs.io/): HTTP client used as the default transport for all API calls.
311+
- [pydantic](https://docs.pydantic.dev/): Data validation and serialization for request and response models.
312+
313+
## Examples
314+
315+
You can find:
316+
- a Python example of each request in the [examples/snippets](./examples/snippets) folder.
317+
- getting started guides for specific use cases in the [examples/getting-started](./examples/getting-started) folder.
318+
- server-side event handling examples in the [examples/sinch_events](./examples/sinch_events) folder.
319+
320+
## Changelog & Migration
321+
322+
For information about the latest changes in the SDK, please refer to the [CHANGELOG](CHANGELOG.md) file
323+
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.
244324

245325
## License
246326

247-
This project is licensed under the Apache License. See the [LICENSE](LICENSE) file for the license text.
327+
This project is licensed under the Apache License.
328+
329+
See the [LICENSE](LICENSE) file for the license text.
330+
331+
332+
## Contact
333+
334+
Developer Experience engineering team: [team-developer-experience@sinch.com](mailto:team-developer-experience@sinch.com)
335+

0 commit comments

Comments
 (0)