Python SDK
The Plugipay Python SDK is the recommended way to call Plugipay from Python — Flask, FastAPI, Django, a scheduled job, a Jupyter notebook, or anything else that runs on Python 3.9+.
pip install plugipay
from plugipay import PlugipayClient
plug = PlugipayClient(key_id="pk_live_...", secret="sk_live_...")
customer = plug.customers.create(email="ada@example.com", name="Ada Lovelace")
That's it. HMAC signing, request envelopes, idempotency keys, timestamp generation, retry-able timeouts, and webhook verification all live inside the SDK so you don't have to think about them.
What it does for you
| Concern | What the SDK handles |
|---|---|
| Authentication | Signs every request with HMAC-SHA256. You only see key_id + secret. |
| Envelope unwrapping | Returns the inner data directly; raises PlugipayError for any error. |
| Idempotency | Auto-generates Idempotency-Key headers for write methods that need them. |
| Pagination | Cursor-based lists return a PageResult with data, cursor, has_more. |
| Errors | One exception hierarchy — PlugipayError and three subclasses. |
| Webhooks | verify_webhook(raw_body, header, secret) returns a parsed WebhookEvent. |
| Platform keys | client.for_merchant(account_id) returns a new client scoped via X-Plugipay-On-Behalf-Of. |
| Connection pooling | Uses one httpx.Client per PlugipayClient; with block closes it. |
You provide a key_id and secret; everything else is automatic.
What it doesn't do
- It doesn't validate request shapes — if you pass an invalid argument, the server returns
400 invalid_requestand the SDK raisesPlugipayError. The same is true of every Plugipay SDK. - It doesn't speak async. The client is synchronous (built on
httpx.Client). If you need to call Plugipay fromasynciocode, run it in a thread pool withasyncio.to_thread(). A first-class async client is on the roadmap; the wire protocol is identical. - It doesn't retry on its own. Network blips raise
PlugipayNetworkError— wrap the call yourself if you want retries. See Errors for a recipe.
Sub-pages
Same shape as the Node SDK:
- Installation — pip, poetry, uv, pipenv. Python version requirements.
- Quickstart — first customer + first checkout session, end-to-end.
- Authentication — constructor options, env vars, platform keys, custom
httpxclients, timeouts. - Errors — the
PlugipayErrorhierarchy, retrying network failures. - Pagination —
PageResult, manual cursor loops, generator helpers. - Webhooks —
verify_webhook, Flask/FastAPI/Django patterns, raw body gotchas. - Reference — every resource namespace and method signature in one place.
Resource namespaces
The client exposes one attribute per resource group, in Python snake_case:
plug.customers # cus_…
plug.plans # pln_…
plug.checkout_sessions # cs_…
plug.invoices # inv_…
plug.subscriptions # sub_…
plug.refunds # ref_…
plug.payouts # po_…
plug.ledger # double-entry rows + balances
plug.reports # pnl, cash_flow
plug.events # event store (search delivery history)
plug.webhook_endpoints # register/delete endpoints
plug.adapters # provider configs (xendit, midtrans, paypal, manual)
plug.api_keys # mint/revoke keys
plug.templates # checkout/invoice/receipt templates
plug.workspaces # multi-workspace support
plug.account # the authenticated merchant profile
plug.portal_sessions # customer self-serve portal links
plug.receipts # receipt summaries
plug.checkout_settings # workspace-level checkout defaults
plug.uploads # upload images (logos, etc.)
plug.onboarding # provision managed adapter accounts
plug.billing # Plugipay's own billing tiers/plans
plug.admin # platform-admin only: provision merchants
plug.admin_portal # internal operator endpoints
Method names also use snake_case: plug.checkout_sessions.create(...), plug.subscriptions.cancel(sub_id), plug.payouts.mark_paid(po_id, reference="…"). The full method list is on the Reference page.
Every list method returns a PageResult[T]. Every other method returns a Resource subclass — a dict-backed object you can index (customer["email"]), .get(), or read .raw from.
Python idioms
The SDK leans into normal Python conventions:
- snake_case everywhere —
checkout_sessions,success_url,customer_id,mark_in_transit. The Node SDK is camelCase; the wire payload is camelCase; the Python SDK translates at the call site so your code stays Pythonic. - Keyword-only arguments — all SDK methods take their parameters as keyword arguments (
plug.customers.create(email=..., name=...)). Positional ids are positional (plug.customers.get("cus_…")). - Context manager —
with PlugipayClient(...) as plug:closes the underlyinghttpx.Clientfor you. Skip it if your process is short-lived; use it in tests and short scripts. - Exceptions, not result objects — failures raise
PlugipayError(or a subclass). No error tuples, noResult[T, E]. - Dict access on resources — the typed classes (
Customer,Invoice, …) wrap a dict. Useobj["field"]orobj.get("field"); or readobj.rawfor the whole payload.
Source & issues
Next
- Installation — install and verify the SDK works.
- Quickstart — round-trip a customer + checkout session in under 30 lines.
- API reference — the underlying HTTP API, if you ever need to drop below the SDK.