Skip to main content

Community Python SDK for SolvaPay (agent-native payment rails)

Project description

solvapay-python

PyPI

Community Python SDK for SolvaPay — payment rails for the agentic economy.

Status: v0.6, community-maintained. Available on PyPI. Pending official adoption. Mirrors the most-used surface of @solvapay/core.

Python is the dominant language for agent frameworks (LangChain, FastMCP, CrewAI, AutoGen). SolvaPay's official SDK is TypeScript-only. This SDK brings first-class Python support so agent developers can gate tools behind paywalls without switching ecosystems.

New in v0.6: Admin endpoints (products, plans, merchant, platform config). Published to PyPI. v0.5: Paywall state classifier (paywall_state module) and LangChain monetize_tool decorator — gate any LangChain tool behind a SolvaPay paywall with one line. v0.4: Async client (AsyncSolvaPay), lifecycle ops, typed webhook events.

Install

pip install solvapay-python
# with optional extras:
pip install solvapay-python[langchain]
pip install solvapay-python[fastapi]

Quickstart

Sync:

from solvapay import SolvaPay

sv = SolvaPay()  # reads SOLVAPAY_SECRET_KEY from env

customer_ref = sv.ensure_customer("user_42", email="alice@example.com")
limits = sv.check_limits(customer_ref=customer_ref, product_ref="prd_0QKI8NHF")
if not limits.within_limits:
    print("Upgrade needed:", limits.checkout_url)

session = sv.create_checkout_session(
    customer_ref=customer_ref,
    product_ref="prd_0QKI8NHF",
    return_url="https://your-app.com/done",
)
print(session.checkout_url)

Async:

import asyncio
from solvapay import AsyncSolvaPay

async def main() -> None:
    async with AsyncSolvaPay() as sv:
        customer_ref = await sv.ensure_customer("user_42", email="alice@example.com")
        limits = await sv.check_limits(customer_ref=customer_ref, product_ref="prd_0QKI8NHF")
        if not limits.within_limits:
            print("Upgrade needed:", limits.checkout_url)
            return
        session = await sv.create_checkout_session(
            customer_ref=customer_ref,
            product_ref="prd_0QKI8NHF",
        )
        print(session.checkout_url)

asyncio.run(main())

Ecosystem integrations

LangChain

Gate any LangChain tool with monetize_tool:

from solvapay.langchain import monetize_tool
from langchain_core.tools import Tool

raw = Tool.from_function(name="search", func=do_search, description="Search the web.")
paid = monetize_tool(raw, product="prd_0QKI8NHF")

When the customer is over-limit the tool returns a structured dict with checkout_url — the agent surfaces it to the user instead of raising an exception.

pip install solvapay-python[langchain]

See examples/langchain-paywall/ for a full agent example.

FastMCP

See examples/fastmcp-paywall/ for a FastMCP server with two paywalled tools, ready to plug into Claude Desktop.

FastAPI

Use webhook_router to mount a verified webhook endpoint:

from solvapay.fastapi import webhook_router
app.include_router(webhook_router(secret=os.environ["SOLVAPAY_WEBHOOK_SECRET"], on_event=handle))
pip install solvapay-python[fastapi]

Paywall state classifier

solvapay.paywall_state maps a LimitResponse to a structured recovery action:

from solvapay.paywall_state import decide

limits = sv.check_limits(customer_ref="cus_123", product_ref="prd_xyz")
if not limits.within_limits:
    d = decide(limits)
    print(d.state)        # PaywallState.UPGRADE_REQUIRED
    print(d.message)      # "You don't have an active plan..."
    print(d.recovery_tool)  # "upgrade"
    print(d.checkout_url)   # "https://solvapay.com/c/..."

Examples

Path What it shows
examples/fastmcp-paywall/ FastMCP server with two paywalled tools. Demo for @paywall.require + MCP.
examples/langchain-paywall/ LangChain agent with monetize_tool. Shows paywall response in agent trace.

TS ↔ Python parity

// TypeScript (@solvapay/core)
const sv = createSolvaPay();
const session = await sv.createCheckoutSession({
  customerRef: "cus_123",
  productRef: "prd_0QKI8NHF",
});
# Python (solvapay-python)
sv = SolvaPay()
session = sv.create_checkout_session(
    customer_ref="cus_123",
    product_ref="prd_0QKI8NHF",
)

Supported methods

Core:

Python TypeScript equivalent Description
create_checkout_session createCheckoutSession Hosted checkout URL
ensure_customer ensureCustomer Idempotent customer upsert
get_customer getCustomer Fetch customer by ref / email
check_limits checkLimits Usage / purchase limit check
verify_webhook verifyWebhook HMAC-SHA256 signature verification

Lifecycle (new in v0.4):

Python Verb + path Description
track_usage POST /v1/sdk/usages Record metered usage
update_customer PATCH /v1/sdk/customers/{ref} Update customer email / name
get_customer_balance GET /v1/sdk/customers/{ref}/balance Credit balance
cancel_purchase POST /v1/sdk/purchases/{ref}/cancel Cancel a subscription
reactivate_purchase POST /v1/sdk/purchases/{ref}/reactivate Reactivate cancelled purchase

All methods available on both SolvaPay (sync) and AsyncSolvaPay (async).

Webhook handler (FastAPI)

from fastapi import FastAPI, HTTPException, Request
from solvapay import SolvaPayError
from solvapay.webhooks import verify_webhook
import os

app = FastAPI()

@app.post("/webhooks/solvapay")
async def handle_webhook(request: Request) -> dict:
    body = (await request.body()).decode()
    sig = request.headers.get("sv-signature", "")
    try:
        event = verify_webhook(
            body=body,
            signature=sig,
            secret=os.environ["SOLVAPAY_WEBHOOK_SECRET"],
        )
    except SolvaPayError as exc:
        raise HTTPException(401, str(exc))
    # Option A: dict (default)
    if event["type"] == "purchase.created":
        ...  # grant access

    # Option B: typed discriminated union (new in v0.4)
    from solvapay import WebhookEvent, PurchaseCreated
    from pydantic import TypeAdapter
    typed = TypeAdapter(WebhookEvent).validate_python(event)
    if isinstance(typed, PurchaseCreated):
        ...  # typed access to typed.data, typed.id, etc.

    return {"received": True}

Important: use await request.body() (raw bytes), not await request.json(). Re-serialising JSON changes whitespace and breaks the HMAC signature.

Environment variables

Variable Purpose
SOLVAPAY_SECRET_KEY API secret key (required)
SOLVAPAY_API_BASE_URL Override API base URL (optional)
SOLVAPAY_WEBHOOK_SECRET Webhook signing secret (required for verify_webhook)

Non-features

  • No retries — add your own retry logic or use tenacity
  • No pagination — not needed for current endpoints

Roadmap

  • v0.1 — sync client, hosted checkout, customers, limits, webhooks ✅
  • v0.2 — @paywall.require decorator, FastAPI webhook router ✅
  • v0.3 — FastMCP paywall demo (examples/fastmcp-paywall/) ✅
  • v0.4 — async client (AsyncSolvaPay), lifecycle ops, typed webhook events ✅
  • v0.5 — paywall state classifier, LangChain monetize_tool decorator ✅
  • v0.6 — admin endpoints (products, plans, merchant, platform config), PyPI publish ✅

Contributing

git clone https://github.com/dhruv-sanan/solvapay-python
cd solvapay-python
uv sync
uv run pytest

Open a PR — all contributions welcome.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

solvapay_python-0.7.1.tar.gz (236.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

solvapay_python-0.7.1-py3-none-any.whl (25.1 kB view details)

Uploaded Python 3

File details

Details for the file solvapay_python-0.7.1.tar.gz.

File metadata

  • Download URL: solvapay_python-0.7.1.tar.gz
  • Upload date:
  • Size: 236.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for solvapay_python-0.7.1.tar.gz
Algorithm Hash digest
SHA256 7137771f81bb06b20a5375cf323603739671c60494ec820c46b40158a681dc76
MD5 b954794a994f1cdb0ef9556f07e21ff3
BLAKE2b-256 88a13932d87927f096828af64aeea31bd4fd3cc3db77c5c4a4b063b949377a8f

See more details on using hashes here.

Provenance

The following attestation bundles were made for solvapay_python-0.7.1.tar.gz:

Publisher: publish.yml on dhruv-sanan/solvapay-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file solvapay_python-0.7.1-py3-none-any.whl.

File metadata

  • Download URL: solvapay_python-0.7.1-py3-none-any.whl
  • Upload date:
  • Size: 25.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for solvapay_python-0.7.1-py3-none-any.whl
Algorithm Hash digest
SHA256 b9174d36d58d9b3e6e4594fc3443671a3317460dfb59494296d82008dff80499
MD5 f2104a83d0390f139f79f6b953727139
BLAKE2b-256 abbc5c9cf5684b5f96c233e0b005007c24b4afc2ae7143f8a64395ee995085e2

See more details on using hashes here.

Provenance

The following attestation bundles were made for solvapay_python-0.7.1-py3-none-any.whl:

Publisher: publish.yml on dhruv-sanan/solvapay-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page