drip-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.
- drip_sdk-0.1.0/.gitignore +30 -0
- drip_sdk-0.1.0/LICENSE +21 -0
- drip_sdk-0.1.0/PKG-INFO +420 -0
- drip_sdk-0.1.0/README.md +373 -0
- drip_sdk-0.1.0/pyproject.toml +139 -0
- drip_sdk-0.1.0/src/drip/__init__.py +350 -0
- drip_sdk-0.1.0/src/drip/_version.py +3 -0
- drip_sdk-0.1.0/src/drip/client.py +4291 -0
- drip_sdk-0.1.0/src/drip/core.py +1871 -0
- drip_sdk-0.1.0/src/drip/errors.py +230 -0
- drip_sdk-0.1.0/src/drip/integrations/__init__.py +20 -0
- drip_sdk-0.1.0/src/drip/integrations/langchain.py +1437 -0
- drip_sdk-0.1.0/src/drip/middleware/__init__.py +58 -0
- drip_sdk-0.1.0/src/drip/middleware/core.py +754 -0
- drip_sdk-0.1.0/src/drip/middleware/fastapi.py +415 -0
- drip_sdk-0.1.0/src/drip/middleware/flask.py +381 -0
- drip_sdk-0.1.0/src/drip/middleware/types.py +178 -0
- drip_sdk-0.1.0/src/drip/models.py +1104 -0
- drip_sdk-0.1.0/src/drip/resilience.py +837 -0
- drip_sdk-0.1.0/src/drip/stream.py +327 -0
- drip_sdk-0.1.0/src/drip/utils.py +304 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*$py.class
|
|
4
|
+
*.so
|
|
5
|
+
.Python
|
|
6
|
+
build/
|
|
7
|
+
develop-eggs/
|
|
8
|
+
dist/
|
|
9
|
+
downloads/
|
|
10
|
+
eggs/
|
|
11
|
+
.eggs/
|
|
12
|
+
lib/
|
|
13
|
+
lib64/
|
|
14
|
+
parts/
|
|
15
|
+
sdist/
|
|
16
|
+
var/
|
|
17
|
+
wheels/
|
|
18
|
+
*.egg-info/
|
|
19
|
+
.installed.cfg
|
|
20
|
+
*.egg
|
|
21
|
+
.env
|
|
22
|
+
.venv
|
|
23
|
+
env/
|
|
24
|
+
venv/
|
|
25
|
+
.pytest_cache/
|
|
26
|
+
.mypy_cache/
|
|
27
|
+
.ruff_cache/
|
|
28
|
+
.coverage
|
|
29
|
+
htmlcov/
|
|
30
|
+
.DS_Store
|
drip_sdk-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Drip Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
drip_sdk-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: drip-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official Python SDK for Drip - usage-based billing infrastructure with on-chain settlement
|
|
5
|
+
Project-URL: Homepage, https://drippay.dev
|
|
6
|
+
Project-URL: Documentation, https://docs.drippay.dev
|
|
7
|
+
Project-URL: Repository, https://github.com/drip/sdk-python
|
|
8
|
+
Author-email: Drip <sdk@drippay.dev>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: api,billing,blockchain,drip,metered-billing,payments,sdk,usage-based
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Requires-Dist: httpx>=0.25.0
|
|
23
|
+
Requires-Dist: pydantic>=2.0.0
|
|
24
|
+
Provides-Extra: all
|
|
25
|
+
Requires-Dist: fastapi>=0.100.0; extra == 'all'
|
|
26
|
+
Requires-Dist: flask>=2.0.0; extra == 'all'
|
|
27
|
+
Requires-Dist: langchain-core>=0.1.0; extra == 'all'
|
|
28
|
+
Requires-Dist: python-dotenv>=1.0.0; extra == 'all'
|
|
29
|
+
Requires-Dist: starlette>=0.27.0; extra == 'all'
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: mypy>=1.0.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
|
|
34
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
35
|
+
Requires-Dist: respx>=0.20.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
37
|
+
Provides-Extra: dotenv
|
|
38
|
+
Requires-Dist: python-dotenv>=1.0.0; extra == 'dotenv'
|
|
39
|
+
Provides-Extra: fastapi
|
|
40
|
+
Requires-Dist: fastapi>=0.100.0; extra == 'fastapi'
|
|
41
|
+
Requires-Dist: starlette>=0.27.0; extra == 'fastapi'
|
|
42
|
+
Provides-Extra: flask
|
|
43
|
+
Requires-Dist: flask>=2.0.0; extra == 'flask'
|
|
44
|
+
Provides-Extra: langchain
|
|
45
|
+
Requires-Dist: langchain-core>=0.1.0; extra == 'langchain'
|
|
46
|
+
Description-Content-Type: text/markdown
|
|
47
|
+
|
|
48
|
+
# Drip SDK (Python)
|
|
49
|
+
|
|
50
|
+
Drip is a Python SDK for **usage-based tracking and execution logging** in systems where spend is tied to computation — AI agents, APIs, batch jobs, and infra workloads.
|
|
51
|
+
|
|
52
|
+
This **Core SDK** is optimized for pilots: capture usage and run data first, add billing later.
|
|
53
|
+
|
|
54
|
+
**One line to start tracking:** `drip.track_usage(customer_id, meter, quantity)`
|
|
55
|
+
|
|
56
|
+
[](https://pypi.org/project/drip-sdk/)
|
|
57
|
+
[](https://pypi.org/project/drip-sdk/)
|
|
58
|
+
[](https://opensource.org/licenses/MIT)
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## 60-Second Quickstart (Core SDK)
|
|
63
|
+
|
|
64
|
+
### 1. Install
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pip install drip-sdk
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 2. Set your API key
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# Secret key — full access (server-side only)
|
|
74
|
+
export DRIP_API_KEY=sk_test_...
|
|
75
|
+
|
|
76
|
+
# Or public key — usage, customers, billing (safe for client-side)
|
|
77
|
+
export DRIP_API_KEY=pk_test_...
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Or use a `.env` file (recommended):
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
pip install drip-sdk[dotenv] # or: pip install python-dotenv
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```env
|
|
87
|
+
# .env
|
|
88
|
+
DRIP_API_KEY=sk_test_...
|
|
89
|
+
DRIP_API_URL=https://api.drippay.dev # optional, defaults to this
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The SDK auto-loads `.env` files when `python-dotenv` is installed — no extra code needed.
|
|
93
|
+
|
|
94
|
+
### 3. Create a customer and track usage
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
from drip import drip
|
|
98
|
+
|
|
99
|
+
# Create a customer first
|
|
100
|
+
customer = drip.create_customer(external_customer_id="user_123")
|
|
101
|
+
|
|
102
|
+
# Track usage — that's it
|
|
103
|
+
drip.track_usage(customer_id=customer.id, meter="api_calls", quantity=1)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The `drip` singleton reads `DRIP_API_KEY` from your environment automatically.
|
|
107
|
+
|
|
108
|
+
### Alternative: Explicit Configuration
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
from drip import Drip
|
|
112
|
+
|
|
113
|
+
# Auto-reads DRIP_API_KEY from environment
|
|
114
|
+
client = Drip()
|
|
115
|
+
|
|
116
|
+
# Or pass config explicitly with a secret key (full access)
|
|
117
|
+
client = Drip(api_key="sk_test_...")
|
|
118
|
+
|
|
119
|
+
# Or with a public key (limited scope, safe for client-side)
|
|
120
|
+
client = Drip(api_key="pk_test_...")
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Full Example
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
from drip import drip
|
|
127
|
+
|
|
128
|
+
# Verify connectivity
|
|
129
|
+
drip.ping()
|
|
130
|
+
|
|
131
|
+
# Create a customer (at least one of external_customer_id or onchain_address required)
|
|
132
|
+
customer = drip.create_customer(external_customer_id="user_123")
|
|
133
|
+
|
|
134
|
+
# Record usage
|
|
135
|
+
drip.track_usage(
|
|
136
|
+
customer_id=customer.id,
|
|
137
|
+
meter="llm_tokens",
|
|
138
|
+
quantity=842,
|
|
139
|
+
metadata={"model": "gpt-4o-mini"}
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# Record execution lifecycle
|
|
143
|
+
drip.record_run(
|
|
144
|
+
customer_id=customer.id,
|
|
145
|
+
workflow="research-agent",
|
|
146
|
+
events=[
|
|
147
|
+
{"event_type": "llm.call", "quantity": 1700, "units": "tokens"},
|
|
148
|
+
{"event_type": "tool.call", "quantity": 1},
|
|
149
|
+
],
|
|
150
|
+
status="COMPLETED"
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
print(f"Customer {customer.id}: usage + run recorded")
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Expected result:**
|
|
157
|
+
- No exceptions
|
|
158
|
+
- Events appear in the Drip dashboard within seconds
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Core Concepts
|
|
163
|
+
|
|
164
|
+
| Concept | Description |
|
|
165
|
+
|---------|-------------|
|
|
166
|
+
| `customer_id` | The entity you're attributing usage to |
|
|
167
|
+
| `meter` | What's being measured (tokens, calls, time, etc.) |
|
|
168
|
+
| `quantity` | Numeric usage value |
|
|
169
|
+
| `run` | A single request or job execution |
|
|
170
|
+
| `correlation_id` | Optional. Your trace/request ID for linking Drip data with your APM (OpenTelemetry, Datadog, etc.) |
|
|
171
|
+
|
|
172
|
+
**Status values:** `PENDING` | `RUNNING` | `COMPLETED` | `FAILED`
|
|
173
|
+
|
|
174
|
+
**Event schema:** Payloads are schema-flexible. Drip stores events as structured JSON and does not enforce a fixed event taxonomy. CamelCase is accepted.
|
|
175
|
+
|
|
176
|
+
> **Distributed tracing:** Pass `correlation_id` to `start_run()`, `record_run()`, or `emit_event()` to cross-reference Drip billing with your observability stack. See [FULL_SDK.md](./FULL_SDK.md#distributed-tracing-correlation_id) for details.
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Idempotency Keys
|
|
181
|
+
|
|
182
|
+
Every mutating SDK method (`charge`, `track_usage`, `emit_event`) requires an `idempotency_key`. The server uses this key to deduplicate requests — if two requests share the same key, only the first is processed. The parameter is optional in the method signature because **the SDK always generates one for you if you don't provide it**.
|
|
183
|
+
|
|
184
|
+
`record_run` generates idempotency keys internally for its batch events (using `external_run_id` when provided, otherwise deterministic keys).
|
|
185
|
+
|
|
186
|
+
### Auto-generated keys (default)
|
|
187
|
+
|
|
188
|
+
When you omit `idempotency_key`, the SDK generates one automatically — this works for both `drip.core.Drip` and the full `Drip` client. The auto key is:
|
|
189
|
+
|
|
190
|
+
- **Unique per call** — two separate calls with identical parameters produce different keys (a monotonic counter ensures this).
|
|
191
|
+
- **Stable across retries** — the key is generated once and reused for all retry attempts of that call, so network retries are safely deduplicated.
|
|
192
|
+
- **Deterministic** — no randomness; keys are reproducible for debugging.
|
|
193
|
+
|
|
194
|
+
This means you get **free retry safety** with zero configuration.
|
|
195
|
+
|
|
196
|
+
### When to pass explicit keys
|
|
197
|
+
|
|
198
|
+
Pass your own `idempotency_key` when you need **application-level deduplication** — e.g., to guarantee that a specific business operation is billed exactly once, even across process restarts:
|
|
199
|
+
|
|
200
|
+
```python
|
|
201
|
+
customer = drip.create_customer(external_customer_id="user_123")
|
|
202
|
+
|
|
203
|
+
drip.charge(
|
|
204
|
+
customer_id=customer.id,
|
|
205
|
+
meter="api_calls",
|
|
206
|
+
quantity=1,
|
|
207
|
+
idempotency_key=f"order_{order_id}_charge", # your business-level key
|
|
208
|
+
)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Common patterns:
|
|
212
|
+
- `order_{order_id}` — one charge per order
|
|
213
|
+
- `run_{run_id}_step_{step_index}` — one charge per pipeline step
|
|
214
|
+
- `invoice_{invoice_id}` — one charge per invoice
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Installation Options
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
pip install drip-sdk # core only
|
|
222
|
+
pip install drip-sdk[fastapi] # FastAPI helpers
|
|
223
|
+
pip install drip-sdk[flask] # Flask helpers
|
|
224
|
+
pip install drip-sdk[all] # everything
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## SDK Variants
|
|
230
|
+
|
|
231
|
+
| Variant | Description |
|
|
232
|
+
|---------|-------------|
|
|
233
|
+
| **Core SDK** (recommended for pilots) | Usage tracking + execution logging only |
|
|
234
|
+
| **Full SDK** | Includes billing, balances, and workflows (for later stages) |
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## Core SDK Methods
|
|
239
|
+
|
|
240
|
+
All methods are on the `Drip` / `AsyncDrip` class. Start with these for pilots:
|
|
241
|
+
|
|
242
|
+
| Method | Description |
|
|
243
|
+
|--------|-------------|
|
|
244
|
+
| `ping()` | Verify API connection |
|
|
245
|
+
| `create_customer(...)` | Create a customer (see below) |
|
|
246
|
+
| `get_or_create_customer(external_customer_id)` | Idempotently create or retrieve a customer by external ID |
|
|
247
|
+
| `get_customer(customer_id)` | Get customer details |
|
|
248
|
+
| `list_customers(options)` | List all customers |
|
|
249
|
+
| `track_usage(params)` | Record metered usage |
|
|
250
|
+
| `charge(customer_id, meter, quantity, ...)` | Create a billable charge (sync — waits for settlement) |
|
|
251
|
+
| `charge_async(customer_id, meter, quantity, ...)` | Async charge — returns immediately, processes in background |
|
|
252
|
+
| `list_charges(options)` | List charges for your business |
|
|
253
|
+
| `get_charge(charge_id)` | Get a single charge by ID |
|
|
254
|
+
| `list_events(options)` | List execution events with filters |
|
|
255
|
+
| `get_event(event_id)` | Get a single event by ID |
|
|
256
|
+
| `get_event_trace(event_id)` | Get event causality trace (ancestors, children, retries) |
|
|
257
|
+
| `record_run(params)` | Log complete agent run (simplified) |
|
|
258
|
+
| `start_run(params)` | Start execution trace |
|
|
259
|
+
| `emit_event(params)` | Log event within run |
|
|
260
|
+
| `emit_events_batch(params)` | Batch log events |
|
|
261
|
+
| `end_run(run_id, params)` | Complete execution trace |
|
|
262
|
+
| `get_run(run_id)` | Get run details and summary |
|
|
263
|
+
| `get_run_timeline(run_id)` | Get execution timeline |
|
|
264
|
+
| `get_balance(customer_id)` | Get customer balance |
|
|
265
|
+
| `check_entitlement(customer_id, feature_key, quantity?)` | Pre-request authorization check |
|
|
266
|
+
| `run(workflow, customer_id)` | Context manager for run tracking (see below) |
|
|
267
|
+
|
|
268
|
+
### Run Context Manager
|
|
269
|
+
|
|
270
|
+
```python
|
|
271
|
+
with drip.run("research-agent", customer_id=customer.id) as run:
|
|
272
|
+
run.event("llm.call", quantity=1700, units="tokens")
|
|
273
|
+
run.event("tool.call", quantity=1)
|
|
274
|
+
# Run auto-completes on exit, or marks FAILED on exception
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Creating Customers
|
|
278
|
+
|
|
279
|
+
All parameters are optional, but at least one of `external_customer_id` or `onchain_address` must be provided:
|
|
280
|
+
|
|
281
|
+
```python
|
|
282
|
+
# Simplest — just your internal user ID
|
|
283
|
+
customer = drip.create_customer(external_customer_id="user_123")
|
|
284
|
+
|
|
285
|
+
# With an on-chain address (for on-chain billing)
|
|
286
|
+
customer = drip.create_customer(
|
|
287
|
+
onchain_address="0x1234...",
|
|
288
|
+
external_customer_id="user_123"
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
# Internal/non-billing customer (for tracking only)
|
|
292
|
+
customer = drip.create_customer(
|
|
293
|
+
external_customer_id="internal-team",
|
|
294
|
+
is_internal=True
|
|
295
|
+
)
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
| Parameter | Type | Required | Description |
|
|
299
|
+
|-----------|------|----------|-------------|
|
|
300
|
+
| `external_customer_id` | `str` | No* | Your internal user/account ID |
|
|
301
|
+
| `onchain_address` | `str` | No* | Customer's Ethereum address |
|
|
302
|
+
| `is_internal` | `bool` | No | Mark as internal (non-billing). Default: `False` |
|
|
303
|
+
| `metadata` | `dict` | No | Arbitrary key-value metadata |
|
|
304
|
+
|
|
305
|
+
\*At least one of `external_customer_id` or `onchain_address` is required.
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
## Async Core SDK
|
|
310
|
+
|
|
311
|
+
```python
|
|
312
|
+
from drip import AsyncDrip
|
|
313
|
+
|
|
314
|
+
async with AsyncDrip(api_key="sk_test_...") as client:
|
|
315
|
+
await client.ping()
|
|
316
|
+
|
|
317
|
+
# Create a customer
|
|
318
|
+
customer = await client.create_customer(external_customer_id="user_123")
|
|
319
|
+
|
|
320
|
+
await client.track_usage(
|
|
321
|
+
customer_id=customer.id,
|
|
322
|
+
meter="api_calls",
|
|
323
|
+
quantity=1
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
result = await client.record_run(
|
|
327
|
+
customer_id=customer.id,
|
|
328
|
+
workflow="research-agent",
|
|
329
|
+
events=[...],
|
|
330
|
+
status="COMPLETED"
|
|
331
|
+
)
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## Who This Is For
|
|
337
|
+
|
|
338
|
+
- AI agents (token metering, tool calls, execution traces)
|
|
339
|
+
- API companies (per-request billing, endpoint attribution)
|
|
340
|
+
- RPC providers (multi-chain call tracking)
|
|
341
|
+
- Cloud/infra (compute seconds, storage, bandwidth)
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
## Full SDK (Billing, Entitlements, Webhooks, Subscriptions, Invoices)
|
|
346
|
+
|
|
347
|
+
For billing, entitlements, subscriptions, invoices, contracts, webhooks, middleware, and advanced features:
|
|
348
|
+
|
|
349
|
+
```python
|
|
350
|
+
from drip import Drip
|
|
351
|
+
|
|
352
|
+
client = Drip(api_key="sk_test_...")
|
|
353
|
+
|
|
354
|
+
# Check if a customer can use a feature before processing
|
|
355
|
+
check = client.check_entitlement(customer.id, "search")
|
|
356
|
+
|
|
357
|
+
if not check.allowed:
|
|
358
|
+
# Over quota — return 429 without wasting compute
|
|
359
|
+
pass
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
Key methods:
|
|
363
|
+
|
|
364
|
+
| Method | Description |
|
|
365
|
+
|--------|-------------|
|
|
366
|
+
| `get_balance(customer_id)` | Get customer balance (USDC, pending, available) |
|
|
367
|
+
| `check_entitlement(customer_id, feature_key, quantity?)` | Pre-request authorization check (allowed/denied + remaining quota) |
|
|
368
|
+
| `set_customer_spending_cap(customer_id, cap_type, limit_value)` | Set daily/monthly/single-charge spending cap |
|
|
369
|
+
| `get_customer_spending_caps(customer_id)` | List active spending caps |
|
|
370
|
+
| `remove_customer_spending_cap(customer_id, cap_id)` | Remove a spending cap |
|
|
371
|
+
| `checkout(params)` | Create hosted checkout session for top-ups |
|
|
372
|
+
|
|
373
|
+
Highlights:
|
|
374
|
+
- **Billing** — `charge()`, `list_charges()`, `get_charge()`, `get_balance()`
|
|
375
|
+
- **Cost Estimation** — `estimate_from_usage()`, `estimate_from_hypothetical()` for budget planning
|
|
376
|
+
- **Spending Caps** — per-customer daily/monthly limits with multi-level alerts at 50%, 80%, 95%, 100%
|
|
377
|
+
- **Entitlements** — pre-request quota gating with `check_entitlement()`
|
|
378
|
+
- **Subscription billing** — create, update, pause, resume, cancel
|
|
379
|
+
- **Invoices** — available via REST API (SDK methods planned)
|
|
380
|
+
- **Contracts** — available via REST API (SDK methods planned)
|
|
381
|
+
- **Webhooks** — create, verify, manage webhook endpoints
|
|
382
|
+
- **Middleware** — FastAPI and Flask integrations
|
|
383
|
+
|
|
384
|
+
See **[FULL_SDK.md](./FULL_SDK.md)** for complete documentation.
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
## Error Handling
|
|
389
|
+
|
|
390
|
+
```python
|
|
391
|
+
from drip import Drip, DripError, DripAPIError
|
|
392
|
+
|
|
393
|
+
client = Drip(api_key="sk_test_...")
|
|
394
|
+
customer = client.create_customer(external_customer_id="user_123")
|
|
395
|
+
|
|
396
|
+
try:
|
|
397
|
+
result = client.track_usage(customer_id=customer.id, meter="api_calls", quantity=1)
|
|
398
|
+
except DripAPIError as e:
|
|
399
|
+
print(f"API error {e.status_code}: {e.message}")
|
|
400
|
+
except DripError as e:
|
|
401
|
+
print(f"Error: {e}")
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
## Requirements
|
|
407
|
+
|
|
408
|
+
- Python 3.10+
|
|
409
|
+
- httpx
|
|
410
|
+
- pydantic
|
|
411
|
+
|
|
412
|
+
## Links
|
|
413
|
+
|
|
414
|
+
- [Full SDK Documentation](./FULL_SDK.md)
|
|
415
|
+
- [API Documentation](https://docs.drippay.dev/api-reference)
|
|
416
|
+
- [PyPI](https://pypi.org/project/drip-sdk/)
|
|
417
|
+
|
|
418
|
+
## License
|
|
419
|
+
|
|
420
|
+
MIT
|