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 southbill package 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,
)