Python SDK — getting started
The Python SDK ships in two packages that compose:
| Package | Imports as | Purpose |
|---|---|---|
paylera | paylera.PayleraClient / paylera.AsyncPayleraClient | Typed HTTP client for the public API. |
paylera-fastapi | paylera_fastapi.paylera_relay / paylera_fastapi.paylera_webhooks (plus paylera_django.*) | Framework routers that mount the relay protocol + webhook receiver. |
Most apps want both: the client for server-to-server calls (cron jobs, ingestion workers, webhook reactions); the relay router to keep the API token off the browser.
pip install paylerapip install "paylera-fastapi[django]" # drop [django] if you only need FastAPIPython 3.10 is the floor. The wheels are pure-Python and have no native dependencies.
Construct a client
from paylera import PayleraClient
with PayleraClient(api_token="pl_test_...") as client: result = client.check(customer_id="cus_...", feature_code="api_calls") print(result["allowed"], result["balance"])Base URL is inferred from the token prefix:
pl_test_*→https://api.test.paylera.devpl_live_*→https://api.paylera.dev- anything else → pass
base_url=explicitly
PayleraClient is sync; AsyncPayleraClient is the awaitable twin with an
identical method surface. Choose per the async-vs-sync
guide.
Auth + versioning
client = PayleraClient( api_token="pl_test_...", # sent as `Authorization: Bearer ...` api_version="2026-05-01", # sent as `Paylera-Api-Version`, pin it timeout=30.0, # per-request httpx timeout)The api_version is part of the contract. Pin it; never let it auto-roll.
When you’re ready to upgrade, change the value, run your tests against the
new shape, and ship.
Make a typed call
sub = client.attach( plan_id="plan_pro_monthly", customer_email="ada@example.com", customer_name="Ada Lovelace",)print(sub["redirect_url"])The wrapper ships convenience methods for the relay-protocol operations
(check, track, attach, get_customer, get_entitlements,
list_invoices, cancel_subscription, change_subscription_plan, and the
admin upserts). For anything else, drop to the low-level escape hatch:
result = client.request( "POST", "/v1/customers", json={"email": "ada@example.com", "name": "Ada"},)client.request(...) handles auth, idempotency, retries, OpenTelemetry,
and error mapping for you.
Handle errors
from paylera import ( PayleraError, PayleraIdempotencyConflictError, PayleraRateLimitError,)
try: client.track(customer_id="cus_...", feature_code="api_calls", value=1)except PayleraIdempotencyConflictError as err: # Same key, different body. Inspect err.problem / err.detail. ...except PayleraRateLimitError as err: # Already retried 5x with jittered backoff; we're truly out of budget. ...except PayleraError as err: # Fallback: any other RFC 9457 problem-details response. logger.warning("paylera %s (trace %s): %s", err.problem, err.trace_id, err.detail)The full hierarchy lives in paylera.errors. Subclasses cover 401, 403,
404, 409, 412, 429, and 5xx.
Idempotency
Every state-changing POST carries an Idempotency-Key. The SDK
auto-stamps a UUID v7 unless you pass idempotency_key=:
client.attach(plan_id="plan_pro_monthly", idempotency_key="signup-ada-2026-05-12")A retry of the same request with the same key returns the same cached response.
Mock the wire in tests
import httpx, respxfrom paylera import PayleraClient
@respx.mockdef test_handler(): respx.post("https://api.test.paylera.dev/v1/check").mock( return_value=httpx.Response(200, json={"allowed": True, "balance": 99}), ) with PayleraClient("pl_test_x") as client: assert client.check(customer_id="cus_1", feature_code="f")["allowed"]Or pass transport=httpx.MockTransport(...) straight into the constructor —
the SDK never reads the network when you do.
Going server-side only? You’re done.
If your service only talks to Paylera from the backend (cron jobs, queue
consumers, admin actions), the typed client is all you need. Skip
straight to the fastapi or django guides
when you want a frontend to talk to Paylera through your backend without
ever seeing the API token.
Source
Workspace path: sdks/paylera-sdk-python/. The package is published to
paylera on PyPI.