Type-safe Python client for the FlexPrice API: billing, metering, and subscription management for SaaS and usage-based products.
- Python 3.10+
pip install flexprice
With uv or poetry:
uv add flexprice
# or
poetry add flexpriceRunnable samples are in the examples/ directory.
| Variable | Required | Description |
|---|---|---|
FLEXPRICE_API_KEY |
Yes | API key |
FLEXPRICE_API_HOST |
Optional | Full base URL including https:// and /v1 (default: https://us.api.flexprice.io/v1). No trailing slash. |
Integration tests in api/tests/python/test_sdk.py use a different env shape; see api/tests/README.md.
Initialize the client, create a customer, ingest an event:
import os from flexprice import Flexprice api_key = os.getenv("FLEXPRICE_API_KEY", "YOUR_API_KEY") server_url = os.getenv( "FLEXPRICE_API_HOST", "https://us.api.flexprice.io/v1" ) with Flexprice(server_url=server_url, api_key_auth=api_key) as client: external_id = "customer-123" client.customers.create_customer( external_id=external_id, email="user@example.com", name="Example Customer", ) result = client.events.ingest_event( request={ "event_name": "Sample Event", "external_customer_id": external_id, "properties": {"source": "python_app", "environment": "test"}, "source": "python_app", } ) print(result)
The same client supports async when used as an async context manager:
import asyncio import os from flexprice import Flexprice async def main(): server_url = os.getenv( "FLEXPRICE_API_HOST", "https://us.api.flexprice.io/v1" ) async with Flexprice( server_url=server_url, api_key_auth=os.getenv("FLEXPRICE_API_KEY", "YOUR_API_KEY"), ) as client: result = await client.events.ingest_event_async( request={ "event_name": "Sample Event", "external_customer_id": "customer-123", "properties": {"source": "python_async", "environment": "test"}, "source": "python_async", } ) print(result) asyncio.run(main())
- Pass your API key as
api_key_authwhen creating the client. The SDK sends it in thex-api-keyheader. - Set
FLEXPRICE_API_HOSTto a full URL (see Environment) or use the defaulthttps://us.api.flexprice.io/v1. - Prefer environment variables; get keys from your FlexPrice dashboard or docs.
API errors are raised as exceptions. Catch them and inspect the response as needed:
try: with Flexprice(server_url="...", api_key_auth="...") as flexprice: result = flexprice.events.ingest_event(request={...}) except Exception as e: print(f"Error: {e}") # Inspect status code and body if available on the exception
See the API docs for error formats and status codes.
- Full API coverage (customers, plans, events, invoices, payments, entitlements, etc.)
- Sync and async support
- Type-safe request/response models (Pydantic)
- Built-in retries and error handling
For a full list of operations, see the API reference and the examples in this repo.
- Missing or invalid API key: Ensure
api_key_authis set (or setFLEXPRICE_API_KEYand pass it in). Keys are for server-side use only. - Wrong server URL: Use a full URL such as
https://us.api.flexprice.io/v1(include/v1; no trailing slash). - 4xx/5xx on ingest: Event ingest returns 202 Accepted; for errors, check request fields (
event_name,external_customer_id,properties,source) against the API docs.
Flexprice sends webhook events to your server for async updates on payments, invoices, subscriptions, wallets, and more.
Flow:
- Register your endpoint URL in the Flexprice dashboard
- Receive
POSTwith raw JSON body - Read
event_typeto route - Parse payload into typed model
- Handle business logic idempotently
- Return
200quickly
import json from flexprice.models import ( WebhookDtoPaymentWebhookPayload, WebhookDtoSubscriptionWebhookPayload, WebhookDtoInvoiceWebhookPayload, ) def handle_webhook(raw_body: str) -> None: event = json.loads(raw_body) match event.get("event_type"): case "payment.success" | "payment.failed" | "payment.updated": payload = WebhookDtoPaymentWebhookPayload.model_validate(event) if payload.payment: print(f"payment {payload.payment.id}") # TODO: update payment record case "subscription.activated" | "subscription.cancelled" | "subscription.updated": payload = WebhookDtoSubscriptionWebhookPayload.model_validate(event) if payload.subscription: print(f"subscription {payload.subscription.id}") case "invoice.update.finalized" | "invoice.payment.overdue": payload = WebhookDtoInvoiceWebhookPayload.model_validate(event) if payload.invoice: print(f"invoice {payload.invoice.id}") case _: print(f"unhandled event: {event.get('event_type')}")
| Category | Events |
|---|---|
| Payment | payment.created · payment.updated · payment.success · payment.failed · payment.pending |
| Invoice | invoice.create.drafted · invoice.update · invoice.update.finalized · invoice.update.payment · invoice.update.voided · invoice.payment.overdue · invoice.communication.triggered |
| Subscription | subscription.created · subscription.draft.created · subscription.activated · subscription.updated · subscription.paused · subscription.resumed · subscription.cancelled · subscription.renewal.due |
| Subscription Phase | subscription.phase.created · subscription.phase.updated · subscription.phase.deleted |
| Customer | customer.created · customer.updated · customer.deleted |
| Wallet | wallet.created · wallet.updated · wallet.terminated · wallet.transaction.created · wallet.credit_balance.dropped · wallet.credit_balance.recovered · wallet.ongoing_balance.dropped · wallet.ongoing_balance.recovered |
| Feature / Entitlement | feature.created · feature.updated · feature.deleted · feature.wallet_balance.alert · entitlement.created · entitlement.updated · entitlement.deleted |
| Credit Note | credit_note.created · credit_note.updated |
Production rules:
- Keep handlers idempotent — Flexprice retries on non-
2xx - Return
200for unknown event types — prevents unnecessary retries - Do heavy processing async — respond fast, queue the work
- FlexPrice API documentation
- Python SDK examples in this repo
- SDK integration tests — different
FLEXPRICE_API_HOSTshape for automated tests