cdp-python-sdk 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cdp_python_sdk-0.1.0/MANIFEST.in +7 -0
- cdp_python_sdk-0.1.0/PKG-INFO +310 -0
- cdp_python_sdk-0.1.0/README.md +292 -0
- cdp_python_sdk-0.1.0/cdp_client/__init__.py +22 -0
- cdp_python_sdk-0.1.0/cdp_client/client.py +220 -0
- cdp_python_sdk-0.1.0/cdp_client/errors.py +15 -0
- cdp_python_sdk-0.1.0/cdp_client/gateway_urls.py +40 -0
- cdp_python_sdk-0.1.0/cdp_client/models.py +110 -0
- cdp_python_sdk-0.1.0/cdp_client/validators.py +35 -0
- cdp_python_sdk-0.1.0/cdp_python_sdk.egg-info/PKG-INFO +310 -0
- cdp_python_sdk-0.1.0/cdp_python_sdk.egg-info/SOURCES.txt +15 -0
- cdp_python_sdk-0.1.0/cdp_python_sdk.egg-info/dependency_links.txt +1 -0
- cdp_python_sdk-0.1.0/cdp_python_sdk.egg-info/requires.txt +8 -0
- cdp_python_sdk-0.1.0/cdp_python_sdk.egg-info/top_level.txt +1 -0
- cdp_python_sdk-0.1.0/pyproject.toml +36 -0
- cdp_python_sdk-0.1.0/setup.cfg +4 -0
- cdp_python_sdk-0.1.0/setup.py +7 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cdp-python-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A Python client library for Codematic's Customer Data Platform (CDP) with optional Customer.io integration.
|
|
5
|
+
Author-email: Codematic Engineering <engineering@codematic.io>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Requires-Python: >=3.8
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: httpx>=0.24.0
|
|
12
|
+
Requires-Dist: pydantic>=2.0.0
|
|
13
|
+
Requires-Dist: customerio>=1.1.0
|
|
14
|
+
Provides-Extra: test
|
|
15
|
+
Requires-Dist: pytest>=7.0.0; extra == "test"
|
|
16
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "test"
|
|
17
|
+
Requires-Dist: pytest-httpx>=0.21.0; extra == "test"
|
|
18
|
+
|
|
19
|
+
# CDP Python SDK
|
|
20
|
+
|
|
21
|
+
A Python client library for Codematic's Customer Data Platform (CDP) with optional Customer.io integration.
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install cdp-python-sdk
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Or via `requirements.txt`:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
cdp-python-sdk
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Features
|
|
36
|
+
|
|
37
|
+
- **Async Support**: Built on `httpx` and `asyncio` for high-performance non-blocking I/O.
|
|
38
|
+
- **Dual-Write**: Optional integration to send data to both CDP and Customer.io simultaneously.
|
|
39
|
+
- **Type Safety**: Uses Pydantic models for request validation.
|
|
40
|
+
- **Transactional Messaging**: Support for Email, Push, and SMS.
|
|
41
|
+
- **Device Registration**: Register devices for push notification targeting.
|
|
42
|
+
|
|
43
|
+
## Examples
|
|
44
|
+
|
|
45
|
+
A complete runnable example is available in [`example/`](example/):
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
example/
|
|
49
|
+
├── main.py # Full flow: init → identify → track → register_device → email → push → sms
|
|
50
|
+
└── README.md # How to run
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
See [`example/README.md`](example/README.md) for run instructions.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Quick Start
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
import asyncio
|
|
61
|
+
from cdp_client import CDPClient, CDPConfig
|
|
62
|
+
|
|
63
|
+
async def main():
|
|
64
|
+
config = CDPConfig(cdp_api_key="your-cdp-api-key")
|
|
65
|
+
client = CDPClient(config)
|
|
66
|
+
|
|
67
|
+
await client.identify("user-123", {"email": "user@example.com", "name": "Jane"})
|
|
68
|
+
await client.track("user-123", "signed_up", {"plan": "pro"})
|
|
69
|
+
|
|
70
|
+
await client.close()
|
|
71
|
+
|
|
72
|
+
asyncio.run(main())
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Usage
|
|
76
|
+
|
|
77
|
+
### Initialization
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
import asyncio
|
|
81
|
+
from cdp_client import CDPClient, CDPConfig, CustomerIoConfig
|
|
82
|
+
|
|
83
|
+
async def main():
|
|
84
|
+
config = CDPConfig(
|
|
85
|
+
cdp_api_key="your-cdp-api-key",
|
|
86
|
+
debug=True,
|
|
87
|
+
# Optional: enable Customer.io dual-write
|
|
88
|
+
send_to_customer_io=True,
|
|
89
|
+
customer_io=CustomerIoConfig(
|
|
90
|
+
site_id="your-cio-site-id",
|
|
91
|
+
api_key="your-cio-api-key",
|
|
92
|
+
region="us" # "us" or "eu"
|
|
93
|
+
)
|
|
94
|
+
)
|
|
95
|
+
client = CDPClient(config)
|
|
96
|
+
|
|
97
|
+
# ... use client ...
|
|
98
|
+
|
|
99
|
+
await client.close()
|
|
100
|
+
|
|
101
|
+
asyncio.run(main())
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
### Identify a User
|
|
107
|
+
|
|
108
|
+
Associate a user ID with a set of traits (name, email, plan, etc.). Call this on sign-up, login, or whenever user attributes change.
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
await client.identify("user-123", {
|
|
112
|
+
"email": "user@example.com",
|
|
113
|
+
"name": "Jane Doe",
|
|
114
|
+
"plan": "premium"
|
|
115
|
+
})
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
### Track an Event
|
|
121
|
+
|
|
122
|
+
Record a user action or behaviour.
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
await client.track("user-123", "purchase_completed", {
|
|
126
|
+
"amount": 99.99,
|
|
127
|
+
"currency": "USD",
|
|
128
|
+
"item_id": "prod-456"
|
|
129
|
+
})
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
### Register a Device
|
|
135
|
+
|
|
136
|
+
Register a device token for push notification targeting. Call this after you receive a push token from your mobile platform.
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
await client.register_device(
|
|
140
|
+
user_id="user-123",
|
|
141
|
+
device_id="device-abc", # Unique device identifier
|
|
142
|
+
platform="ios", # "ios", "android", or "web"
|
|
143
|
+
token="apns-or-fcm-token",
|
|
144
|
+
attributes={ # Optional device metadata
|
|
145
|
+
"app_version": "2.1.0",
|
|
146
|
+
"os_version": "17.2"
|
|
147
|
+
}
|
|
148
|
+
)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
### Send Transactional Email
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
from cdp_client import EmailPayload, Identifiers
|
|
157
|
+
|
|
158
|
+
await client.send_email(EmailPayload(
|
|
159
|
+
to="user@example.com",
|
|
160
|
+
identifiers=Identifiers(id="user-123"),
|
|
161
|
+
transactional_message_id="WELCOME_EMAIL",
|
|
162
|
+
subject="Welcome!",
|
|
163
|
+
body="<h1>Thanks for joining!</h1>",
|
|
164
|
+
body_plain="Thanks for joining!"
|
|
165
|
+
))
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
### Send Push Notification
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
from cdp_client import PushPayload, Identifiers
|
|
174
|
+
|
|
175
|
+
await client.send_push(PushPayload(
|
|
176
|
+
identifiers=Identifiers(id="user-123"),
|
|
177
|
+
transactional_message_id="PROMO_PUSH",
|
|
178
|
+
title="Flash Sale 🔥",
|
|
179
|
+
body="50% off for the next hour."
|
|
180
|
+
))
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
### Send SMS
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
from cdp_client import SmsPayload, Identifiers
|
|
189
|
+
|
|
190
|
+
await client.send_sms(SmsPayload(
|
|
191
|
+
identifiers=Identifiers(id="user-123"),
|
|
192
|
+
to="+14155551234", # Optional: raw phone number
|
|
193
|
+
transactional_message_id="OTP_MSG",
|
|
194
|
+
body="Your one-time code is 881234."
|
|
195
|
+
))
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
### Clear Identity / Logout
|
|
201
|
+
|
|
202
|
+
To reset the client's user context (e.g., on logout), close the current client and re-initialize without a user session:
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
# On user logout: flush pending work and release the HTTP client
|
|
206
|
+
await client.close()
|
|
207
|
+
|
|
208
|
+
# Re-initialize for anonymous or new user session
|
|
209
|
+
client = CDPClient(config)
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Error Handling
|
|
215
|
+
|
|
216
|
+
By default, the Python SDK raises exceptions on HTTP errors or network failures. Wrap calls in `try/except` to handle them gracefully:
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
import httpx
|
|
220
|
+
|
|
221
|
+
try:
|
|
222
|
+
await client.identify("user-123", {"email": "user@example.com"})
|
|
223
|
+
except httpx.HTTPStatusError as e:
|
|
224
|
+
# Server returned 4xx or 5xx
|
|
225
|
+
print(f"API error {e.response.status_code}: {e.response.text}")
|
|
226
|
+
except Exception as e:
|
|
227
|
+
# Network error, timeout, etc.
|
|
228
|
+
print(f"Unexpected error: {e}")
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
> All methods (`identify`, `track`, `send_email`, `send_push`, `send_sms`, `register_device`) raise on failure. Dual-write Customer.io errors are non-fatal and only emit a warning log.
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Configuration Options
|
|
236
|
+
|
|
237
|
+
| Option | Type | Default | Description |
|
|
238
|
+
|--------|------|---------|-------------|
|
|
239
|
+
| `cdp_api_key` | `str` | **Required** | Your CDP API Key |
|
|
240
|
+
| `cdp_endpoint` | `str` | Production URL | Custom CDP Gateway URL |
|
|
241
|
+
| `debug` | `bool` | `False` | Enable verbose debug logging |
|
|
242
|
+
| `send_to_customer_io` | `bool` | `False` | Enable dual-write to Customer.io |
|
|
243
|
+
| `customer_io` | `CustomerIoConfig` | `None` | Customer.io integration config (see below) |
|
|
244
|
+
|
|
245
|
+
### `CustomerIoConfig` Options
|
|
246
|
+
|
|
247
|
+
| Option | Type | Description |
|
|
248
|
+
|--------|------|-------------|
|
|
249
|
+
| `site_id` | `str` | Customer.io Site ID |
|
|
250
|
+
| `api_key` | `str` | Customer.io API Key |
|
|
251
|
+
| `region` | `str` | `"us"` (default) or `"eu"` |
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Dual-Write to Customer.io
|
|
256
|
+
|
|
257
|
+
When `send_to_customer_io=True`, all `identify`, `track`, and `register_device` calls are mirrored to Customer.io automatically. Customer.io failures are **non-blocking** — the CDP call succeeds even if the Customer.io call fails.
|
|
258
|
+
|
|
259
|
+
```python
|
|
260
|
+
config = CDPConfig(
|
|
261
|
+
cdp_api_key="your-cdp-api-key",
|
|
262
|
+
send_to_customer_io=True,
|
|
263
|
+
customer_io=CustomerIoConfig(
|
|
264
|
+
site_id="cio-site-id",
|
|
265
|
+
api_key="cio-api-key",
|
|
266
|
+
region="eu"
|
|
267
|
+
)
|
|
268
|
+
)
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## Development
|
|
274
|
+
|
|
275
|
+
### Setup
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
python3 -m venv venv
|
|
279
|
+
source venv/bin/activate
|
|
280
|
+
python -m pip install --upgrade pip setuptools wheel build
|
|
281
|
+
python -m pip install -e ".[test]"
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Run Tests
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
pytest -v
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Building the Package
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
python -m build
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
This creates files in the `dist/` directory:
|
|
297
|
+
- `cdp_python_sdk-{version}-py3-none-any.whl`
|
|
298
|
+
- `cdp_python_sdk-{version}.tar.gz`
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## Versioning
|
|
303
|
+
|
|
304
|
+
Follow [Semantic Versioning](https://semver.org/):
|
|
305
|
+
|
|
306
|
+
| Bump | When |
|
|
307
|
+
|------|------|
|
|
308
|
+
| **PATCH** `1.0.0 → 1.0.1` | Bug fixes |
|
|
309
|
+
| **MINOR** `1.0.0 → 1.1.0` | New features, backward compatible |
|
|
310
|
+
| **MAJOR** `1.0.0 → 2.0.0` | Breaking API changes |
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
# CDP Python SDK
|
|
2
|
+
|
|
3
|
+
A Python client library for Codematic's Customer Data Platform (CDP) with optional Customer.io integration.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install cdp-python-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or via `requirements.txt`:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
cdp-python-sdk
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Features
|
|
18
|
+
|
|
19
|
+
- **Async Support**: Built on `httpx` and `asyncio` for high-performance non-blocking I/O.
|
|
20
|
+
- **Dual-Write**: Optional integration to send data to both CDP and Customer.io simultaneously.
|
|
21
|
+
- **Type Safety**: Uses Pydantic models for request validation.
|
|
22
|
+
- **Transactional Messaging**: Support for Email, Push, and SMS.
|
|
23
|
+
- **Device Registration**: Register devices for push notification targeting.
|
|
24
|
+
|
|
25
|
+
## Examples
|
|
26
|
+
|
|
27
|
+
A complete runnable example is available in [`example/`](example/):
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
example/
|
|
31
|
+
├── main.py # Full flow: init → identify → track → register_device → email → push → sms
|
|
32
|
+
└── README.md # How to run
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
See [`example/README.md`](example/README.md) for run instructions.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Quick Start
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
import asyncio
|
|
43
|
+
from cdp_client import CDPClient, CDPConfig
|
|
44
|
+
|
|
45
|
+
async def main():
|
|
46
|
+
config = CDPConfig(cdp_api_key="your-cdp-api-key")
|
|
47
|
+
client = CDPClient(config)
|
|
48
|
+
|
|
49
|
+
await client.identify("user-123", {"email": "user@example.com", "name": "Jane"})
|
|
50
|
+
await client.track("user-123", "signed_up", {"plan": "pro"})
|
|
51
|
+
|
|
52
|
+
await client.close()
|
|
53
|
+
|
|
54
|
+
asyncio.run(main())
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Usage
|
|
58
|
+
|
|
59
|
+
### Initialization
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
import asyncio
|
|
63
|
+
from cdp_client import CDPClient, CDPConfig, CustomerIoConfig
|
|
64
|
+
|
|
65
|
+
async def main():
|
|
66
|
+
config = CDPConfig(
|
|
67
|
+
cdp_api_key="your-cdp-api-key",
|
|
68
|
+
debug=True,
|
|
69
|
+
# Optional: enable Customer.io dual-write
|
|
70
|
+
send_to_customer_io=True,
|
|
71
|
+
customer_io=CustomerIoConfig(
|
|
72
|
+
site_id="your-cio-site-id",
|
|
73
|
+
api_key="your-cio-api-key",
|
|
74
|
+
region="us" # "us" or "eu"
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
client = CDPClient(config)
|
|
78
|
+
|
|
79
|
+
# ... use client ...
|
|
80
|
+
|
|
81
|
+
await client.close()
|
|
82
|
+
|
|
83
|
+
asyncio.run(main())
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
### Identify a User
|
|
89
|
+
|
|
90
|
+
Associate a user ID with a set of traits (name, email, plan, etc.). Call this on sign-up, login, or whenever user attributes change.
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
await client.identify("user-123", {
|
|
94
|
+
"email": "user@example.com",
|
|
95
|
+
"name": "Jane Doe",
|
|
96
|
+
"plan": "premium"
|
|
97
|
+
})
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
### Track an Event
|
|
103
|
+
|
|
104
|
+
Record a user action or behaviour.
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
await client.track("user-123", "purchase_completed", {
|
|
108
|
+
"amount": 99.99,
|
|
109
|
+
"currency": "USD",
|
|
110
|
+
"item_id": "prod-456"
|
|
111
|
+
})
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
### Register a Device
|
|
117
|
+
|
|
118
|
+
Register a device token for push notification targeting. Call this after you receive a push token from your mobile platform.
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
await client.register_device(
|
|
122
|
+
user_id="user-123",
|
|
123
|
+
device_id="device-abc", # Unique device identifier
|
|
124
|
+
platform="ios", # "ios", "android", or "web"
|
|
125
|
+
token="apns-or-fcm-token",
|
|
126
|
+
attributes={ # Optional device metadata
|
|
127
|
+
"app_version": "2.1.0",
|
|
128
|
+
"os_version": "17.2"
|
|
129
|
+
}
|
|
130
|
+
)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
### Send Transactional Email
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
from cdp_client import EmailPayload, Identifiers
|
|
139
|
+
|
|
140
|
+
await client.send_email(EmailPayload(
|
|
141
|
+
to="user@example.com",
|
|
142
|
+
identifiers=Identifiers(id="user-123"),
|
|
143
|
+
transactional_message_id="WELCOME_EMAIL",
|
|
144
|
+
subject="Welcome!",
|
|
145
|
+
body="<h1>Thanks for joining!</h1>",
|
|
146
|
+
body_plain="Thanks for joining!"
|
|
147
|
+
))
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
### Send Push Notification
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
from cdp_client import PushPayload, Identifiers
|
|
156
|
+
|
|
157
|
+
await client.send_push(PushPayload(
|
|
158
|
+
identifiers=Identifiers(id="user-123"),
|
|
159
|
+
transactional_message_id="PROMO_PUSH",
|
|
160
|
+
title="Flash Sale 🔥",
|
|
161
|
+
body="50% off for the next hour."
|
|
162
|
+
))
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
### Send SMS
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
from cdp_client import SmsPayload, Identifiers
|
|
171
|
+
|
|
172
|
+
await client.send_sms(SmsPayload(
|
|
173
|
+
identifiers=Identifiers(id="user-123"),
|
|
174
|
+
to="+14155551234", # Optional: raw phone number
|
|
175
|
+
transactional_message_id="OTP_MSG",
|
|
176
|
+
body="Your one-time code is 881234."
|
|
177
|
+
))
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
### Clear Identity / Logout
|
|
183
|
+
|
|
184
|
+
To reset the client's user context (e.g., on logout), close the current client and re-initialize without a user session:
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
# On user logout: flush pending work and release the HTTP client
|
|
188
|
+
await client.close()
|
|
189
|
+
|
|
190
|
+
# Re-initialize for anonymous or new user session
|
|
191
|
+
client = CDPClient(config)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Error Handling
|
|
197
|
+
|
|
198
|
+
By default, the Python SDK raises exceptions on HTTP errors or network failures. Wrap calls in `try/except` to handle them gracefully:
|
|
199
|
+
|
|
200
|
+
```python
|
|
201
|
+
import httpx
|
|
202
|
+
|
|
203
|
+
try:
|
|
204
|
+
await client.identify("user-123", {"email": "user@example.com"})
|
|
205
|
+
except httpx.HTTPStatusError as e:
|
|
206
|
+
# Server returned 4xx or 5xx
|
|
207
|
+
print(f"API error {e.response.status_code}: {e.response.text}")
|
|
208
|
+
except Exception as e:
|
|
209
|
+
# Network error, timeout, etc.
|
|
210
|
+
print(f"Unexpected error: {e}")
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
> All methods (`identify`, `track`, `send_email`, `send_push`, `send_sms`, `register_device`) raise on failure. Dual-write Customer.io errors are non-fatal and only emit a warning log.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Configuration Options
|
|
218
|
+
|
|
219
|
+
| Option | Type | Default | Description |
|
|
220
|
+
|--------|------|---------|-------------|
|
|
221
|
+
| `cdp_api_key` | `str` | **Required** | Your CDP API Key |
|
|
222
|
+
| `cdp_endpoint` | `str` | Production URL | Custom CDP Gateway URL |
|
|
223
|
+
| `debug` | `bool` | `False` | Enable verbose debug logging |
|
|
224
|
+
| `send_to_customer_io` | `bool` | `False` | Enable dual-write to Customer.io |
|
|
225
|
+
| `customer_io` | `CustomerIoConfig` | `None` | Customer.io integration config (see below) |
|
|
226
|
+
|
|
227
|
+
### `CustomerIoConfig` Options
|
|
228
|
+
|
|
229
|
+
| Option | Type | Description |
|
|
230
|
+
|--------|------|-------------|
|
|
231
|
+
| `site_id` | `str` | Customer.io Site ID |
|
|
232
|
+
| `api_key` | `str` | Customer.io API Key |
|
|
233
|
+
| `region` | `str` | `"us"` (default) or `"eu"` |
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Dual-Write to Customer.io
|
|
238
|
+
|
|
239
|
+
When `send_to_customer_io=True`, all `identify`, `track`, and `register_device` calls are mirrored to Customer.io automatically. Customer.io failures are **non-blocking** — the CDP call succeeds even if the Customer.io call fails.
|
|
240
|
+
|
|
241
|
+
```python
|
|
242
|
+
config = CDPConfig(
|
|
243
|
+
cdp_api_key="your-cdp-api-key",
|
|
244
|
+
send_to_customer_io=True,
|
|
245
|
+
customer_io=CustomerIoConfig(
|
|
246
|
+
site_id="cio-site-id",
|
|
247
|
+
api_key="cio-api-key",
|
|
248
|
+
region="eu"
|
|
249
|
+
)
|
|
250
|
+
)
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Development
|
|
256
|
+
|
|
257
|
+
### Setup
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
python3 -m venv venv
|
|
261
|
+
source venv/bin/activate
|
|
262
|
+
python -m pip install --upgrade pip setuptools wheel build
|
|
263
|
+
python -m pip install -e ".[test]"
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Run Tests
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
pytest -v
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Building the Package
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
python -m build
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
This creates files in the `dist/` directory:
|
|
279
|
+
- `cdp_python_sdk-{version}-py3-none-any.whl`
|
|
280
|
+
- `cdp_python_sdk-{version}.tar.gz`
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## Versioning
|
|
285
|
+
|
|
286
|
+
Follow [Semantic Versioning](https://semver.org/):
|
|
287
|
+
|
|
288
|
+
| Bump | When |
|
|
289
|
+
|------|------|
|
|
290
|
+
| **PATCH** `1.0.0 → 1.0.1` | Bug fixes |
|
|
291
|
+
| **MINOR** `1.0.0 → 1.1.0` | New features, backward compatible |
|
|
292
|
+
| **MAJOR** `1.0.0 → 2.0.0` | Breaking API changes |
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from .client import CDPClient
|
|
2
|
+
from .errors import CDPError, CDPValidationError
|
|
3
|
+
from .models import (
|
|
4
|
+
CDPConfig,
|
|
5
|
+
CustomerIoConfig,
|
|
6
|
+
DeviceRegistrationParameters,
|
|
7
|
+
EmailPayload,
|
|
8
|
+
PushPayload,
|
|
9
|
+
SmsPayload,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"CDPClient",
|
|
14
|
+
"CDPConfig",
|
|
15
|
+
"CDPError",
|
|
16
|
+
"CDPValidationError",
|
|
17
|
+
"CustomerIoConfig",
|
|
18
|
+
"DeviceRegistrationParameters",
|
|
19
|
+
"EmailPayload",
|
|
20
|
+
"PushPayload",
|
|
21
|
+
"SmsPayload",
|
|
22
|
+
]
|