Skip to content

About

Framework-independent fluent billing for Vatly, the European Merchant of Record for AI, software and digital products

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Vatly Fluent for Python

Alpha — under active development. Every alpha release may include breaking changes. Pin exact versions during alpha.

Integrate billing with Vatly, the European Merchant of Record for AI, software and digital products, without tying your application to a framework or database. Fluent adds chainable checkout/subscription builders, customer and subscription handles, pluggable persistence, and a signed webhook-to-domain-event pipeline on top of vatly-api-python. Your application owns authentication, entitlements, storage, transactions and jobs. Python 3.10+, fully typed, async-first.

Install

pip install vatly-fluent-python==0.1.0a3 vatly-api-python==0.1.0a3

For development, run .agents/setup or uv sync --locked. Both development and package metadata use the exact SDK version from PyPI.

First checkout

from vatly import AsyncVatlyClient, RequestOptions
from vatly_fluent import Vatly, Wiring


async def start_subscription(plan_id: str, purchase_id: str):
    async with AsyncVatlyClient() as api:  # reads VATLY_API_KEY
        vatly = Vatly(
            Wiring(
                api=api,
                redirect_url_success="https://app.example.com/billing/return",
                redirect_url_canceled="https://app.example.com/billing/canceled",
            )
        )
        checkout = await (
            vatly.subscribe()
            .to_plan(plan_id)
            .with_quantity(3)
            .with_trial_days(14)
            .with_metadata({"purchaseId": purchase_id})
            .create(options=RequestOptions(idempotency_key=f"subscribe:{purchase_id}"))
        )
        return checkout.get_url()

This creates a checkout, not a subscription. Confirm payment through signed webhooks, not redirects. No API calls happen until create(). Use a new builder per purchase and persist a stable operation ID before sending. SDK errors pass through unchanged; FluentError means invalid local input or missing wiring.

Connect your own entities and storage

Wire CheckoutRecords, Repository[LocalSubscription], Repository[Stored[Order]], and WebhookCalls to your application's database. For entity-linked checkouts:

from vatly_fluent import EntityRef

# In an authorized handler, with vatly.wiring.checkouts configured:
builder = vatly.subscribe().to_plan(plan_id).for_entity(EntityRef("team", team_id))

Ownership follows your stored checkout → order → subscription links. It never falls back to customerId, which is only billing identity and may be shared or null. Metadata is correlation data, not authorization. A signed webhook authenticates Vatly's snapshot; it does not authorize a browser-provided entity ID.

Linkage follows each order line's relatedResources.subscriptionId, which names the signup's subscription on the initial order, and productType="subscription" renewal lines. subscription_plan product IDs remain plan references. A signed order.paid snapshot can carry a null subscriptionId; reconcile the checkout to read the current order. See Subscriptions. Fluent never guesses a subscription from a customer, plan or quantity.

Learn the integration

Develop

See the development guide for setup and contributor checks.

uv sync --locked
uv run ruff check .
uv run ruff format --check .
uv run mypy
uv run pytest
uv build
uv run twine check dist/*
uv run python scripts/check_package.py

CI runs these checks across Python 3.10–3.14. Release workflows are prepared but require PyPI trusted-publisher configuration and an explicitly published GitHub release. No release is triggered by pushing main.

About

Framework-independent fluent billing for Vatly, the European Merchant of Record for AI, software and digital products

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages