growflowbilling-client 1.2.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.
- growflowbilling_client-1.2.0/.gitignore +66 -0
- growflowbilling_client-1.2.0/LICENSE +21 -0
- growflowbilling_client-1.2.0/PKG-INFO +247 -0
- growflowbilling_client-1.2.0/PUBLISHING.md +73 -0
- growflowbilling_client-1.2.0/README.md +216 -0
- growflowbilling_client-1.2.0/pyproject.toml +62 -0
- growflowbilling_client-1.2.0/src/growflow_billing/__init__.py +83 -0
- growflowbilling_client-1.2.0/src/growflow_billing/client.py +261 -0
- growflowbilling_client-1.2.0/src/growflow_billing/config.py +36 -0
- growflowbilling_client-1.2.0/src/growflow_billing/endpoints/__init__.py +17 -0
- growflowbilling_client-1.2.0/src/growflow_billing/endpoints/admin_products.py +221 -0
- growflowbilling_client-1.2.0/src/growflow_billing/endpoints/checkout.py +114 -0
- growflowbilling_client-1.2.0/src/growflow_billing/endpoints/invoices.py +125 -0
- growflowbilling_client-1.2.0/src/growflow_billing/endpoints/plans.py +48 -0
- growflowbilling_client-1.2.0/src/growflow_billing/endpoints/products.py +138 -0
- growflowbilling_client-1.2.0/src/growflow_billing/endpoints/subscribers.py +130 -0
- growflowbilling_client-1.2.0/src/growflow_billing/endpoints/subscriptions.py +187 -0
- growflowbilling_client-1.2.0/src/growflow_billing/exceptions.py +59 -0
- growflowbilling_client-1.2.0/src/growflow_billing/models/__init__.py +24 -0
- growflowbilling_client-1.2.0/src/growflow_billing/models/admin_product.py +66 -0
- growflowbilling_client-1.2.0/src/growflow_billing/models/checkout.py +52 -0
- growflowbilling_client-1.2.0/src/growflow_billing/models/invoice.py +80 -0
- growflowbilling_client-1.2.0/src/growflow_billing/models/plan.py +83 -0
- growflowbilling_client-1.2.0/src/growflow_billing/models/product.py +73 -0
- growflowbilling_client-1.2.0/src/growflow_billing/models/subscriber.py +50 -0
- growflowbilling_client-1.2.0/src/growflow_billing/models/subscription.py +84 -0
- growflowbilling_client-1.2.0/src/growflow_billing/utils/__init__.py +10 -0
- growflowbilling_client-1.2.0/src/growflow_billing/utils/helpers.py +110 -0
- growflowbilling_client-1.2.0/src/growflow_billing/utils/retry.py +80 -0
- growflowbilling_client-1.2.0/src/growflow_billing/webhooks.py +337 -0
- growflowbilling_client-1.2.0/tests/__init__.py +1 -0
- growflowbilling_client-1.2.0/tests/conftest.py +32 -0
- growflowbilling_client-1.2.0/tests/test_client.py +1225 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
.installed.cfg
|
|
21
|
+
*.egg
|
|
22
|
+
|
|
23
|
+
# Virtual Environment
|
|
24
|
+
venv/
|
|
25
|
+
ENV/
|
|
26
|
+
env/
|
|
27
|
+
.venv
|
|
28
|
+
|
|
29
|
+
# Environment
|
|
30
|
+
.env
|
|
31
|
+
.env.local
|
|
32
|
+
.env.*.local
|
|
33
|
+
|
|
34
|
+
# IDEs
|
|
35
|
+
.vscode/
|
|
36
|
+
.idea/
|
|
37
|
+
*.swp
|
|
38
|
+
*.swo
|
|
39
|
+
*~
|
|
40
|
+
.DS_Store
|
|
41
|
+
|
|
42
|
+
# Testing
|
|
43
|
+
.pytest_cache/
|
|
44
|
+
.coverage
|
|
45
|
+
htmlcov/
|
|
46
|
+
*.cover
|
|
47
|
+
|
|
48
|
+
# Database
|
|
49
|
+
*.db
|
|
50
|
+
|
|
51
|
+
# Logs
|
|
52
|
+
*.log
|
|
53
|
+
|
|
54
|
+
# Alembic
|
|
55
|
+
# Uncommit migrations/versions/ in production
|
|
56
|
+
|
|
57
|
+
# Node (for admin dashboard)
|
|
58
|
+
node_modules/
|
|
59
|
+
.pnpm-store/
|
|
60
|
+
dist/
|
|
61
|
+
build/
|
|
62
|
+
|
|
63
|
+
# Exception: keep admin-dashboard src/lib
|
|
64
|
+
!platform/admin-dashboard/src/lib/
|
|
65
|
+
|
|
66
|
+
full-version/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 GrowFlow
|
|
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.
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: growflowbilling-client
|
|
3
|
+
Version: 1.2.0
|
|
4
|
+
Summary: Python client for GrowFlow Billing API - subscription management, checkout, invoices
|
|
5
|
+
Project-URL: Homepage, https://github.com/giuliogarofalo/growflow-billing
|
|
6
|
+
Project-URL: Documentation, https://docs.growflow.studio/billing-client
|
|
7
|
+
Project-URL: Repository, https://github.com/giuliogarofalo/growflow-billing
|
|
8
|
+
Author-email: GrowFlow <dev@growflow.studio>
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: billing,payments,saas,stripe,subscriptions
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Requires-Dist: httpx>=0.25.0
|
|
23
|
+
Requires-Dist: pydantic[email]>=2.0.0
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: mypy>=1.0.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: respx>=0.20.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# GrowFlow Billing Client
|
|
33
|
+
|
|
34
|
+
Python client for [GrowFlow Billing API](https://billing.growflow.studio) - subscription management, checkout sessions, invoices, and more.
|
|
35
|
+
|
|
36
|
+
> **Documentation**: See [growflow-billing-docs](https://github.com/growflow/growflow-billing-docs) for complete API documentation and examples.
|
|
37
|
+
>
|
|
38
|
+
> **Node.js**: Looking for the Node.js/TypeScript client? See [@growflow/billing-client](https://github.com/growflow/growflow-billing-client-node).
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install growflow-billing-client
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Or install from source:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pip install git+https://github.com/growflow/growflow-billing-client.git
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Quick Start
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
import asyncio
|
|
56
|
+
from growflow_billing import GrowFlowBillingClient
|
|
57
|
+
|
|
58
|
+
async def main():
|
|
59
|
+
async with GrowFlowBillingClient(api_key="sk_live_xxx") as client:
|
|
60
|
+
# Get available plans
|
|
61
|
+
plans = await client.get_plans()
|
|
62
|
+
for plan in plans:
|
|
63
|
+
print(f"{plan.name}: {plan.price_monthly} {plan.currency}/month")
|
|
64
|
+
|
|
65
|
+
# Create a checkout session
|
|
66
|
+
session = await client.create_checkout_session(
|
|
67
|
+
customer_external_id="customer_123",
|
|
68
|
+
plan_slug="pro",
|
|
69
|
+
billing_cycle="monthly",
|
|
70
|
+
success_url="https://yourapp.com/billing?status=success",
|
|
71
|
+
cancel_url="https://yourapp.com/billing?status=canceled",
|
|
72
|
+
)
|
|
73
|
+
print(f"Checkout URL: {session.checkout_url}")
|
|
74
|
+
|
|
75
|
+
asyncio.run(main())
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Features
|
|
79
|
+
|
|
80
|
+
- **Plans**: List available subscription plans
|
|
81
|
+
- **Subscribers**: Create and manage subscribers
|
|
82
|
+
- **Subscriptions**: Get subscription status, cancel, change plans
|
|
83
|
+
- **Checkout**: Create Stripe checkout sessions
|
|
84
|
+
- **Portal**: Create Stripe customer portal sessions
|
|
85
|
+
- **Invoices**: List invoice history with PDF downloads
|
|
86
|
+
- **Products**: List and purchase add-on products
|
|
87
|
+
|
|
88
|
+
## API Reference
|
|
89
|
+
|
|
90
|
+
### Client Initialization
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from growflow_billing import GrowFlowBillingClient
|
|
94
|
+
|
|
95
|
+
client = GrowFlowBillingClient(
|
|
96
|
+
api_key="sk_live_xxx", # Required
|
|
97
|
+
base_url="https://billing.growflow.studio/api/v1", # Optional
|
|
98
|
+
timeout=30.0, # Optional (seconds)
|
|
99
|
+
max_retries=3, # Optional
|
|
100
|
+
)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Plans
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
# List all active plans
|
|
107
|
+
plans = await client.get_plans()
|
|
108
|
+
|
|
109
|
+
# Access plan properties
|
|
110
|
+
for plan in plans:
|
|
111
|
+
print(plan.slug) # e.g., "pro"
|
|
112
|
+
print(plan.name) # e.g., "Pro Plan"
|
|
113
|
+
print(plan.price_monthly) # e.g., Decimal("349.00")
|
|
114
|
+
print(plan.price_yearly) # e.g., Decimal("3490.00")
|
|
115
|
+
print(plan.limits) # e.g., {"conversations": 5000, "stores": 3}
|
|
116
|
+
print(plan.features) # e.g., ["premium_support", "api_access"]
|
|
117
|
+
print(plan.trial_days) # e.g., 14
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Subscribers
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
# Create a new subscriber
|
|
124
|
+
subscriber = await client.create_subscriber(
|
|
125
|
+
external_id="store_123", # Your internal ID
|
|
126
|
+
email="owner@store.com",
|
|
127
|
+
name="My Store",
|
|
128
|
+
company_name="Store Inc.", # Optional
|
|
129
|
+
vat_number="IT12345678901", # Optional
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# Get subscriber by external ID
|
|
133
|
+
subscriber = await client.get_subscriber(external_id="store_123")
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Subscriptions
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
# Get active subscription
|
|
140
|
+
subscription = await client.get_subscription(external_id="store_123")
|
|
141
|
+
|
|
142
|
+
if subscription:
|
|
143
|
+
print(subscription.status) # "active", "trialing", "past_due", etc.
|
|
144
|
+
print(subscription.plan_slug) # "pro"
|
|
145
|
+
print(subscription.billing_cycle) # "monthly" or "yearly"
|
|
146
|
+
print(subscription.current_period_end) # datetime
|
|
147
|
+
print(subscription.is_trialing) # bool
|
|
148
|
+
print(subscription.trial_days_remaining) # int or None
|
|
149
|
+
|
|
150
|
+
# Cancel subscription
|
|
151
|
+
await client.cancel_subscription(
|
|
152
|
+
subscription_id="sub_xxx",
|
|
153
|
+
at_period_end=True, # Cancel at end of billing period
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
# Change plan
|
|
157
|
+
await client.change_plan(
|
|
158
|
+
subscription_id="sub_xxx",
|
|
159
|
+
new_plan_slug="enterprise",
|
|
160
|
+
prorate=True,
|
|
161
|
+
)
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Checkout Sessions
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
# Create checkout session for new subscription
|
|
168
|
+
session = await client.create_checkout_session(
|
|
169
|
+
customer_external_id="store_123",
|
|
170
|
+
plan_slug="pro",
|
|
171
|
+
billing_cycle="monthly", # or "yearly"
|
|
172
|
+
success_url="https://yourapp.com/billing?status=success",
|
|
173
|
+
cancel_url="https://yourapp.com/billing?status=canceled",
|
|
174
|
+
coupon_code="WELCOME20", # Optional discount code
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
# Redirect user to Stripe checkout
|
|
178
|
+
redirect_url = session.checkout_url
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Customer Portal
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
# Create portal session for subscription management
|
|
185
|
+
portal = await client.create_portal_session(
|
|
186
|
+
customer_external_id="store_123",
|
|
187
|
+
return_url="https://yourapp.com/billing",
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
# Redirect user to Stripe portal
|
|
191
|
+
redirect_url = portal.portal_url
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Invoices
|
|
195
|
+
|
|
196
|
+
```python
|
|
197
|
+
# List invoices
|
|
198
|
+
invoices = await client.get_invoices(
|
|
199
|
+
external_id="store_123",
|
|
200
|
+
limit=20,
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
for invoice in invoices:
|
|
204
|
+
print(invoice.number) # "INV-0001"
|
|
205
|
+
print(invoice.status) # "paid", "open", "void"
|
|
206
|
+
print(invoice.amount_paid) # 34900 (cents)
|
|
207
|
+
print(invoice.currency) # "eur"
|
|
208
|
+
print(invoice.invoice_pdf) # URL to PDF
|
|
209
|
+
print(invoice.hosted_invoice_url) # Stripe hosted page
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Error Handling
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
from growflow_billing import (
|
|
216
|
+
GrowFlowBillingError,
|
|
217
|
+
AuthenticationError,
|
|
218
|
+
NotFoundError,
|
|
219
|
+
ConflictError,
|
|
220
|
+
ValidationError,
|
|
221
|
+
RateLimitError,
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
try:
|
|
225
|
+
plans = await client.get_plans()
|
|
226
|
+
except AuthenticationError:
|
|
227
|
+
print("Invalid API key")
|
|
228
|
+
except NotFoundError as e:
|
|
229
|
+
print(f"Resource not found: {e.message}")
|
|
230
|
+
except RateLimitError:
|
|
231
|
+
print("Rate limit exceeded, try again later")
|
|
232
|
+
except GrowFlowBillingError as e:
|
|
233
|
+
print(f"API error: {e.message} (status: {e.status_code})")
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Configuration
|
|
237
|
+
|
|
238
|
+
Environment variables:
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
GROWFLOW_BILLING_API_KEY=sk_live_xxx
|
|
242
|
+
GROWFLOW_BILLING_URL=https://billing.growflow.studio/api/v1
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## License
|
|
246
|
+
|
|
247
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Publishing growflowbilling-client (Python SDK)
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The Python SDK is published to PyPI as `growflowbilling-client`.
|
|
6
|
+
Publishing is automated via GitHub Actions on push to `main` when files in `sdk/python/` change.
|
|
7
|
+
|
|
8
|
+
**Note**: The distribution name is `growflowbilling-client` but the Python import path remains `growflow_billing`:
|
|
9
|
+
|
|
10
|
+
```python
|
|
11
|
+
from growflow_billing import GrowFlowBillingClient
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## How It Works
|
|
15
|
+
|
|
16
|
+
1. **Version detection**: CI compares `pyproject.toml` version against the published PyPI version
|
|
17
|
+
2. **If version changed**: lint, type-check, test, build, publish to PyPI, create git tag
|
|
18
|
+
3. **If version unchanged**: CI skips publishing
|
|
19
|
+
|
|
20
|
+
## Publishing a New Version
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
cd sdk/python
|
|
24
|
+
|
|
25
|
+
# 1. Make your changes
|
|
26
|
+
# 2. Bump version in pyproject.toml
|
|
27
|
+
# version = "1.3.0"
|
|
28
|
+
|
|
29
|
+
# 3. Commit and push
|
|
30
|
+
git add pyproject.toml
|
|
31
|
+
git commit -m "chore(sdk): bump python SDK to vX.Y.Z"
|
|
32
|
+
git push origin main
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
CI will automatically:
|
|
36
|
+
- Run `ruff` linting and `mypy` type checking
|
|
37
|
+
- Run `pytest`
|
|
38
|
+
- Build with `python -m build`
|
|
39
|
+
- Publish to PyPI via OIDC Trusted Publisher (no tokens needed)
|
|
40
|
+
- Create a git tag `growflowbilling-python-sdk-vX.Y.Z`
|
|
41
|
+
|
|
42
|
+
## PyPI Trusted Publisher (OIDC)
|
|
43
|
+
|
|
44
|
+
Publishing uses PyPI's Trusted Publisher mechanism — no API tokens required.
|
|
45
|
+
|
|
46
|
+
**Setup (one-time, already done):**
|
|
47
|
+
1. PyPI → Manage → Publishing → Add trusted publisher for `growflowbilling-client`
|
|
48
|
+
- Owner: `giuliogarofalo`, Repo: `growflow-billing`, Workflow: `publish-python-sdk.yml`, Environment: `pypi`
|
|
49
|
+
2. GitHub → `growflow-billing` repo → Settings → Environments → Create `pypi` environment
|
|
50
|
+
|
|
51
|
+
## Local Development
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
cd sdk/python
|
|
55
|
+
pip install -e ".[dev]"
|
|
56
|
+
ruff check src/ # Linting
|
|
57
|
+
mypy src/ # Type checking
|
|
58
|
+
pytest # Tests
|
|
59
|
+
python -m build # Build sdist + wheel
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Consumer Usage
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pip install growflowbilling-client
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from growflow_billing import GrowFlowBillingClient
|
|
70
|
+
|
|
71
|
+
async with GrowFlowBillingClient(api_key="sk_...") as client:
|
|
72
|
+
plans = await client.get_plans()
|
|
73
|
+
```
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# GrowFlow Billing Client
|
|
2
|
+
|
|
3
|
+
Python client for [GrowFlow Billing API](https://billing.growflow.studio) - subscription management, checkout sessions, invoices, and more.
|
|
4
|
+
|
|
5
|
+
> **Documentation**: See [growflow-billing-docs](https://github.com/growflow/growflow-billing-docs) for complete API documentation and examples.
|
|
6
|
+
>
|
|
7
|
+
> **Node.js**: Looking for the Node.js/TypeScript client? See [@growflow/billing-client](https://github.com/growflow/growflow-billing-client-node).
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install growflow-billing-client
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Or install from source:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install git+https://github.com/growflow/growflow-billing-client.git
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
import asyncio
|
|
25
|
+
from growflow_billing import GrowFlowBillingClient
|
|
26
|
+
|
|
27
|
+
async def main():
|
|
28
|
+
async with GrowFlowBillingClient(api_key="sk_live_xxx") as client:
|
|
29
|
+
# Get available plans
|
|
30
|
+
plans = await client.get_plans()
|
|
31
|
+
for plan in plans:
|
|
32
|
+
print(f"{plan.name}: {plan.price_monthly} {plan.currency}/month")
|
|
33
|
+
|
|
34
|
+
# Create a checkout session
|
|
35
|
+
session = await client.create_checkout_session(
|
|
36
|
+
customer_external_id="customer_123",
|
|
37
|
+
plan_slug="pro",
|
|
38
|
+
billing_cycle="monthly",
|
|
39
|
+
success_url="https://yourapp.com/billing?status=success",
|
|
40
|
+
cancel_url="https://yourapp.com/billing?status=canceled",
|
|
41
|
+
)
|
|
42
|
+
print(f"Checkout URL: {session.checkout_url}")
|
|
43
|
+
|
|
44
|
+
asyncio.run(main())
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Features
|
|
48
|
+
|
|
49
|
+
- **Plans**: List available subscription plans
|
|
50
|
+
- **Subscribers**: Create and manage subscribers
|
|
51
|
+
- **Subscriptions**: Get subscription status, cancel, change plans
|
|
52
|
+
- **Checkout**: Create Stripe checkout sessions
|
|
53
|
+
- **Portal**: Create Stripe customer portal sessions
|
|
54
|
+
- **Invoices**: List invoice history with PDF downloads
|
|
55
|
+
- **Products**: List and purchase add-on products
|
|
56
|
+
|
|
57
|
+
## API Reference
|
|
58
|
+
|
|
59
|
+
### Client Initialization
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from growflow_billing import GrowFlowBillingClient
|
|
63
|
+
|
|
64
|
+
client = GrowFlowBillingClient(
|
|
65
|
+
api_key="sk_live_xxx", # Required
|
|
66
|
+
base_url="https://billing.growflow.studio/api/v1", # Optional
|
|
67
|
+
timeout=30.0, # Optional (seconds)
|
|
68
|
+
max_retries=3, # Optional
|
|
69
|
+
)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Plans
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
# List all active plans
|
|
76
|
+
plans = await client.get_plans()
|
|
77
|
+
|
|
78
|
+
# Access plan properties
|
|
79
|
+
for plan in plans:
|
|
80
|
+
print(plan.slug) # e.g., "pro"
|
|
81
|
+
print(plan.name) # e.g., "Pro Plan"
|
|
82
|
+
print(plan.price_monthly) # e.g., Decimal("349.00")
|
|
83
|
+
print(plan.price_yearly) # e.g., Decimal("3490.00")
|
|
84
|
+
print(plan.limits) # e.g., {"conversations": 5000, "stores": 3}
|
|
85
|
+
print(plan.features) # e.g., ["premium_support", "api_access"]
|
|
86
|
+
print(plan.trial_days) # e.g., 14
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Subscribers
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
# Create a new subscriber
|
|
93
|
+
subscriber = await client.create_subscriber(
|
|
94
|
+
external_id="store_123", # Your internal ID
|
|
95
|
+
email="owner@store.com",
|
|
96
|
+
name="My Store",
|
|
97
|
+
company_name="Store Inc.", # Optional
|
|
98
|
+
vat_number="IT12345678901", # Optional
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
# Get subscriber by external ID
|
|
102
|
+
subscriber = await client.get_subscriber(external_id="store_123")
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Subscriptions
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
# Get active subscription
|
|
109
|
+
subscription = await client.get_subscription(external_id="store_123")
|
|
110
|
+
|
|
111
|
+
if subscription:
|
|
112
|
+
print(subscription.status) # "active", "trialing", "past_due", etc.
|
|
113
|
+
print(subscription.plan_slug) # "pro"
|
|
114
|
+
print(subscription.billing_cycle) # "monthly" or "yearly"
|
|
115
|
+
print(subscription.current_period_end) # datetime
|
|
116
|
+
print(subscription.is_trialing) # bool
|
|
117
|
+
print(subscription.trial_days_remaining) # int or None
|
|
118
|
+
|
|
119
|
+
# Cancel subscription
|
|
120
|
+
await client.cancel_subscription(
|
|
121
|
+
subscription_id="sub_xxx",
|
|
122
|
+
at_period_end=True, # Cancel at end of billing period
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
# Change plan
|
|
126
|
+
await client.change_plan(
|
|
127
|
+
subscription_id="sub_xxx",
|
|
128
|
+
new_plan_slug="enterprise",
|
|
129
|
+
prorate=True,
|
|
130
|
+
)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Checkout Sessions
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
# Create checkout session for new subscription
|
|
137
|
+
session = await client.create_checkout_session(
|
|
138
|
+
customer_external_id="store_123",
|
|
139
|
+
plan_slug="pro",
|
|
140
|
+
billing_cycle="monthly", # or "yearly"
|
|
141
|
+
success_url="https://yourapp.com/billing?status=success",
|
|
142
|
+
cancel_url="https://yourapp.com/billing?status=canceled",
|
|
143
|
+
coupon_code="WELCOME20", # Optional discount code
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
# Redirect user to Stripe checkout
|
|
147
|
+
redirect_url = session.checkout_url
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Customer Portal
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
# Create portal session for subscription management
|
|
154
|
+
portal = await client.create_portal_session(
|
|
155
|
+
customer_external_id="store_123",
|
|
156
|
+
return_url="https://yourapp.com/billing",
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
# Redirect user to Stripe portal
|
|
160
|
+
redirect_url = portal.portal_url
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Invoices
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
# List invoices
|
|
167
|
+
invoices = await client.get_invoices(
|
|
168
|
+
external_id="store_123",
|
|
169
|
+
limit=20,
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
for invoice in invoices:
|
|
173
|
+
print(invoice.number) # "INV-0001"
|
|
174
|
+
print(invoice.status) # "paid", "open", "void"
|
|
175
|
+
print(invoice.amount_paid) # 34900 (cents)
|
|
176
|
+
print(invoice.currency) # "eur"
|
|
177
|
+
print(invoice.invoice_pdf) # URL to PDF
|
|
178
|
+
print(invoice.hosted_invoice_url) # Stripe hosted page
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Error Handling
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
from growflow_billing import (
|
|
185
|
+
GrowFlowBillingError,
|
|
186
|
+
AuthenticationError,
|
|
187
|
+
NotFoundError,
|
|
188
|
+
ConflictError,
|
|
189
|
+
ValidationError,
|
|
190
|
+
RateLimitError,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
try:
|
|
194
|
+
plans = await client.get_plans()
|
|
195
|
+
except AuthenticationError:
|
|
196
|
+
print("Invalid API key")
|
|
197
|
+
except NotFoundError as e:
|
|
198
|
+
print(f"Resource not found: {e.message}")
|
|
199
|
+
except RateLimitError:
|
|
200
|
+
print("Rate limit exceeded, try again later")
|
|
201
|
+
except GrowFlowBillingError as e:
|
|
202
|
+
print(f"API error: {e.message} (status: {e.status_code})")
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Configuration
|
|
206
|
+
|
|
207
|
+
Environment variables:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
GROWFLOW_BILLING_API_KEY=sk_live_xxx
|
|
211
|
+
GROWFLOW_BILLING_URL=https://billing.growflow.studio/api/v1
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## License
|
|
215
|
+
|
|
216
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "growflowbilling-client"
|
|
3
|
+
version = "1.2.0"
|
|
4
|
+
description = "Python client for GrowFlow Billing API - subscription management, checkout, invoices"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.10"
|
|
7
|
+
license = {text = "MIT"}
|
|
8
|
+
authors = [
|
|
9
|
+
{name = "GrowFlow", email = "dev@growflow.studio"}
|
|
10
|
+
]
|
|
11
|
+
keywords = ["billing", "subscriptions", "stripe", "payments", "saas"]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 4 - Beta",
|
|
14
|
+
"Intended Audience :: Developers",
|
|
15
|
+
"License :: OSI Approved :: MIT License",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3.10",
|
|
18
|
+
"Programming Language :: Python :: 3.11",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
21
|
+
"Typing :: Typed",
|
|
22
|
+
]
|
|
23
|
+
dependencies = [
|
|
24
|
+
"httpx>=0.25.0",
|
|
25
|
+
"pydantic[email]>=2.0.0",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.optional-dependencies]
|
|
29
|
+
dev = [
|
|
30
|
+
"pytest>=7.0.0",
|
|
31
|
+
"pytest-asyncio>=0.21.0",
|
|
32
|
+
"respx>=0.20.0",
|
|
33
|
+
"ruff>=0.1.0",
|
|
34
|
+
"mypy>=1.0.0",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[project.urls]
|
|
38
|
+
Homepage = "https://github.com/giuliogarofalo/growflow-billing"
|
|
39
|
+
Documentation = "https://docs.growflow.studio/billing-client"
|
|
40
|
+
Repository = "https://github.com/giuliogarofalo/growflow-billing"
|
|
41
|
+
|
|
42
|
+
[build-system]
|
|
43
|
+
requires = ["hatchling"]
|
|
44
|
+
build-backend = "hatchling.build"
|
|
45
|
+
|
|
46
|
+
[tool.hatch.build.targets.wheel]
|
|
47
|
+
packages = ["src/growflow_billing"]
|
|
48
|
+
|
|
49
|
+
[tool.ruff]
|
|
50
|
+
line-length = 100
|
|
51
|
+
target-version = "py310"
|
|
52
|
+
|
|
53
|
+
[tool.ruff.lint]
|
|
54
|
+
select = ["E", "F", "I", "N", "W", "UP"]
|
|
55
|
+
|
|
56
|
+
[tool.mypy]
|
|
57
|
+
python_version = "3.10"
|
|
58
|
+
strict = true
|
|
59
|
+
|
|
60
|
+
[tool.pytest.ini_options]
|
|
61
|
+
asyncio_mode = "auto"
|
|
62
|
+
testpaths = ["tests"]
|