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.
Install
pip install southbill
Package: pypi.org/project/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, list_installments, list_payments |
products |
create, retrieve, update, list |
payments |
retrieve, list |
prices |
via products: list_prices, create_price, set_default_price |
refunds |
create, retrieve, list |
subscriptions |
create, retrieve, update, list, cancel |
subscription_links |
create, retrieve, update, list, archive |
events |
retrieve, list, replay |
webhook_endpoints |
create, retrieve, update, delete, list, rotate_secret, list_deliveries |
balance |
retrieve, transactions.retrieve, transactions.list |
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,
)