This release is a pre-release and may not be stable for production use.
solvapay
SolvaPay for Python: paywalls, usage billing, webhooks and paid MCP tools.
pip install solvapay # API client, paywall, webhooks
pip install 'solvapay[mcp]' # paid tools for the official MCP Python SDK
Python 3.10+. Typed (py.typed), async-first, with blocking twins for the API client.
Configure
export SOLVAPAY_SECRET_KEY=sk_sandbox_... # required
export SOLVAPAY_PRODUCT_REF=prd_... # the product paid calls bill against
export SOLVAPAY_API_BASE_URL=... # optional; defaults to https://api.solvapay.com
Run npx solvapay init to sign in and write these to .env.
Make a function paid
from solvapay import PaywallError, create_solvapay
solvapay = create_solvapay()
@solvapay.payable()
async def summarise(text: str, *, customer_ref: str) -> str:
return text[:100]
try:
summary = await summarise("...", customer_ref="user_123")
except PaywallError as error:
print(error.gate["message"]) # what the customer should see, with a checkout link
customer_ref is your own user id: SolvaPay creates the customer on first use.
Each call is checked against the customer's plan, and billed when it succeeds.
Paid MCP tools
from solvapay import create_solvapay
from solvapay.mcp import ResponseContext, create_solvapay_mcp_server
mcp = create_solvapay_mcp_server(
solvapay=create_solvapay(),
public_base_url="https://research.example.com",
)
async def quote(symbol: str, ctx: ResponseContext):
return ctx.respond({"symbol": symbol, "price": 101.5})
mcp.register_payable("quote", handler=quote, description="Latest price for a symbol.")
app = mcp.http_app() # serve with uvicorn; the MCP endpoint is /mcp
Customers sign in with SolvaPay over OAuth, and every bearer token is verified
with SolvaPay. A call over the customer's limit returns the paywall: a message
naming the next step, with a checkout link. See
examples/python-stock-research-mcp.
The server also comes with SolvaPay's built-in tools, as the TypeScript server
does: account shows the customer's plan, balance and usage with a checkout,
top-up or account link (view: checkout, account or topup), and
activate_plan activates a plan by planRef. The /upgrade,
/manage_account, /topup and /activate_plan prompts and the
docs://solvapay/overview.md resource come with them. Pass views=[...] to
choose the views, or views=[] to leave account out.
The checkout widget
On hosts that support MCP Apps (ChatGPT, Claude), account also opens
SolvaPay's checkout and account widget in the chat, the same one the TypeScript
SDK serves. It ships in this package (solvapay/mcp/mcp-app.html) and is
served at ui://<name>/mcp-app.html (resource_uri= to change it). Text-only
hosts get the same text as before; mode: "text" asks for text on any host.
The widget pays, tops up, cancels and reactivates renewals through six tools
only it calls: create_payment_intent, process_payment,
create_hosted_session, set_renewal, attach_business_details and
get_history. They are marked for the app (_meta.ui.visibility: ["app"]), so
MCP Apps hosts keep them from the model. For a host that lists them anyway,
hide_tools_by_audience=["ui"] leaves them out of tools/list; ChatGPT still
gets them, since its widget can only call listed tools.
Its Content Security Policy allows Stripe and the SolvaPay API. Add domains with
csp={"connectDomains": [...], "resourceDomains": [...], "frameDomains": [...]}.
Paid by agents
solvapay.agents.mcp.create_agent_mcp_route serves an MCP server that SolvaPay
agents pay for per call: each paid tool call is authorized with SolvaPay before
it runs and completed at the cost the upstream reports. Install
solvapay[agents,mcp].
Verify webhooks
from solvapay import SolvaPayError, verify_webhook
try:
event = verify_webhook(
body=raw_body, # bytes or str, exactly as received
signature=request.headers["sv-signature"],
secret=os.environ["SOLVAPAY_WEBHOOK_SECRET"],
)
except SolvaPayError as error:
... # error.code: webhook_signature_invalid, webhook_timestamp_out_of_tolerance, ...
The API
Every SolvaPay API operation, generated from the API spec:
from solvapay import AsyncApiClient
async with AsyncApiClient(api_key="sk_sandbox_...") as api:
customer = await api.get_customer(reference="cus_123")
balance = await api.get_customer_balance(reference="cus_123")
ApiClient is the blocking twin. Errors are SolvaPayError with a stable code
and the HTTP status; branch on those, not on the message.
Same behaviour as the TypeScript SDK
The paywall, its messages, the account and activate_plan narration, what
the widget's tools answer and webhook verification are checked against the
TypeScript SDK on every change by a shared conformance suite
(conformance/). The API client is generated from the same
spec as the TypeScript types (openapi/).
Versions
solvapay has its own version line, starting at 0.1.0. Its numbers don't
follow the TypeScript packages: Python 0.3.0 and @solvapay/server 2.12.0 can
behave the same. What the two share is the conformance suite (the version this
package passes is pinned in conformance.lock) and the API
spec.
Until 1.0.0, a minor release (0.x → 0.y) may change the API. Previews of the
next release are published from the dev branch as <next>.devN:
pip install --pre solvapay
Metadata
Release files for solvapay 0.1.0.dev5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| solvapay-0.1.0.dev5.tar.gz | 511.7 kB | With provenance | Details for solvapay-0.1.0.dev5.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| solvapay-0.1.0.dev5-py3-none-any.whl | Python 3 | none | any | Details for solvapay-0.1.0.dev5-py3-none-any.whl |
Total release size: 853.2 kB
Release files / solvapay-0.1.0.dev5.tar.gz
| Download URL | solvapay-0.1.0.dev5.tar.gz |
|---|---|
| Size | 511.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
45e2103ebf39fba20b16110ffcb29f541c6dcd08999fe030f0f13728fcc04c39
|
|
BLAKE2b-256 checksum How to use checksums |
491d95057d4372f00fe25a3f5a12e7ed2c5ccea82374c27785d71d542c1b352a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 14, 2026.
Transparency logRelease files / solvapay-0.1.0.dev5-py3-none-any.whl
| Download URL | solvapay-0.1.0.dev5-py3-none-any.whl |
|---|---|
| Size | 341.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8f29b4771706721a14b507b3bfa1a534d15f1b9942b20f2789606cf7c2435c2d
|
|
BLAKE2b-256 checksum How to use checksums |
7978f7a9771c9a300865b5860ffe9d21ec52559822f6ee5ccc486201fe894c87
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 14, 2026.
Transparency logSecurity for solvapay 0.1.0.dev5
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for solvapay-0.1.0.dev5.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 14, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.