Python SDK quickstart
End-to-end: from pip install to a working checkout URL in under 30 lines of code. We'll create a customer, open a checkout session for them, print the hosted URL, and then read the session back.
Prerequisites
- Python 3.9+ in an activated virtualenv.
- A Plugipay test-mode key pair (
pk_test_*+sk_test_*). Mint one in Settings → API keys, or follow Portal → API keys. plugipayinstalled:pip install plugipay(see Installation).
Set the credentials as environment variables — that's the convention every example on these pages assumes:
export PLUGIPAY_KEY_ID=pk_test_xxxxxxxxxxxxxxxx
export PLUGIPAY_KEY_SECRET=sk_test_xxxxxxxxxxxxxxxxxxxxxxxx
The 30-line round-trip
Save as quickstart.py:
import os
from plugipay import PlugipayClient, PlugipayError
def main():
with PlugipayClient(
key_id=os.environ["PLUGIPAY_KEY_ID"],
secret=os.environ["PLUGIPAY_KEY_SECRET"],
) as plug:
# 1. Create (or update) a customer.
customer = plug.customers.create(
email="ada@example.com",
name="Ada Lovelace",
)
print(f"Customer: {customer['id']} ({customer.get('email')})")
# 2. Open a hosted checkout session for them.
session = plug.checkout_sessions.create(
amount=125_000, # IDR 125,000 (minor units = rupiah)
currency="IDR",
methods=["qris", "va", "ewallet"],
success_url="https://yourapp.com/checkout/success",
cancel_url="https://yourapp.com/checkout/cancel",
customer_id=customer["id"],
)
print(f"Checkout URL: {session['hostedUrl']}")
print(f"Session id: {session['id']}")
# 3. Read the session back to verify.
fetched = plug.checkout_sessions.get(session["id"])
print(f"Status: {fetched['status']}")
if __name__ == "__main__":
try:
main()
except PlugipayError as exc:
print(f"Plugipay failed: {exc.status} {exc.code} — {exc.message}")
if exc.request_id:
print(f" request_id: {exc.request_id}")
raise
Run it:
python quickstart.py
Expected output:
Customer: cus_01HXXXXXXXXXXXXXXXXXXXXXXX (ada@example.com)
Checkout URL: https://plugipay.com/c/cs_01HXXXXXXXXXXXXXXXXXXXXXXX
Session id: cs_01HXXXXXXXXXXXXXXXXXXXXXXX
Status: open
Open the checkout URL in a browser to see the hosted page in test mode — pick a payment method, simulate, and the session status will move to succeeded.
What just happened
Step by step:
1. The client
with PlugipayClient(key_id=..., secret=...) as plug:
PlugipayClient is the only top-level object you'll use. The with block ensures the underlying httpx.Client is closed when you're done — if you skip it, call plug.close() yourself before your process exits. For long-lived servers (Flask, FastAPI, Django), construct one PlugipayClient at startup and reuse it everywhere; don't put it in a with block.
The constructor validates that both arguments are non-empty and raises ValueError otherwise. The pk_test_* / sk_test_* prefixes encode the environment — test keys can't touch live data and vice versa.
2. Create the customer
customer = plug.customers.create(
email="ada@example.com",
name="Ada Lovelace",
)
All SDK methods take keyword arguments. Under the hood, the SDK builds a POST /api/v1/customers request with the JSON body Plugipay expects, signs it with HMAC-SHA256, and auto-attaches an Idempotency-Key header (so retrying the same call won't create a duplicate customer).
The return value is a Customer — a thin dict-backed object. Read it like a dict:
customer["id"] # 'cus_01HXX…'
customer["email"] # 'ada@example.com'
customer.get("phone") # None — field absent
customer.raw # full dict, including server fields not promoted to attributes
customer["nonexistent"] raises KeyError; customer.get("nonexistent") returns None. Use whichever fits.
3. Open the checkout session
session = plug.checkout_sessions.create(
amount=125_000,
currency="IDR",
methods=["qris", "va", "ewallet"],
success_url="https://yourapp.com/checkout/success",
cancel_url="https://yourapp.com/checkout/cancel",
customer_id=customer["id"],
)
A few conventions worth noting:
amountis an integer in minor units. For IDR that's rupiah (no decimals); for USD it'd be cents.125_000=Rp 125.000. See Concepts → Amounts for the full list.methodsis a list of payment-method codes — what shows up on the hosted page."qris","va","ewallet","card", etc. See API → Checkout sessions for all options.success_urlandcancel_urlbecome the redirect targets after checkout. They're passed assuccessUrl/cancelUrlon the wire — the SDK does the snake-case ↔ camelCase translation for you.
The returned CheckoutSession carries id, hostedUrl, status, expiry, and the full echoed request. Redirect your buyer to session["hostedUrl"].
4. Read it back
fetched = plug.checkout_sessions.get(session["id"])
print(fetched["status"])
Get methods take the resource id as a positional argument — everything else is keyword-only. status will be open immediately after creation and transitions through succeeded, failed, or cancelled as the buyer interacts with the hosted page.
5. Errors
except PlugipayError as exc:
print(exc.status, exc.code, exc.message, exc.request_id)
Every failure — network timeout, bad credentials, server 5xx, validation error, missing resource — raises PlugipayError or a subclass:
PlugipayNetworkError(DNS/connect/TLS)PlugipayTimeoutError(request exceededtimeout)PlugipaySignatureError(webhook verification only)
Catch the base class to handle everything in one place; catch a subclass if you want to retry transport-level failures differently from API-level ones. See Errors for the full hierarchy and a retry recipe.
Next steps
You now have:
- A customer record (
cus_…) you can charge again later. - A live hosted-checkout URL.
- A pattern (create → act → read back) that works for every other resource: invoices, subscriptions, refunds, payouts, plans.
Try these next:
- Replace
methods=[…]withmethods=["qris"]and watch the hosted page collapse to a single QR. Useful for in-person flows. - Switch to
pk_live_*/sk_live_*keys, pointsuccess_urlat your real domain, and you're in production. - Add the webhook listener so your server learns when the payment succeeds — redirects to
success_urlaren't reliable on mobile.
Next
- Authentication — env vars, platform keys, custom
httpxclients. - Errors — the exception hierarchy, retry patterns.
- Webhooks — verify Plugipay → you deliveries.
- Reference — every method on every namespace.