solvapay-python 0.7.1__tar.gz → 0.8.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.
- solvapay_python-0.8.0/.github/ISSUE_TEMPLATE/bug.yml +27 -0
- solvapay_python-0.8.0/.github/ISSUE_TEMPLATE/feature.yml +23 -0
- solvapay_python-0.8.0/.github/ISSUE_TEMPLATE/question.yml +14 -0
- solvapay_python-0.8.0/.github/PULL_REQUEST_TEMPLATE.md +15 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/.github/workflows/ci.yml +3 -0
- solvapay_python-0.8.0/CHANGELOG.md +93 -0
- solvapay_python-0.8.0/CODEOWNERS +1 -0
- solvapay_python-0.8.0/CODE_OF_CONDUCT.md +27 -0
- solvapay_python-0.8.0/CONTRIBUTING.md +58 -0
- solvapay_python-0.8.0/PKG-INFO +315 -0
- solvapay_python-0.8.0/README.md +282 -0
- solvapay_python-0.8.0/SECURITY.md +36 -0
- solvapay_python-0.8.0/SUPPORT.md +10 -0
- solvapay_python-0.8.0/assets/agent-marketplace.png +0 -0
- solvapay_python-0.8.0/docs/architecture/layers.md +46 -0
- solvapay_python-0.8.0/docs/rfcs/0001-spending-policy.md +60 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/examples/fastmcp-paywall/pyproject.toml +1 -1
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/examples/langchain-paywall/pyproject.toml +1 -1
- solvapay_python-0.8.0/examples/marketplace/.gitignore +4 -0
- solvapay_python-0.8.0/examples/multi-framework-paywall/.env.example +3 -0
- solvapay_python-0.8.0/examples/multi-framework-paywall/.gitignore +4 -0
- solvapay_python-0.8.0/examples/multi-framework-paywall/README.md +52 -0
- solvapay_python-0.8.0/examples/multi-framework-paywall/agent_langchain.py +43 -0
- solvapay_python-0.8.0/examples/multi-framework-paywall/model.py +13 -0
- solvapay_python-0.8.0/examples/multi-framework-paywall/pyproject.toml +9 -0
- solvapay_python-0.8.0/examples/multi-framework-paywall/script_async.py +43 -0
- solvapay_python-0.8.0/examples/multi-framework-paywall/server_mcp.py +28 -0
- solvapay_python-0.8.0/examples/multi-framework-paywall/tool.py +36 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/pyproject.toml +4 -2
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/src/solvapay/__init__.py +31 -1
- solvapay_python-0.8.0/src/solvapay/_async_client.py +308 -0
- solvapay_python-0.8.0/src/solvapay/_http.py +21 -0
- solvapay_python-0.8.0/src/solvapay/_stability.py +60 -0
- solvapay_python-0.8.0/src/solvapay/_transport/__init__.py +106 -0
- solvapay_python-0.8.0/src/solvapay/_transport/_recipe.py +63 -0
- solvapay_python-0.8.0/src/solvapay/_transport/httpx_transport.py +397 -0
- solvapay_python-0.8.0/src/solvapay/_transport/middleware.py +233 -0
- solvapay_python-0.8.0/src/solvapay/adapters/__init__.py +3 -0
- solvapay_python-0.8.0/src/solvapay/adapters/langchain.py +88 -0
- solvapay_python-0.8.0/src/solvapay/adapters/mcp.py +158 -0
- solvapay_python-0.8.0/src/solvapay/client.py +303 -0
- solvapay_python-0.8.0/src/solvapay/langchain.py +15 -0
- solvapay_python-0.8.0/src/solvapay/operations/__init__.py +7 -0
- solvapay_python-0.8.0/src/solvapay/operations/_registry.py +117 -0
- solvapay_python-0.8.0/src/solvapay/operations/checkout.py +75 -0
- solvapay_python-0.8.0/src/solvapay/operations/customers.py +256 -0
- solvapay_python-0.8.0/src/solvapay/operations/limits.py +77 -0
- solvapay_python-0.8.0/src/solvapay/operations/merchant.py +71 -0
- solvapay_python-0.8.0/src/solvapay/operations/plans.py +167 -0
- solvapay_python-0.8.0/src/solvapay/operations/products.py +141 -0
- solvapay_python-0.8.0/src/solvapay/operations/purchases.py +103 -0
- solvapay_python-0.8.0/src/solvapay/operations/usage.py +75 -0
- solvapay_python-0.8.0/src/solvapay/paywall/__init__.py +32 -0
- solvapay_python-0.8.0/src/solvapay/paywall/core.py +152 -0
- solvapay_python-0.8.0/src/solvapay/paywall/decorators.py +126 -0
- solvapay_python-0.8.0/src/solvapay/paywall/meta.py +18 -0
- solvapay_python-0.8.0/src/solvapay/paywall/policy.py +14 -0
- solvapay_python-0.8.0/src/solvapay/paywall/resolvers.py +60 -0
- solvapay_python-0.8.0/src/solvapay/paywall/state.py +23 -0
- solvapay_python-0.8.0/src/solvapay/webhooks/__init__.py +28 -0
- solvapay_python-0.8.0/src/solvapay/webhooks/envelope.py +16 -0
- solvapay_python-0.8.0/src/solvapay/webhooks/pipeline.py +88 -0
- solvapay_python-0.8.0/src/solvapay/webhooks/replay.py +42 -0
- solvapay_python-0.8.0/src/solvapay/webhooks/rotation.py +32 -0
- solvapay_python-0.7.1/src/solvapay/webhooks.py → solvapay_python-0.8.0/src/solvapay/webhooks/verify.py +4 -22
- solvapay_python-0.8.0/tests/_stability/__init__.py +0 -0
- solvapay_python-0.8.0/tests/_stability/test_stable_returns_identity.py +75 -0
- solvapay_python-0.8.0/tests/_transport/__init__.py +0 -0
- solvapay_python-0.8.0/tests/_transport/test_aclose_cascade.py +100 -0
- solvapay_python-0.8.0/tests/_transport/test_error_wrapping.py +66 -0
- solvapay_python-0.8.0/tests/_transport/test_headers_case_insensitive.py +52 -0
- solvapay_python-0.8.0/tests/_transport/test_middleware_composition.py +51 -0
- solvapay_python-0.8.0/tests/_transport/test_protocol_conformance.py +46 -0
- solvapay_python-0.8.0/tests/adapters/__init__.py +0 -0
- solvapay_python-0.8.0/tests/adapters/test_langchain_protocol.py +99 -0
- solvapay_python-0.8.0/tests/adapters/test_mcp.py +165 -0
- solvapay_python-0.8.0/tests/operations/__init__.py +0 -0
- solvapay_python-0.8.0/tests/operations/test_namespace_api.py +59 -0
- solvapay_python-0.8.0/tests/operations/test_path_interpolation.py +54 -0
- solvapay_python-0.8.0/tests/operations/test_retry_safety_enum.py +57 -0
- solvapay_python-0.8.0/tests/paywall/__init__.py +0 -0
- solvapay_python-0.8.0/tests/paywall/test_checkout_mint_error_surfaces.py +52 -0
- solvapay_python-0.8.0/tests/paywall/test_payable_tool_meta.py +59 -0
- solvapay_python-0.8.0/tests/paywall/test_resolvers.py +47 -0
- solvapay_python-0.8.0/tests/paywall/test_split_classes.py +34 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/tests/test_invariants.py +2 -2
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/tests/test_langchain.py +21 -16
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/tests/test_lifecycle.py +3 -1
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/tests/test_paywall.py +5 -5
- solvapay_python-0.8.0/tests/webhooks/__init__.py +0 -0
- solvapay_python-0.8.0/tests/webhooks/test_clock_skew_vs_replay_ttl.py +58 -0
- solvapay_python-0.8.0/tests/webhooks/test_seen_cache_atomic.py +54 -0
- solvapay_python-0.8.0/tests/webhooks/test_webhook_pipeline.py +66 -0
- solvapay_python-0.8.0/tools/api_baseline.json +82 -0
- solvapay_python-0.8.0/tools/api_diff.py +60 -0
- solvapay_python-0.8.0/tools/importlinter.cfg +42 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/uv.lock +795 -114
- solvapay_python-0.7.1/CHANGELOG.md +0 -53
- solvapay_python-0.7.1/PKG-INFO +0 -278
- solvapay_python-0.7.1/README.md +0 -247
- solvapay_python-0.7.1/src/solvapay/_async_client.py +0 -387
- solvapay_python-0.7.1/src/solvapay/_http.py +0 -220
- solvapay_python-0.7.1/src/solvapay/client.py +0 -380
- solvapay_python-0.7.1/src/solvapay/langchain.py +0 -67
- solvapay_python-0.7.1/src/solvapay/paywall.py +0 -148
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/.github/workflows/publish.yml +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/.gitignore +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/.python-version +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/LICENSE +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/examples/fastmcp-paywall/.env.example +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/examples/fastmcp-paywall/.gitignore +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/examples/fastmcp-paywall/README.md +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/examples/fastmcp-paywall/claim.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/examples/fastmcp-paywall/server.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/examples/fastmcp-paywall/uv.lock +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/examples/langchain-paywall/.env.example +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/examples/langchain-paywall/.gitignore +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/examples/langchain-paywall/README.md +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/examples/langchain-paywall/agent.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/examples/marketplace/.env.example +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/examples/marketplace/.streamlit/config.toml +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/examples/marketplace/PLAN.md +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/examples/marketplace/README.md +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/examples/marketplace/agents.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/examples/marketplace/app.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/examples/marketplace/demo_customers.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/examples/marketplace/requirements.txt +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/examples/marketplace/sdk_gateway.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/examples/marketplace/ui_components.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/src/solvapay/_config.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/src/solvapay/events.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/src/solvapay/exceptions.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/src/solvapay/fastapi.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/src/solvapay/idempotency.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/src/solvapay/models.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/src/solvapay/paywall_state.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/src/solvapay/py.typed +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/tests/__init__.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/tests/conftest.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/tests/test_admin.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/tests/test_async_client.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/tests/test_checkout.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/tests/test_config.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/tests/test_customer.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/tests/test_errors.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/tests/test_http.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/tests/test_idempotency.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/tests/test_limits.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/tests/test_packaging.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/tests/test_paywall_state.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/tests/test_redaction.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/tests/test_webhook_events.py +0 -0
- {solvapay_python-0.7.1 → solvapay_python-0.8.0}/tests/test_webhooks.py +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: Bug Report
|
|
2
|
+
description: Something broken in the SDK
|
|
3
|
+
labels: [bug]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: Please fill in the details below.
|
|
8
|
+
- type: input
|
|
9
|
+
id: version
|
|
10
|
+
attributes:
|
|
11
|
+
label: SDK version
|
|
12
|
+
placeholder: "0.8.0"
|
|
13
|
+
validations:
|
|
14
|
+
required: true
|
|
15
|
+
- type: textarea
|
|
16
|
+
id: description
|
|
17
|
+
attributes:
|
|
18
|
+
label: What happened?
|
|
19
|
+
description: What did you expect vs what actually happened?
|
|
20
|
+
validations:
|
|
21
|
+
required: true
|
|
22
|
+
- type: textarea
|
|
23
|
+
id: repro
|
|
24
|
+
attributes:
|
|
25
|
+
label: Minimal repro
|
|
26
|
+
description: Minimal Python snippet to reproduce
|
|
27
|
+
render: python
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name: Feature Request
|
|
2
|
+
description: Suggest a new capability
|
|
3
|
+
labels: [enhancement]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: problem
|
|
7
|
+
attributes:
|
|
8
|
+
label: What problem does this solve?
|
|
9
|
+
validations:
|
|
10
|
+
required: true
|
|
11
|
+
- type: textarea
|
|
12
|
+
id: proposal
|
|
13
|
+
attributes:
|
|
14
|
+
label: Proposed solution
|
|
15
|
+
validations:
|
|
16
|
+
required: true
|
|
17
|
+
- type: dropdown
|
|
18
|
+
id: priority
|
|
19
|
+
attributes:
|
|
20
|
+
label: Priority
|
|
21
|
+
options:
|
|
22
|
+
- Nice to have
|
|
23
|
+
- Blocking a use-case
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
name: Question
|
|
2
|
+
description: How do I...?
|
|
3
|
+
labels: [question]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: question
|
|
7
|
+
attributes:
|
|
8
|
+
label: What are you trying to do?
|
|
9
|
+
validations:
|
|
10
|
+
required: true
|
|
11
|
+
- type: textarea
|
|
12
|
+
id: tried
|
|
13
|
+
attributes:
|
|
14
|
+
label: What have you tried?
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
## What
|
|
2
|
+
|
|
3
|
+
<!-- Brief description of the change -->
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
<!-- Problem it solves or feature it adds -->
|
|
8
|
+
|
|
9
|
+
## Checklist
|
|
10
|
+
|
|
11
|
+
- [ ] Tests added / updated
|
|
12
|
+
- [ ] `CHANGELOG.md` entry added
|
|
13
|
+
- [ ] Layer DAG respected (`uv run lint-imports` passes)
|
|
14
|
+
- [ ] If new public exports: `tools/api_baseline.json` updated
|
|
15
|
+
- [ ] Docs updated (if public API changed)
|
|
@@ -20,5 +20,8 @@ jobs:
|
|
|
20
20
|
run: uv python install ${{ matrix.python-version }}
|
|
21
21
|
- run: uv sync --all-extras --dev
|
|
22
22
|
- run: uv run ruff check src tests
|
|
23
|
+
- run: uv run ruff format --check src tests
|
|
23
24
|
- run: uv run mypy src
|
|
24
25
|
- run: uv run pytest -v
|
|
26
|
+
- run: uv run python tools/api_diff.py
|
|
27
|
+
- run: uv run lint-imports --config tools/importlinter.cfg
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.8.0 — 2026-05-23
|
|
4
|
+
|
|
5
|
+
V1 architecture spine + AI-agent moat. 10 atomic commits establishing locked architecture invariants per HLD §V1.1–V1.19.
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **Transport Protocol kernel** (`solvapay._transport`): `Transport`/`AsyncTransport` Protocol shapes, `RequestSpec`/`ResponseSpec` frozen dataclasses, case-insensitive `Headers`, canonical middleware stack (`Redacting` → `Logging` → `IdempotencyHeader` → `ContextPropagating`), `default_stack()` recipe.
|
|
9
|
+
- **Operations registry + resource-namespace API**: `OpSpec` + `RetrySafety` enum, `REGISTRY`, path interpolation with `urllib.parse.quote`. All clients gain eager namespace attrs: `sv.customers`, `sv.checkout`, `sv.limits`, `sv.purchases`, `sv.usage`, `sv.products`, `sv.plans`, `sv.merchant`.
|
|
10
|
+
- **Paywall package** (`solvapay.paywall`): `Paywall`/`AsyncPaywall` split with type-narrowed construction, `PaywallRequired.checkout_mint_error`, `PayableToolMeta(_meta_version=1)`, `KwargsResolver`/`PositionalResolver`/`PydanticBodyResolver`, `@require`/`@require_async`/`@payable_tool` decorators.
|
|
11
|
+
- **Webhook pipeline** (`solvapay.webhooks`): `WebhookPipeline` with two-knob config (`max_clock_skew_seconds`, `replay_ttl_seconds`), atomic `SeenEventCache.try_claim` (`threading.Lock`), `MultiSecretVerifier` interface, `WebhookEnvelope` dataclass.
|
|
12
|
+
- **`solvapay.adapters.mcp`** (optional `solvapay[mcp]`): `@payable_tool` decorator + four schema flavors (`payable_tool_mcp_schema`, `payable_tool_openai_function`, `payable_tool_anthropic_tool`, `payable_tool_langchain_args_schema`), `register_payable_tool_fastmcp`.
|
|
13
|
+
- **Stability manifest** (`solvapay._stability`): `stable(X)→X` identity decorator registers in `MANIFEST`; `experimental` emits once-per-process `RuntimeWarning`; `deprecated(removed_in=)`. CI gate: `tools/api_diff.py` fails on `@stable` symbol removal without prior `@deprecated`.
|
|
14
|
+
- **Import-linter DAG gate**: `tools/importlinter.cfg` (3 contracts), `docs/architecture/layers.md`. CI fails on layer violation.
|
|
15
|
+
- **LangChain adapter refactor** (`solvapay.adapters.langchain`): Protocol duck-typing — no hard `langchain_core` import at module level; absorbs 0.3→0.4 churn.
|
|
16
|
+
- **Multi-framework demo** (`examples/multi-framework-paywall/`): one `@payable_tool`-decorated function runs across FastMCP, LangChain, and raw async — "one tool, three runtimes, one paywall."
|
|
17
|
+
- **Governance scaffold**: `CODEOWNERS`, `SECURITY.md`, `CODE_OF_CONDUCT.md`, `SUPPORT.md`, `CONTRIBUTING.md`, GitHub issue templates, PR template, `docs/rfcs/0001-spending-policy.md`.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
- **Flat methods deprecated**: `sv.ensure_customer()`, `sv.check_limits()`, etc. now emit `DeprecationWarning(stacklevel=2)` per call. Use `sv.customers.ensure()`, `sv.limits.check()`, etc. Flat shims removed in v2.0.
|
|
21
|
+
- **`langchain-core` upper bound**: `langchain-core>=0.3,<0.4` now enforced in both dev and optional deps.
|
|
22
|
+
- **`solvapay.langchain`** replaced by `solvapay.adapters.langchain`; old path is a deprecated shim.
|
|
23
|
+
|
|
24
|
+
### Deprecated
|
|
25
|
+
- `SolvaPayAPIError` — use `APIError`. Alias fires `DeprecationWarning`; removed in v2.0.
|
|
26
|
+
- All flat client methods (`sv.ensure_customer`, `sv.check_limits`, etc.) — use resource-namespace API.
|
|
27
|
+
|
|
28
|
+
## 0.7.2 — 2026-05-18
|
|
29
|
+
|
|
30
|
+
Bug fixes and documentation update.
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
- **`paywall.require_async`**: `AsyncSolvaPay()` instantiated without a caller-supplied `client=` was not closed after the decorated function returned, leaking the underlying `httpx.AsyncClient` connection pool. Wrapped in `try/finally`; `await sv.aclose()` called when the decorator owns the client.
|
|
34
|
+
- **`examples/fastmcp-paywall/pyproject.toml`**: dependency used wrong PyPI dist name (`solvapay`) and a stale `@v0.3.0` pin. Updated to `solvapay-python>=0.7.2`.
|
|
35
|
+
- **`examples/langchain-paywall/pyproject.toml`**: same wrong dist name and stale `@v0.5.0` pin. Updated to `solvapay-python[langchain]>=0.7.2`.
|
|
36
|
+
|
|
37
|
+
### Docs
|
|
38
|
+
- **README** updated to v0.7.1 surface: `paywall_state.gate()`, error hierarchy, idempotency keys, admin ops table, marketplace example, roadmap entries for v0.7.0 and v0.7.1.
|
|
39
|
+
|
|
40
|
+
### Internal
|
|
41
|
+
- `tests/test_lifecycle.py` reformatted (ruff format compliance)
|
|
42
|
+
|
|
43
|
+
## 0.7.1 — 2026-05-17
|
|
44
|
+
|
|
45
|
+
Payments-grade hardening: structured errors, idempotency keys, py.typed, structured logging.
|
|
46
|
+
|
|
47
|
+
### Added
|
|
48
|
+
- **Structured error hierarchy** (`exceptions.py`): `APIError` base with `status_code`, `request_id`, `error_code`, `error_message`. Subclasses: `AuthenticationError` (401), `PermissionError` (403), `NotFoundError` (404), `RateLimitError` (429, adds `.retry_after`), `InvalidRequestError` (4xx), `APIServerError` (5xx), `APIConnectionError`, `APITimeoutError`. `SolvaPayAPIError` aliased to `APIError` for back-compat.
|
|
49
|
+
- **Idempotency keys** on all mutating ops: `create_checkout_session`, `ensure_customer`, `track_usage`, `cancel_purchase`, `reactivate_purchase`, `create_product`, `clone_product`, `create_plan` all accept `idempotency_key: str | None = None`. Header casing: `Idempotency-Key` (matches TS SDK).
|
|
50
|
+
- **`solvapay.idempotency.from_payload(*parts)`** — SHA256 of stable-serialized payload parts → 32-hex-char deterministic key.
|
|
51
|
+
- **PEP 561 `py.typed` marker** — downstream mypy users no longer see `Any` on `solvapay.*` imports.
|
|
52
|
+
- **Structured logging** at `solvapay.http` logger: INFO on success (method, path, status, request_id, duration_ms), WARNING on 4xx/5xx (adds body_excerpt ≤200 chars). Never calls `logging.basicConfig`. Optional `logger=` injection on `SolvaPay`/`AsyncSolvaPay` constructors for `loguru`/`structlog`.
|
|
53
|
+
- **Secret redaction**: `Authorization` header never appears in logs. Verified by `tests/test_redaction.py`.
|
|
54
|
+
- **pyproject classifiers**: `Development Status :: 4 - Beta`, `Framework :: AsyncIO`, `Topic :: Office/Business :: Financial`, `Typing :: Typed`.
|
|
55
|
+
|
|
56
|
+
### Internal
|
|
57
|
+
- User-Agent bumped to `solvapay-python/0.7.1`
|
|
58
|
+
- 142 tests (up from 125), `mypy --strict` clean, `ruff` clean
|
|
59
|
+
|
|
60
|
+
## 0.7.0 — 2026-05-17
|
|
61
|
+
|
|
62
|
+
Real-API alignment after testing against the SolvaPay sandbox revealed wire-format mismatches.
|
|
63
|
+
|
|
64
|
+
### Fixed
|
|
65
|
+
- **`Customer.customer_ref`** now accepts `reference` (real API) in addition to `customerRef` via `validation_alias=AliasChoices(...)`.
|
|
66
|
+
- **`ensure_customer()`** reads `reference` from API response; falls back to `customerRef`. Raises if neither present.
|
|
67
|
+
- **`BalanceResponse`** rewritten: `credits`, `display_currency`, `credits_per_minor_unit`, `display_exchange_rate`; `balance` and `currency` kept as computed properties.
|
|
68
|
+
|
|
69
|
+
### Added
|
|
70
|
+
- **`paywall_state.gate()`** — one-call enrichment helper (limits + checkout URL + plan via `get_customer`).
|
|
71
|
+
- **`paywall.require` / `require_async`**: auto-mints checkout URL when `LimitResponse.checkout_url is None`.
|
|
72
|
+
- **`examples/marketplace/`** — Streamlit demo with 4 paywalled AI agents (Google Gemini) against real SolvaPay sandbox.
|
|
73
|
+
|
|
74
|
+
### Internal
|
|
75
|
+
- User-Agent `solvapay-python/0.7.0`. 125 tests (up from 121). `mypy --strict` clean.
|
|
76
|
+
|
|
77
|
+
## 0.6.0
|
|
78
|
+
- Admin endpoints (products, plans, merchant config). GitHub Actions trusted-publish to PyPI.
|
|
79
|
+
|
|
80
|
+
## 0.5.0
|
|
81
|
+
- `paywall_state` classifier (ACTIVATION_REQUIRED / TOPUP_REQUIRED / UPGRADE_REQUIRED). LangChain `monetize_tool`.
|
|
82
|
+
|
|
83
|
+
## 0.4.0
|
|
84
|
+
- Full async client. 5 lifecycle operations. 13 typed webhook event classes.
|
|
85
|
+
|
|
86
|
+
## 0.3.0
|
|
87
|
+
- FastMCP example: AI agent with two paywalled tools.
|
|
88
|
+
|
|
89
|
+
## 0.2.0
|
|
90
|
+
- `@paywall.require` decorator. FastAPI webhook router.
|
|
91
|
+
|
|
92
|
+
## 0.1.0
|
|
93
|
+
- Sync client, HMAC-SHA256 webhook verification, Pydantic v2 models, CI on 3 Python versions.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
* @dhruv-sanan
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
We pledge to make participation in our community a harassment-free experience for everyone.
|
|
6
|
+
|
|
7
|
+
## Our Standards
|
|
8
|
+
|
|
9
|
+
**Positive behavior:**
|
|
10
|
+
- Using welcoming and inclusive language
|
|
11
|
+
- Being respectful of differing viewpoints
|
|
12
|
+
- Gracefully accepting constructive criticism
|
|
13
|
+
- Focusing on what is best for the community
|
|
14
|
+
|
|
15
|
+
**Unacceptable behavior:**
|
|
16
|
+
- Harassment, trolling, or personal attacks
|
|
17
|
+
- Publishing others' private information without permission
|
|
18
|
+
- Other conduct which could reasonably be considered inappropriate
|
|
19
|
+
|
|
20
|
+
## Enforcement
|
|
21
|
+
|
|
22
|
+
Community leaders may remove, edit, or reject contributions that violate this Code of Conduct.
|
|
23
|
+
Report issues to `dhruv.sanan@greyorange.com`.
|
|
24
|
+
|
|
25
|
+
## Attribution
|
|
26
|
+
|
|
27
|
+
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
## Local development
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
git clone https://github.com/dhruv-sanan/solvapay-python
|
|
7
|
+
cd solvapay-python
|
|
8
|
+
uv sync --all-extras --dev
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Running checks
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
uv run ruff check src tests # lint
|
|
15
|
+
uv run ruff format --check src tests # format gate
|
|
16
|
+
uv run mypy src # type check
|
|
17
|
+
uv run pytest -v # tests
|
|
18
|
+
uv run python tools/api_diff.py # stability manifest gate
|
|
19
|
+
uv run lint-imports --config tools/importlinter.cfg # layer DAG gate
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Layer DAG rules
|
|
23
|
+
|
|
24
|
+
The SDK has a strict layer hierarchy — see [docs/architecture/layers.md](docs/architecture/layers.md).
|
|
25
|
+
|
|
26
|
+
**Hard rules:**
|
|
27
|
+
- `_transport` must not import `client`, `paywall`, `adapters`, or `operations`
|
|
28
|
+
- `operations` must not import `paywall` or `adapters`
|
|
29
|
+
- `client` must not import `adapters` or `experimental`
|
|
30
|
+
|
|
31
|
+
CI fails on violations via `import-linter`.
|
|
32
|
+
|
|
33
|
+
## PR checklist
|
|
34
|
+
|
|
35
|
+
- [ ] Tests added for new behavior
|
|
36
|
+
- [ ] `CHANGELOG.md` updated
|
|
37
|
+
- [ ] `docs/` updated if public API changed
|
|
38
|
+
- [ ] Layer DAG respected (`uv run lint-imports` passes)
|
|
39
|
+
- [ ] Stability manifest updated if new public exports added
|
|
40
|
+
|
|
41
|
+
## Commit style
|
|
42
|
+
|
|
43
|
+
[Conventional Commits](https://www.conventionalcommits.org/):
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
feat: add AsyncPaywall class
|
|
47
|
+
fix(webhooks): set replay_ttl_seconds default correctly
|
|
48
|
+
refactor: extract _transport package
|
|
49
|
+
docs: update README with MCP quickstart
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Adding a new resource namespace
|
|
53
|
+
|
|
54
|
+
1. Add `OpSpec` entries to `src/solvapay/operations/_registry.py`
|
|
55
|
+
2. Create `src/solvapay/operations/<resource>.py` with sync + async methods
|
|
56
|
+
3. Wire namespace attr in `SolvaPay.__init__` and `AsyncSolvaPay.__init__`
|
|
57
|
+
4. Add deprecated flat shim in `client.py` / `_async_client.py`
|
|
58
|
+
5. Tests in `tests/operations/`
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: solvapay-python
|
|
3
|
+
Version: 0.8.0
|
|
4
|
+
Summary: Community Python SDK for SolvaPay (agent-native payment rails)
|
|
5
|
+
Project-URL: Homepage, https://github.com/dhruv-sanan/solvapay-python
|
|
6
|
+
Project-URL: Issues, https://github.com/dhruv-sanan/solvapay-python/issues
|
|
7
|
+
Project-URL: Official TS SDK, https://github.com/solvapay/solvapay-sdk
|
|
8
|
+
Author: Dhruv Sanan
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: agents,fintech,mcp,payments,solvapay
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Framework :: AsyncIO
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
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: Topic :: Office/Business :: Financial
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Requires-Dist: httpx>=0.27
|
|
25
|
+
Requires-Dist: pydantic<2.13,>=2.6
|
|
26
|
+
Provides-Extra: fastapi
|
|
27
|
+
Requires-Dist: fastapi>=0.110; extra == 'fastapi'
|
|
28
|
+
Provides-Extra: langchain
|
|
29
|
+
Requires-Dist: langchain-core<0.4,>=0.3; extra == 'langchain'
|
|
30
|
+
Provides-Extra: mcp
|
|
31
|
+
Requires-Dist: fastmcp<0.5,>=0.4; extra == 'mcp'
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# solvapay-python
|
|
35
|
+
|
|
36
|
+
Community Python SDK for [SolvaPay](https://solvapay.com) — agentic payment rails.
|
|
37
|
+
`pip install solvapay-python` · Python 3.10+ · Fully typed (py.typed) · [PyPI](https://pypi.org/project/solvapay-python/)
|
|
38
|
+
|
|
39
|
+
[](https://github.com/dhruv-sanan/solvapay-python/actions/workflows/ci.yml)
|
|
40
|
+
[](https://pypi.org/project/solvapay-python/)
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## One tool. Three runtimes. One paywall.
|
|
45
|
+
|
|
46
|
+
`@payable_tool` stamps a function with payment metadata once. Any framework reads it — no per-framework wiring.
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
# Define once
|
|
50
|
+
from solvapay.adapters.mcp import payable_tool
|
|
51
|
+
|
|
52
|
+
@payable_tool(product="prd_search")
|
|
53
|
+
def web_search(*, customer_ref: str, query: str) -> list[str]:
|
|
54
|
+
"""Search the web."""
|
|
55
|
+
return do_real_search(query)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
# Run on MCP (Claude Desktop / Claude Code)
|
|
60
|
+
from solvapay.adapters.mcp import register_payable_tool_fastmcp
|
|
61
|
+
from fastmcp import FastMCP
|
|
62
|
+
|
|
63
|
+
mcp = FastMCP("My App")
|
|
64
|
+
register_payable_tool_fastmcp(mcp, web_search)
|
|
65
|
+
mcp.run()
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
# Run on LangChain
|
|
70
|
+
from solvapay.adapters.langchain import monetize_tool
|
|
71
|
+
|
|
72
|
+
paid = monetize_tool(web_search, product="prd_search")
|
|
73
|
+
# Blocked callers get {"paywall_required": True, "checkout_url": "..."}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
# Run raw async
|
|
78
|
+
async with AsyncSolvaPay() as sv:
|
|
79
|
+
limits = await sv.limits.acheck(customer_ref="cus_123", product_ref="prd_search")
|
|
80
|
+
if limits.within_limits:
|
|
81
|
+
result = await web_search(customer_ref="cus_123", query="hello")
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
`pip install 'solvapay-python[mcp]'` · `pip install 'solvapay-python[langchain]'`
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Quickstart
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
pip install solvapay-python
|
|
92
|
+
export SOLVAPAY_SECRET_KEY=sk_...
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
from solvapay import SolvaPay
|
|
97
|
+
|
|
98
|
+
sv = SolvaPay()
|
|
99
|
+
|
|
100
|
+
# Ensure customer exists
|
|
101
|
+
customer_ref = sv.customers.ensure("user_alice")
|
|
102
|
+
|
|
103
|
+
# Create checkout session
|
|
104
|
+
session = sv.checkout.create_session(customer_ref=customer_ref, product_ref="prd_0QKI8NHF")
|
|
105
|
+
print(session.checkout_url)
|
|
106
|
+
|
|
107
|
+
# Check limits and track usage
|
|
108
|
+
limits = sv.limits.check(customer_ref=customer_ref, product_ref="prd_0QKI8NHF")
|
|
109
|
+
if limits.within_limits:
|
|
110
|
+
sv.usage.track(
|
|
111
|
+
customer_ref=customer_ref,
|
|
112
|
+
product_ref="prd_0QKI8NHF",
|
|
113
|
+
meter_name="requests",
|
|
114
|
+
units=1.0,
|
|
115
|
+
idempotency_key="req_abc123", # idempotent — safe to retry
|
|
116
|
+
)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Stable API
|
|
122
|
+
|
|
123
|
+
| Namespace | Sync | Async |
|
|
124
|
+
|-----------|------|-------|
|
|
125
|
+
| `sv.customers` | `ensure`, `get`, `update`, `balance` | `aensure`, `aget`, `aupdate`, `abalance` |
|
|
126
|
+
| `sv.checkout` | `create_session` | `acreate_session` |
|
|
127
|
+
| `sv.limits` | `check` | `acheck` |
|
|
128
|
+
| `sv.purchases` | `cancel`, `reactivate` | `acancel`, `areactivate` |
|
|
129
|
+
| `sv.usage` | `track` | `atrack` |
|
|
130
|
+
| `sv.products` | `list`, `get`, `create`, `delete`, `clone` | `a` prefix on each |
|
|
131
|
+
| `sv.plans` | `list`, `create`, `update`, `delete` | `a` prefix on each |
|
|
132
|
+
| `sv.merchant` | `get`, `get_platform_config` | `aget`, `aget_platform_config` |
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Idempotency
|
|
137
|
+
|
|
138
|
+
All mutating ops accept `idempotency_key`. Use `solvapay.idempotency.from_payload` to derive deterministic keys from request content:
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
from solvapay.idempotency import from_payload
|
|
142
|
+
|
|
143
|
+
key = from_payload("track_usage", customer_ref, product_ref, "requests", units)
|
|
144
|
+
sv.usage.track(..., idempotency_key=key) # retry-safe
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Retried POSTs **must reuse the same key**. Key should change only when the logical request changes.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Errors and retries
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
from solvapay import (
|
|
155
|
+
AuthenticationError, PermissionError, NotFoundError,
|
|
156
|
+
RateLimitError, InvalidRequestError, APIServerError,
|
|
157
|
+
APIConnectionError, APITimeoutError, SolvaPayError,
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
try:
|
|
161
|
+
sv.customers.ensure("cus_123")
|
|
162
|
+
except AuthenticationError:
|
|
163
|
+
... # 401 — bad key
|
|
164
|
+
except RateLimitError as e:
|
|
165
|
+
... # 429 — retry after e.retry_after seconds
|
|
166
|
+
except APIConnectionError:
|
|
167
|
+
... # network failure
|
|
168
|
+
except APITimeoutError:
|
|
169
|
+
... # request timed out (default 30s)
|
|
170
|
+
except SolvaPayError as e:
|
|
171
|
+
... # catch-all
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
No built-in retries by design. Layer `tenacity` manually. `solvapay[retry]` RetryTransport ships in v0.9.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Webhooks
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
import os
|
|
182
|
+
from solvapay.webhooks import WebhookPipeline
|
|
183
|
+
|
|
184
|
+
pipeline = WebhookPipeline(
|
|
185
|
+
[os.environ["SOLVAPAY_WEBHOOK_SECRET"]],
|
|
186
|
+
max_clock_skew_seconds=300,
|
|
187
|
+
replay_ttl_seconds=600,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
envelope = pipeline.process(body=request.body, signature=request.headers["sv-signature"])
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Typed events** — discriminated union over 13 event types:
|
|
194
|
+
|
|
195
|
+
```python
|
|
196
|
+
from solvapay import WebhookEvent, PurchaseCreated, PaymentSucceeded
|
|
197
|
+
from pydantic import TypeAdapter
|
|
198
|
+
|
|
199
|
+
event = TypeAdapter(WebhookEvent).validate_python(envelope.event)
|
|
200
|
+
|
|
201
|
+
match event:
|
|
202
|
+
case PurchaseCreated():
|
|
203
|
+
print(f"New purchase: {event.data['purchaseRef']}")
|
|
204
|
+
case PaymentSucceeded():
|
|
205
|
+
print(f"Payment: {event.data['amount']}")
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Paywall decorator
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
from solvapay.paywall import require, PaywallRequired
|
|
214
|
+
|
|
215
|
+
@require(product="prd_0QKI8NHF", client=sv)
|
|
216
|
+
def run_query(*, customer_ref: str, query: str) -> str:
|
|
217
|
+
return expensive_query(query)
|
|
218
|
+
|
|
219
|
+
try:
|
|
220
|
+
result = run_query(customer_ref="cus_123", query="hello")
|
|
221
|
+
except PaywallRequired as e:
|
|
222
|
+
print(f"Upgrade at: {e.checkout_url}")
|
|
223
|
+
if e.checkout_mint_error:
|
|
224
|
+
print(f"Could not auto-mint checkout URL: {e.checkout_mint_error}")
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Async version: `@require_async`. For MCP/LangChain: `@payable_tool` (see above).
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Async
|
|
232
|
+
|
|
233
|
+
`AsyncSolvaPay` is the supported async pattern. Always use `async with` — it guarantees `aclose()`:
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
from solvapay import AsyncSolvaPay
|
|
237
|
+
|
|
238
|
+
async with AsyncSolvaPay() as sv:
|
|
239
|
+
customer_ref = await sv.customers.aensure("user_alice")
|
|
240
|
+
limits = await sv.limits.acheck(customer_ref=customer_ref, product_ref="prd_0QKI8NHF")
|
|
241
|
+
if limits.within_limits:
|
|
242
|
+
await sv.usage.atrack(
|
|
243
|
+
customer_ref=customer_ref,
|
|
244
|
+
product_ref="prd_0QKI8NHF",
|
|
245
|
+
meter_name="requests",
|
|
246
|
+
units=1.0,
|
|
247
|
+
)
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Migrating from v0.7.x
|
|
253
|
+
|
|
254
|
+
Flat methods still work but emit `DeprecationWarning`. Removed in v2.0.
|
|
255
|
+
|
|
256
|
+
| v0.7.x | v0.8+ |
|
|
257
|
+
|--------|-------|
|
|
258
|
+
| `sv.ensure_customer(ref)` | `sv.customers.ensure(ref)` |
|
|
259
|
+
| `sv.get_customer(ref)` | `sv.customers.get(ref)` |
|
|
260
|
+
| `sv.check_limits(...)` | `sv.limits.check(...)` |
|
|
261
|
+
| `sv.track_usage(...)` | `sv.usage.track(...)` |
|
|
262
|
+
| `sv.create_checkout_session(...)` | `sv.checkout.create_session(...)` |
|
|
263
|
+
| `sv.cancel_purchase(ref)` | `sv.purchases.cancel(ref)` |
|
|
264
|
+
| `sv.reactivate_purchase(ref)` | `sv.purchases.reactivate(ref)` |
|
|
265
|
+
| `sv.get_customer_balance(ref)` | `sv.customers.balance(ref)` |
|
|
266
|
+
| `sv.list_products()` | `sv.products.list()` |
|
|
267
|
+
| `sv.create_plan(prd, ...)` | `sv.plans.create(prd, ...)` |
|
|
268
|
+
| `sv.get_merchant()` | `sv.merchant.get()` |
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## Installation
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
pip install solvapay-python # core
|
|
276
|
+
pip install 'solvapay-python[mcp]' # + FastMCP adapter (FastMCP ≥0.4)
|
|
277
|
+
pip install 'solvapay-python[langchain]' # + LangChain adapter (langchain-core ≥0.3)
|
|
278
|
+
pip install 'solvapay-python[fastapi]' # + FastAPI webhook router
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## Environment variables
|
|
282
|
+
|
|
283
|
+
| Variable | Required | Default |
|
|
284
|
+
|----------|----------|---------|
|
|
285
|
+
| `SOLVAPAY_SECRET_KEY` | Yes | — |
|
|
286
|
+
| `SOLVAPAY_API_BASE_URL` | No | `https://api.solvapay.com` |
|
|
287
|
+
| `SOLVAPAY_WEBHOOK_SECRET` | For webhooks | — |
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## Examples
|
|
292
|
+
|
|
293
|
+
| Path | What |
|
|
294
|
+
|------|------|
|
|
295
|
+
| `examples/multi-framework-paywall/` | One `@payable_tool` → FastMCP + LangChain + raw async |
|
|
296
|
+
| `examples/marketplace/` | Streamlit AI-agent marketplace — real SolvaPay sandbox + Gemini LLM |
|
|
297
|
+
| `examples/fastmcp-paywall/` | FastMCP server gated by `@paywall.require` |
|
|
298
|
+
| `examples/langchain-paywall/` | LangChain agent with `monetize_tool` |
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## Roadmap
|
|
303
|
+
|
|
304
|
+
| Version | Theme |
|
|
305
|
+
|---------|-------|
|
|
306
|
+
| v0.8 ✅ | V1 architecture spine — Transport kernel, OpSpec registry, paywall/webhook packages, `@payable_tool`, stability manifest, layer DAG CI gate |
|
|
307
|
+
| v0.9 | Production polish — API-version pinning, idempotency TTL, `RetryTransport`, `RecordingTransport`, contract tests, lint automation, doc site (MkDocs Material), supply-chain hygiene |
|
|
308
|
+
| v1.0 | Gated on founder signal — OpenAPI-generated models, full secret rotation, production hardening |
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## Status
|
|
313
|
+
|
|
314
|
+
**v0.8.0** — V1 architecture spine + AI-agent moat. `mypy --strict` clean (43 files). 261 tests. 89% line coverage.
|
|
315
|
+
Community SDK, not official. Proposal: [solvapay/solvapay-sdk#187](https://github.com/solvapay/solvapay-sdk/issues/187).
|