vatly-api-python 0.1.0a2__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.
Files changed (34) hide show
  1. vatly_api_python-0.1.0a2/.gitignore +9 -0
  2. vatly_api_python-0.1.0a2/CHANGELOG.md +18 -0
  3. vatly_api_python-0.1.0a2/LICENSE +21 -0
  4. vatly_api_python-0.1.0a2/PKG-INFO +144 -0
  5. vatly_api_python-0.1.0a2/README.md +126 -0
  6. vatly_api_python-0.1.0a2/docs/API.md +110 -0
  7. vatly_api_python-0.1.0a2/docs/Chargebacks.md +11 -0
  8. vatly_api_python-0.1.0a2/docs/Checkouts.md +14 -0
  9. vatly_api_python-0.1.0a2/docs/Customers.md +12 -0
  10. vatly_api_python-0.1.0a2/docs/Development.md +55 -0
  11. vatly_api_python-0.1.0a2/docs/OneOffProducts.md +12 -0
  12. vatly_api_python-0.1.0a2/docs/Orders.md +15 -0
  13. vatly_api_python-0.1.0a2/docs/README.md +25 -0
  14. vatly_api_python-0.1.0a2/docs/Refunds.md +13 -0
  15. vatly_api_python-0.1.0a2/docs/SubscriptionPlans.md +13 -0
  16. vatly_api_python-0.1.0a2/docs/Subscriptions.md +21 -0
  17. vatly_api_python-0.1.0a2/docs/Webhooks.md +34 -0
  18. vatly_api_python-0.1.0a2/openapi.yaml +8584 -0
  19. vatly_api_python-0.1.0a2/pyproject.toml +55 -0
  20. vatly_api_python-0.1.0a2/scripts/check_package.py +21 -0
  21. vatly_api_python-0.1.0a2/scripts/generate.py +333 -0
  22. vatly_api_python-0.1.0a2/src/vatly/__init__.py +43 -0
  23. vatly_api_python-0.1.0a2/src/vatly/_model.py +13 -0
  24. vatly_api_python-0.1.0a2/src/vatly/_transport.py +284 -0
  25. vatly_api_python-0.1.0a2/src/vatly/_version.py +1 -0
  26. vatly_api_python-0.1.0a2/src/vatly/client.py +100 -0
  27. vatly_api_python-0.1.0a2/src/vatly/errors.py +86 -0
  28. vatly_api_python-0.1.0a2/src/vatly/models.py +3009 -0
  29. vatly_api_python-0.1.0a2/src/vatly/pagination.py +29 -0
  30. vatly_api_python-0.1.0a2/src/vatly/py.typed +1 -0
  31. vatly_api_python-0.1.0a2/src/vatly/resources.py +2003 -0
  32. vatly_api_python-0.1.0a2/src/vatly/webhooks.py +146 -0
  33. vatly_api_python-0.1.0a2/tests/conftest.py +49 -0
  34. vatly_api_python-0.1.0a2/tests/test_sdk.py +446 -0
@@ -0,0 +1,9 @@
1
+ .venv/
2
+ __pycache__/
3
+ .pytest_cache/
4
+ .mypy_cache/
5
+ .ruff_cache/
6
+ dist/
7
+ *.egg-info/
8
+ .amp/portals/*
9
+ .env
@@ -0,0 +1,18 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0a2 — Unreleased
4
+
5
+ - Use the PyPI distribution name `vatly-api-python`; imports remain `vatly`.
6
+ - Preserve enabled currency/precision intersections in generated Money models.
7
+ - Reject empty successful resource responses instead of returning untyped None.
8
+ - Include request method and URL in timeout/connection errors in both clients.
9
+
10
+ ## 0.1.0a1 — Unreleased
11
+
12
+ > Alpha — under active development. Every alpha release may include breaking changes. Pin exact versions during alpha.
13
+
14
+ - Initial typed Python SDK covering all 50 production OpenAPI operations.
15
+ - Pydantic models, sync/async httpx clients, cursor iterators, retries, idempotency,
16
+ per-request timeouts, typed errors and raw-body webhook verification.
17
+ - Documentation, reproducible code generation, CI, trusted-publishing workflow,
18
+ and cached orb development setup. Nothing published or tagged.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vatly
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,144 @@
1
+ Metadata-Version: 2.4
2
+ Name: vatly-api-python
3
+ Version: 0.1.0a2
4
+ Summary: Python SDK for Vatly, the merchant of record for AI, software and digital products
5
+ Project-URL: Homepage, https://github.com/vatly/vatly-api-python
6
+ Project-URL: Documentation, https://docs.vatly.com
7
+ Project-URL: Issues, https://github.com/vatly/vatly-api-python/issues
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Typing :: Typed
13
+ Requires-Python: >=3.10
14
+ Requires-Dist: httpx<1,>=0.27
15
+ Requires-Dist: pydantic<3,>=2.11
16
+ Requires-Dist: typing-extensions<5,>=4.12
17
+ Description-Content-Type: text/markdown
18
+
19
+ # Vatly Python SDK
20
+
21
+ > **Alpha — under active development. Every alpha release may include breaking changes. Pin exact versions during alpha.**
22
+
23
+ Python SDK for Vatly, the merchant of record for AI, software and digital products.
24
+ Python 3.10+, Pydantic v2 models, and pooled httpx sync/async clients. All 50 production
25
+ OpenAPI operations are covered. No package has been published yet.
26
+
27
+ ## Installation
28
+
29
+ Once published:
30
+
31
+ ```bash
32
+ pip install vatly-api-python==0.1.0a2
33
+ ```
34
+
35
+ For local development: `uv sync --locked`.
36
+
37
+ ## Quick start
38
+
39
+ Get a test or live API key from [the dashboard](https://my.vatly.com), under Settings > API.
40
+ Keep keys server-side. The client reads `VATLY_API_KEY` by default.
41
+
42
+ ```python
43
+ from vatly import VatlyClient
44
+ from vatly.models import CreateCheckoutRequest
45
+
46
+ with VatlyClient() as vatly:
47
+ checkout = vatly.checkouts.create(
48
+ CreateCheckoutRequest(
49
+ redirect_url_success="https://example.com/success",
50
+ redirect_url_canceled="https://example.com/canceled",
51
+ products=[{"id": "subscription_plan_abc123", "quantity": 1}],
52
+ )
53
+ )
54
+ print(checkout.links.checkout_url.href)
55
+ ```
56
+
57
+ ```python
58
+ from vatly import AsyncVatlyClient
59
+
60
+
61
+ async def read_orders():
62
+ async with AsyncVatlyClient() as vatly:
63
+ async for order in vatly.orders.list_all({"limit": 100}):
64
+ print(order.id, order.total)
65
+ ```
66
+
67
+ Pydantic models use snake_case attributes and accept Vatly's camelCase aliases.
68
+ Dictionary inputs use **wire-format camelCase keys**. Model requests serialize with
69
+ aliases and omit unset fields; explicitly supplied `None` is sent as JSON null.
70
+ Money values remain decimal **strings**, never floats.
71
+
72
+ ## Configuration and reliability
73
+
74
+ ```python
75
+ from vatly import VatlyClient, RequestOptions
76
+
77
+ with VatlyClient(timeout=30, max_retries=2) as vatly:
78
+ page = vatly.customers.list({"limit": 25}, options=RequestOptions(timeout=10))
79
+ ```
80
+
81
+ Timeouts are **seconds per httpx network phase per attempt**, not a total request deadline;
82
+ zero disables timeouts. Default base URL: `https://api.vatly.com/v1`.
83
+ `base_url`, `default_headers`, and `transport` (an httpx transport) can be overridden.
84
+ `mode` exposes `test` or `live`. Test helpers reject live keys before sending.
85
+
86
+ POST/PATCH/PUT/DELETE receive a UUID idempotency key, reused across retries.
87
+ Set `RequestOptions(idempotency_key="your-operation-id")` to reuse a business-operation key
88
+ across separate SDK calls. Set `idempotency_key_generator=None` to disable auto-keys.
89
+ GETs and keyed mutations retry 429, 5xx, timeouts and connection errors with exponential
90
+ backoff (250ms to 8s plus jitter), honoring numeric or HTTP-date `Retry-After`.
91
+ Keyed 409 retries **only** `details.idempotency_outcome == "in_progress"`.
92
+ Never blindly retry an `unknown` idempotency outcome: read/reconcile the resource first.
93
+ Unkeyed mutations do not retry. Redirects are not followed.
94
+
95
+ `Vatly-Client-Info` identifies SDK/runtime/OS/architecture. Pass
96
+ `client_info={"app": "MyApp/1.0", "framework": "Django/5"}` to add sanitized identifiers,
97
+ or `client_info=False` to suppress the SDK-generated header.
98
+
99
+ ## Errors
100
+
101
+ All API/transport errors extend `VatlyError`, with `status`, `body`, `url`, `method`,
102
+ `details`, `errors` and `retry_after`. Network errors retain the httpx exception as `__cause__`.
103
+
104
+ | Status | Error |
105
+ | --- | --- |
106
+ | 401 | `VatlyAuthError` |
107
+ | 403 | `VatlyForbiddenError` |
108
+ | 404 | `VatlyNotFoundError` |
109
+ | 409 | `VatlyConflictError` |
110
+ | 422 | `VatlyValidationError` |
111
+ | 429 | `VatlyRateLimitError` |
112
+ | Other / invalid response | `VatlyApiError` |
113
+ | Network / timeout | `VatlyConnectionError` / `VatlyTimeoutError` |
114
+
115
+ ```python
116
+ from vatly import VatlyValidationError
117
+
118
+ try:
119
+ # Your API call here
120
+ pass
121
+ except VatlyValidationError as error:
122
+ print(error.errors)
123
+ ```
124
+
125
+ See [getting started and resource guides](docs/README.md), the generated
126
+ [method inventory](docs/API.md), [webhook guide](docs/Webhooks.md), and
127
+ [production API reference](https://docs.vatly.com/api-reference).
128
+
129
+ ## Development
130
+
131
+ Run `.agents/setup` in a fresh orb. It installs uv if missing, provisions Python 3.12,
132
+ syncs locked dependencies and runs an import sanity check. Warm runs reuse uv's caches.
133
+
134
+ ```bash
135
+ uv run python scripts/generate.py --check
136
+ uv run ruff check .
137
+ uv run ruff format --check .
138
+ uv run mypy
139
+ uv run pytest
140
+ uv build
141
+ uv run twine check dist/*
142
+ ```
143
+
144
+ See [maintainer notes](docs/Development.md) for spec regeneration, docs sync, and trusted publishing.
@@ -0,0 +1,126 @@
1
+ # Vatly Python SDK
2
+
3
+ > **Alpha — under active development. Every alpha release may include breaking changes. Pin exact versions during alpha.**
4
+
5
+ Python SDK for Vatly, the merchant of record for AI, software and digital products.
6
+ Python 3.10+, Pydantic v2 models, and pooled httpx sync/async clients. All 50 production
7
+ OpenAPI operations are covered. No package has been published yet.
8
+
9
+ ## Installation
10
+
11
+ Once published:
12
+
13
+ ```bash
14
+ pip install vatly-api-python==0.1.0a2
15
+ ```
16
+
17
+ For local development: `uv sync --locked`.
18
+
19
+ ## Quick start
20
+
21
+ Get a test or live API key from [the dashboard](https://my.vatly.com), under Settings > API.
22
+ Keep keys server-side. The client reads `VATLY_API_KEY` by default.
23
+
24
+ ```python
25
+ from vatly import VatlyClient
26
+ from vatly.models import CreateCheckoutRequest
27
+
28
+ with VatlyClient() as vatly:
29
+ checkout = vatly.checkouts.create(
30
+ CreateCheckoutRequest(
31
+ redirect_url_success="https://example.com/success",
32
+ redirect_url_canceled="https://example.com/canceled",
33
+ products=[{"id": "subscription_plan_abc123", "quantity": 1}],
34
+ )
35
+ )
36
+ print(checkout.links.checkout_url.href)
37
+ ```
38
+
39
+ ```python
40
+ from vatly import AsyncVatlyClient
41
+
42
+
43
+ async def read_orders():
44
+ async with AsyncVatlyClient() as vatly:
45
+ async for order in vatly.orders.list_all({"limit": 100}):
46
+ print(order.id, order.total)
47
+ ```
48
+
49
+ Pydantic models use snake_case attributes and accept Vatly's camelCase aliases.
50
+ Dictionary inputs use **wire-format camelCase keys**. Model requests serialize with
51
+ aliases and omit unset fields; explicitly supplied `None` is sent as JSON null.
52
+ Money values remain decimal **strings**, never floats.
53
+
54
+ ## Configuration and reliability
55
+
56
+ ```python
57
+ from vatly import VatlyClient, RequestOptions
58
+
59
+ with VatlyClient(timeout=30, max_retries=2) as vatly:
60
+ page = vatly.customers.list({"limit": 25}, options=RequestOptions(timeout=10))
61
+ ```
62
+
63
+ Timeouts are **seconds per httpx network phase per attempt**, not a total request deadline;
64
+ zero disables timeouts. Default base URL: `https://api.vatly.com/v1`.
65
+ `base_url`, `default_headers`, and `transport` (an httpx transport) can be overridden.
66
+ `mode` exposes `test` or `live`. Test helpers reject live keys before sending.
67
+
68
+ POST/PATCH/PUT/DELETE receive a UUID idempotency key, reused across retries.
69
+ Set `RequestOptions(idempotency_key="your-operation-id")` to reuse a business-operation key
70
+ across separate SDK calls. Set `idempotency_key_generator=None` to disable auto-keys.
71
+ GETs and keyed mutations retry 429, 5xx, timeouts and connection errors with exponential
72
+ backoff (250ms to 8s plus jitter), honoring numeric or HTTP-date `Retry-After`.
73
+ Keyed 409 retries **only** `details.idempotency_outcome == "in_progress"`.
74
+ Never blindly retry an `unknown` idempotency outcome: read/reconcile the resource first.
75
+ Unkeyed mutations do not retry. Redirects are not followed.
76
+
77
+ `Vatly-Client-Info` identifies SDK/runtime/OS/architecture. Pass
78
+ `client_info={"app": "MyApp/1.0", "framework": "Django/5"}` to add sanitized identifiers,
79
+ or `client_info=False` to suppress the SDK-generated header.
80
+
81
+ ## Errors
82
+
83
+ All API/transport errors extend `VatlyError`, with `status`, `body`, `url`, `method`,
84
+ `details`, `errors` and `retry_after`. Network errors retain the httpx exception as `__cause__`.
85
+
86
+ | Status | Error |
87
+ | --- | --- |
88
+ | 401 | `VatlyAuthError` |
89
+ | 403 | `VatlyForbiddenError` |
90
+ | 404 | `VatlyNotFoundError` |
91
+ | 409 | `VatlyConflictError` |
92
+ | 422 | `VatlyValidationError` |
93
+ | 429 | `VatlyRateLimitError` |
94
+ | Other / invalid response | `VatlyApiError` |
95
+ | Network / timeout | `VatlyConnectionError` / `VatlyTimeoutError` |
96
+
97
+ ```python
98
+ from vatly import VatlyValidationError
99
+
100
+ try:
101
+ # Your API call here
102
+ pass
103
+ except VatlyValidationError as error:
104
+ print(error.errors)
105
+ ```
106
+
107
+ See [getting started and resource guides](docs/README.md), the generated
108
+ [method inventory](docs/API.md), [webhook guide](docs/Webhooks.md), and
109
+ [production API reference](https://docs.vatly.com/api-reference).
110
+
111
+ ## Development
112
+
113
+ Run `.agents/setup` in a fresh orb. It installs uv if missing, provisions Python 3.12,
114
+ syncs locked dependencies and runs an import sanity check. Warm runs reuse uv's caches.
115
+
116
+ ```bash
117
+ uv run python scripts/generate.py --check
118
+ uv run ruff check .
119
+ uv run ruff format --check .
120
+ uv run mypy
121
+ uv run pytest
122
+ uv build
123
+ uv run twine check dist/*
124
+ ```
125
+
126
+ See [maintainer notes](docs/Development.md) for spec regeneration, docs sync, and trusted publishing.
@@ -0,0 +1,110 @@
1
+ # API reference
2
+
3
+ Generated from `openapi.yaml`. Sync and async clients expose the same methods.
4
+ Pass a Pydantic request/params model or a wire-format dictionary. All methods accept keyword-only `options=RequestOptions(...)`.
5
+
6
+ ## `checkouts`
7
+
8
+ | Method | HTTP endpoint | Returns |
9
+ | --- | --- | --- |
10
+ | `list(params=None)` | `GET /checkouts` | `Page[Checkout]` |
11
+ | `create(body)` | `POST /checkouts` | `Checkout` |
12
+ | `get(checkout_id)` | `GET /checkouts/{checkoutId}` | `Checkout` |
13
+
14
+ ## `customers`
15
+
16
+ | Method | HTTP endpoint | Returns |
17
+ | --- | --- | --- |
18
+ | `list(params=None)` | `GET /customers` | `Page[Customer]` |
19
+ | `create(body)` | `POST /customers` | `Customer` |
20
+ | `get(customer_id)` | `GET /customers/{customerId}` | `Customer` |
21
+ | `update(customer_id, body)` | `PATCH /customers/{customerId}` | `Customer` |
22
+ | `create_portal_session(customer_id, body)` | `POST /customers/{customerId}/portal-sessions` | `PortalSession` |
23
+ | `list_subscriptions(customer_id, params=None)` | `GET /customers/{customerId}/subscriptions` | `Page[Subscription]` |
24
+ | `get_subscription(customer_id, subscription_id)` | `GET /customers/{customerId}/subscriptions/{subscriptionId}` | `Subscription` |
25
+
26
+ ## `one_off_products`
27
+
28
+ | Method | HTTP endpoint | Returns |
29
+ | --- | --- | --- |
30
+ | `list(params=None)` | `GET /one-off-products` | `Page[OneOffProduct]` |
31
+ | `create(body)` | `POST /one-off-products` | `OneOffProduct` |
32
+ | `get(one_off_product_id)` | `GET /one-off-products/{oneOffProductId}` | `OneOffProduct` |
33
+ | `update(one_off_product_id, body)` | `PATCH /one-off-products/{oneOffProductId}` | `OneOffProduct` |
34
+ | `archive(one_off_product_id)` | `POST /one-off-products/{oneOffProductId}/archive` | `None` |
35
+ | `unarchive(one_off_product_id)` | `DELETE /one-off-products/{oneOffProductId}/archive` | `OneOffProduct` |
36
+
37
+ ## `subscription_plans`
38
+
39
+ | Method | HTTP endpoint | Returns |
40
+ | --- | --- | --- |
41
+ | `list(params=None)` | `GET /subscription-plans` | `Page[SubscriptionPlan]` |
42
+ | `create(body)` | `POST /subscription-plans` | `SubscriptionPlan` |
43
+ | `get(subscription_plan_id)` | `GET /subscription-plans/{subscriptionPlanId}` | `SubscriptionPlan` |
44
+ | `update(subscription_plan_id, body)` | `PATCH /subscription-plans/{subscriptionPlanId}` | `SubscriptionPlan` |
45
+ | `archive(subscription_plan_id)` | `POST /subscription-plans/{subscriptionPlanId}/archive` | `None` |
46
+ | `unarchive(subscription_plan_id)` | `DELETE /subscription-plans/{subscriptionPlanId}/archive` | `SubscriptionPlan` |
47
+
48
+ ## `orders`
49
+
50
+ | Method | HTTP endpoint | Returns |
51
+ | --- | --- | --- |
52
+ | `list(params=None)` | `GET /orders` | `Page[Order]` |
53
+ | `get(order_id)` | `GET /orders/{orderId}` | `Order` |
54
+ | `create_invoice_update_link(order_id)` | `POST /orders/{orderId}/invoice-update-link` | `InvoiceUpdateLink` |
55
+ | `list_refunds(order_id, params=None)` | `GET /orders/{orderId}/refunds` | `Page[Refund]` |
56
+ | `create_refund(order_id, body)` | `POST /orders/{orderId}/refunds` | `Refund` |
57
+ | `create_full_refund(order_id, body)` | `POST /orders/{orderId}/refunds/full` | `Refund` |
58
+ | `get_refund(order_id, refund_id)` | `GET /orders/{orderId}/refunds/{refundId}` | `Refund` |
59
+ | `cancel_refund(order_id, refund_id)` | `DELETE /orders/{orderId}/refunds/{refundId}` | `None` |
60
+ | `list_chargebacks(order_id, params=None)` | `GET /orders/{orderId}/chargebacks` | `Page[Chargeback]` |
61
+ | `get_chargeback(order_id, chargeback_id)` | `GET /orders/{orderId}/chargebacks/{chargebackId}` | `Chargeback` |
62
+
63
+ ## `refunds`
64
+
65
+ | Method | HTTP endpoint | Returns |
66
+ | --- | --- | --- |
67
+ | `list(params=None)` | `GET /refunds` | `Page[Refund]` |
68
+ | `get(refund_id)` | `GET /refunds/{refundId}` | `Refund` |
69
+
70
+ ## `chargebacks`
71
+
72
+ | Method | HTTP endpoint | Returns |
73
+ | --- | --- | --- |
74
+ | `list(params=None)` | `GET /chargebacks` | `Page[Chargeback]` |
75
+ | `get(chargeback_id)` | `GET /chargebacks/{chargebackId}` | `Chargeback` |
76
+
77
+ ## `webhook_events`
78
+
79
+ | Method | HTTP endpoint | Returns |
80
+ | --- | --- | --- |
81
+ | `get(event_id)` | `GET /webhook-events/{eventId}` | `WebhookEvent` |
82
+
83
+ ## `webhook_endpoints`
84
+
85
+ | Method | HTTP endpoint | Returns |
86
+ | --- | --- | --- |
87
+ | `list(params=None)` | `GET /webhook-endpoints` | `Page[WebhookEndpoint]` |
88
+ | `create(body)` | `POST /webhook-endpoints` | `WebhookEndpoint` |
89
+ | `get(webhook_endpoint_id)` | `GET /webhook-endpoints/{webhookEndpointId}` | `WebhookEndpoint` |
90
+ | `update(webhook_endpoint_id, body)` | `PATCH /webhook-endpoints/{webhookEndpointId}` | `WebhookEndpoint` |
91
+ | `delete(webhook_endpoint_id)` | `DELETE /webhook-endpoints/{webhookEndpointId}` | `None` |
92
+
93
+ ## `subscriptions`
94
+
95
+ | Method | HTTP endpoint | Returns |
96
+ | --- | --- | --- |
97
+ | `list(params=None)` | `GET /subscriptions` | `Page[Subscription]` |
98
+ | `get(subscription_id)` | `GET /subscriptions/{subscriptionId}` | `Subscription` |
99
+ | `update(subscription_id, body)` | `PATCH /subscriptions/{subscriptionId}` | `Subscription` |
100
+ | `cancel(subscription_id, params=None)` | `DELETE /subscriptions/{subscriptionId}` | `None` |
101
+ | `create_billing_update_link(subscription_id, body)` | `POST /subscriptions/{subscriptionId}/billing-update-link` | `CreateSubscriptionBillingUpdateLinkResponse` |
102
+ | `resume(subscription_id)` | `POST /subscriptions/{subscriptionId}/resume` | `Subscription` |
103
+
104
+ ## `test_helpers`
105
+
106
+ | Method | HTTP endpoint | Returns |
107
+ | --- | --- | --- |
108
+ | `fast_forward_renewal(subscription_id, body)` | `POST /test-helpers/subscriptions/{subscriptionId}/fast-forward-renewal` | `Subscription` |
109
+ | `simulate_order_payment(order_id, body)` | `POST /test-helpers/orders/{orderId}/simulate-payment` | `Order` |
110
+
@@ -0,0 +1,11 @@
1
+ # Chargebacks
2
+
3
+ Read disputes via `client.chargebacks.list`, `list_all`, and `get`, or the
4
+ order-scoped `orders.list_chargebacks`, `list_all_chargebacks`, and `get_chargeback`.
5
+ All are read-only. Preserve the signed financial snapshot for accounting.
6
+
7
+ `order.chargeback_received` and `order.chargeback_reversed` webhook deliveries
8
+ carry a Chargeback in `object` even though `entity_type` is `order`.
9
+ Use `object.resource`, not the envelope entity type, to inspect the resource.
10
+
11
+ See [method inventory](API.md#chargebacks) and [chargeback fields](https://docs.vatly.com/api-reference/chargebacks).
@@ -0,0 +1,14 @@
1
+ # Checkouts
2
+
3
+ Use `client.checkouts.create(CreateCheckoutRequest(...))` to create a hosted payment
4
+ page. Redirect to `checkout.links.checkout_url.href`. Products use Vatly catalogue
5
+ IDs and quantities. Both success/cancellation redirect URLs are required. Use
6
+ `customer_id` for an existing authorized customer, or omit it for an anonymous flow.
7
+
8
+ Read one checkout with `get(id)`, one page with `list(params)`, or iterate with
9
+ `list_all(params)`. Async clients use `await` and `async for` respectively.
10
+ Reuse a business-operation idempotency key across caller retries. Confirm payment
11
+ through signed webhooks, not a browser redirect. A checkout's `order_id` links to
12
+ the order; the checkout itself intentionally has no products array.
13
+
14
+ See [method inventory](API.md#checkouts) and [production checkout fields](https://docs.vatly.com/api-reference/checkouts).
@@ -0,0 +1,12 @@
1
+ # Customers
2
+
3
+ `client.customers` provides `create`, `get`, `update`, `list`, `list_all`,
4
+ `create_portal_session`, `list_subscriptions`, `list_all_subscriptions`, and
5
+ `get_subscription`. Filter by email via `ListCustomersParams(email=...)` or
6
+ `{"email": "person@example.com"}`. Email identity is storefront- and mode-scoped.
7
+
8
+ `update` changes identity name/email, not billing-address details. Portal sessions
9
+ are short-lived and single-use: redirect to the returned `url`; do not store it as
10
+ a permanent link. Pass `{}` for an empty portal-session request body.
11
+
12
+ See [method inventory](API.md#customers) and [customer fields](https://docs.vatly.com/api-reference/customers).
@@ -0,0 +1,55 @@
1
+ # Development and release
2
+
3
+ ## Sources
4
+
5
+ `openapi.yaml` was fetched on 2026-11-09 from https://docs.vatly.com/openapi.yaml,
6
+ byte-identical to `vatly/vatly-docs/public/openapi.yaml` at
7
+ `7e71ade32d311b10f79e10c15d0ac03ae32bde97`.
8
+ SHA-256: `69640ac82bbba8d101e6aa882facd5f13aa5cf67f38508e5cea18abef03c4940`.
9
+ The spec's generated-at date is not the retrieval date.
10
+ JS design reference: `vatly/vatly-api-js` at `8b0b920c29f7e7b30bf71b9e379ec0a8a1a22028`.
11
+
12
+ To update, deliberately replace the pinned spec from that production URL, update
13
+ this provenance, run `uv run python scripts/generate.py`, inspect the diff, and
14
+ run all README checks. CI checks regeneration offline. Do not edit generated files.
15
+
16
+ Output objects preserve extra fields. URLs/emails remain strings. Input enums
17
+ and constraints are generated from the spec. Two observed production differences
18
+ are handled explicitly: empty metadata `[]` normalizes to `{}`, and the output
19
+ OneOffProduct.productType is an open string (production returns `digital_download`).
20
+ The checked-in spec is not patched. Response validation failures surface as
21
+ `VatlyApiError` with the Pydantic cause; response bodies may contain personal data.
22
+ Do not log them indiscriminately.
23
+
24
+ ## Documentation sync
25
+
26
+ `docs/README.md`, `API.md`, and the resource guides mirror the JS SDK's layout.
27
+ They are self-contained Markdown for a future vatly-docs Python SDK sync; no sync
28
+ job or changes to the docs repository are made here. Keep relative links portable.
29
+ `API.md` is generated; prose guides are maintained manually.
30
+
31
+ ## Orb setup
32
+
33
+ `.agents/setup` is executable, provisions uv 0.12.9 and Python 3.12, syncs the
34
+ lockfile, and checks imports. It does not read API credentials or make API calls.
35
+ Run twice to check warm behavior. No services or resume repairs are needed.
36
+ It will become available to project orbs once pushed to the default branch and
37
+ the repository is connected as an Amp project.
38
+
39
+ ## Future PyPI release (not executed)
40
+
41
+ The distribution name `vatly-api-python` returned 404 from PyPI's JSON API on 2026-11-12.
42
+ Availability is not a reservation or guarantee of PyPI name approval.
43
+
44
+ 1. Push reviewed code to the private `vatly/vatly-api-python` repository's main branch.
45
+ 2. Configure a PyPI pending trusted publisher for project `vatly-api-python`, owner `vatly`,
46
+ repository `vatly-api-python`, workflow `release.yml`; leave the environment field blank.
47
+ No GitHub environment or PyPI token is needed.
48
+ 3. Update both package-version sources and changelog, run CI, and only with approval
49
+ create a `v0.1.0a2` tag and publish its GitHub release (mark it a prerelease).
50
+ 4. The release workflow validates/builds first, then exchanges GitHub OIDC for PyPI
51
+ credentials. Anyone able to publish a matching GitHub release can initiate publication;
52
+ restrict repository release access accordingly. Publish the SDK before Fluent.
53
+
54
+ **A private GitHub repository does not make PyPI artifacts private.** Publishing
55
+ uploads the wheel and sdist publicly, including their source and packaged docs.
@@ -0,0 +1,12 @@
1
+ # One-off products
2
+
3
+ `client.one_off_products` provides `list`, `list_all`, `get`, `create`, `update`,
4
+ `archive`, and `unarchive`. Use `CreateOneOffProductRequest` and
5
+ `UpdateOneOffProductRequest` from `vatly.models`. `archive` returns `None`;
6
+ `unarchive` returns the resource. Mode and approval behavior follow the API key.
7
+
8
+ The output `product_type` preserves catalogue strings not yet listed in the
9
+ production spec (including observed `digital_download`). Request validation still
10
+ follows the production request schema. Unknown response fields are preserved.
11
+
12
+ See [method inventory](API.md#one_off_products) and [product fields](https://docs.vatly.com/api-reference/one-off-products).
@@ -0,0 +1,15 @@
1
+ # Orders
2
+
3
+ `client.orders` provides read/pagination plus nested refunds and chargebacks.
4
+ `create_invoice_update_link(order_id)` returns a hosted billing-details update
5
+ link. Financial money values remain decimal strings. Tax and metadata fields are
6
+ retained; do not reconstruct invoices from rounded float calculations.
7
+
8
+ An order line's `product_type` selects what `product_id` refers to. Readers must
9
+ support historical `subscription_plan` lines (plan IDs) and `subscription` lines
10
+ (subscription IDs). Pending core PR #2910 also stamps initial checkout lines with
11
+ the intended subscription ID. An intended ID may temporarily 404 or never resolve
12
+ for a skipped trial start: use bounded recovery and inspect status, not ID presence,
13
+ before granting access. One-off lines are unaffected.
14
+
15
+ See [method inventory](API.md#orders) and [order fields](https://docs.vatly.com/api-reference/orders).
@@ -0,0 +1,25 @@
1
+ # Getting started
2
+
3
+ > **Alpha — under active development. Every alpha release may include breaking changes. Pin exact versions during alpha.**
4
+
5
+ Use `vatly-api-python==0.1.0a2` (once published), imported as `vatly`. Requires Python 3.10+.
6
+ Create `VatlyClient` inside `with`, or `AsyncVatlyClient` inside `async with`, to
7
+ close the connection pool. Both accept an explicit API key or `VATLY_API_KEY`.
8
+ Test and live modes use the same API host; keys select the mode.
9
+
10
+ See the [SDK README](../README.md) for runnable initialization, checkout,
11
+ pagination, retries, configuration, errors and development commands.
12
+
13
+ | Guide | Purpose |
14
+ | --- | --- |
15
+ | [API](API.md) | Every method, endpoint and response |
16
+ | [Checkouts](Checkouts.md) | Hosted payment pages |
17
+ | [Customers](Customers.md) | Customer identity and portal sessions |
18
+ | [Subscriptions](Subscriptions.md) | Recurring billing |
19
+ | [Subscription Plans](SubscriptionPlans.md) | Subscription catalogue |
20
+ | [One-Off Products](OneOffProducts.md) | One-time catalogue |
21
+ | [Orders](Orders.md) | Transactions and nested financial operations |
22
+ | [Refunds](Refunds.md) | Reversals |
23
+ | [Chargebacks](Chargebacks.md) | Disputes |
24
+ | [Webhooks](Webhooks.md) | Signatures, events and endpoints |
25
+ | [Development](Development.md) | Spec/docs sync, setup, release |
@@ -0,0 +1,13 @@
1
+ # Refunds
2
+
3
+ Read refunds via `client.refunds.list`, `list_all`, and `get`. Order-scoped
4
+ operations are `orders.list_refunds`, `list_all_refunds`, `get_refund`,
5
+ `create_refund`, `create_full_refund`, and `cancel_refund`.
6
+
7
+ Partial refunds use `CreateRefundRequest` with order lines and amounts; full
8
+ refunds accept `CreateFullRefundRequest` or `{}`. A cancellation returns `None`.
9
+ Use stable idempotency keys for business operations; a timeout does not prove
10
+ that a refund failed. Read/reconcile before issuing another mutation when the
11
+ server reports an unknown outcome. Webhooks confirm completion/failure/cancellation.
12
+
13
+ See [method inventory](API.md#refunds) and [refund fields](https://docs.vatly.com/api-reference/refunds).
@@ -0,0 +1,13 @@
1
+ # Subscription plans
2
+
3
+ `client.subscription_plans` provides `list`, `list_all`, `get`, `create`, `update`,
4
+ `archive`, and `unarchive`. Use `CreateSubscriptionPlanRequest` and
5
+ `UpdateSubscriptionPlanRequest` from `vatly.models`. Money is a decimal string
6
+ plus currency; preserve both. Archiving returns `None`, unarchiving the plan.
7
+
8
+ Test-mode catalogue changes are auto-approved; live changes may await approval.
9
+ Archive prevents new sales, not existing subscription renewals. Select
10
+ `includeArchived` in dictionary filters when needed, or the corresponding model's
11
+ `include_archived` field.
12
+
13
+ See [method inventory](API.md#subscription_plans) and [plan fields](https://docs.vatly.com/api-reference/subscription-plans).
@@ -0,0 +1,21 @@
1
+ # Subscriptions
2
+
3
+ Use `client.subscriptions.get(id)`, `list(params)`, or `list_all(params)` to read.
4
+ Create a subscription through a checkout containing a subscription-plan ID.
5
+
6
+ `update(id, body)` changes plan, price or quantity. At least one is required;
7
+ `trial_until` cannot be sent alone. By default updates are scheduled; request
8
+ `apply_immediately` and the relevant invoice/proration flags deliberately.
9
+ `cancel(id, {"immediately": True})` encodes the boolean as `1`, as the server expects.
10
+ `resume(id)` is only valid during the cancellation grace period.
11
+
12
+ `create_billing_update_link(id, body)` returns a hosted link for billing details;
13
+ both redirect URLs are required. Check remote status before granting entitlements.
14
+ The signed subscription events carry full snapshots, including scheduled changes,
15
+ mandate, cancellation reason, and renewal periods.
16
+
17
+ Test-only helpers live under `client.test_helpers`: `fast_forward_renewal` and
18
+ `simulate_order_payment`. They mutate remote data and must never run in CI/live
19
+ verification without explicit intent. This repository's tests use mocks only.
20
+
21
+ See [method inventory](API.md#subscriptions) and [subscription fields](https://docs.vatly.com/api-reference/subscriptions).