Python SDK
Official Python client with retries, idempotency and webhook verification
The official Python SDK wraps the same REST API documented here. It has no third-party dependencies (standard library only) and adds retries, idempotency keys, auto-pagination and webhook signature verification.
Status: the
southbillpackage is not on PyPI yet. Until the first release lands you can install it from the repository, or use the plain REST examples in the other articles.
Install
pip install southbill
Requires Python 3.8 or newer.
Create a checkout session
from southbill import Southbill
southbill = Southbill() # reads SOUTHBILL_API_KEY
session = southbill.checkout.sessions.create(
amount=4900,
currency="EUR",
customer_email="ada@acme.com",
success_url="https://acme.com/thanks",
)
print(session["checkout_url"])
All merchant API keys are live keys (sk_live_...). Southbill has no test mode.
is False for them.
Resources
| Namespace | Methods |
|---|---|
checkout.sessions |
create, retrieve, list, expire |
customers |
create, retrieve, update, list, delete |
invoices |
create, retrieve, update, list, send, void, mark_paid |
products |
create, retrieve, update, list |
payments |
retrieve, list |
refunds |
create |
subscriptions |
create, retrieve, list, cancel |
events |
retrieve, list, replay |
Payouts, bank details, KYC and API-key management stay merchant-controlled in the dashboard and are intentionally not part of the API surface.
Idempotency
Every POST sends an Idempotency-Key header (random UUID). Pass your own for
safe retries across processes:
southbill.invoices.create(idempotency_key=f"inv-{order_id}", customer="cus_123")
Pagination
for invoice in southbill.invoices.auto_paging_iter(status="open"):
print(invoice["id"])
Errors and retries
Network errors, 429 and 5xx are retried twice with exponential backoff
(configurable via max_retries). Everything else raises SouthbillError:
from southbill import SouthbillError
try:
southbill.refunds.create(payment="pi_123", amount=500)
except SouthbillError as error:
print(error.status, error.type, error.param, error.request_id)
Webhooks
Verify the raw request body — never a re-serialized object.
import os
from flask import Flask, request
from southbill import construct_event, SouthbillSignatureError
app = Flask(__name__)
@app.post("/webhooks/southbill")
def webhook():
try:
event = construct_event(
payload=request.get_data(),
signature=request.headers.get("Southbill-Signature", ""),
secret=os.environ["SOUTHBILL_WEBHOOK_SECRET"],
)
except SouthbillSignatureError:
return "", 400
if event["type"] == "invoice.paid":
pass # handle it
return "", 200
Signature scheme: Southbill-Signature: t=<unix seconds>,v1=<hex> where the hex
digest is HMAC-SHA256(secret, "<timestamp>.<raw body>"). Default clock tolerance
is 300 seconds.
Configuration
Southbill(
api_key=os.environ["SOUTHBILL_API_KEY"],
base_url="https://api.southbill.com",
timeout=30.0,
max_retries=2,
)