Skip to main content

bachs-io — Python SDK for the Bachs API

Production-grade Python SDK for the Bachs payments & billing platform — the payments stack for African internet businesses. Define products, run hosted checkouts, collect payments in customers' local currencies, manage subscriptions and trials, issue refunds, respond to disputes, convert balances, withdraw funds, configure webhooks, and run a Connect-style platform with connected accounts, transfers, and split payments.

Generated from the official Bachs OpenAPI spec (v1.0.0, 96 operations).

Installation

pip install bachs-io

Python 3.9+ required. Depends on httpx and pydantic>=2.

Quickstart

import bachs

client = bachs.BachsClient(api_key="sk_sandbox_...")

# Product-based hosted checkout
session = client.checkouts.create_checkout_session(
    customer={"email": "jane@example.com", "name": "Jane Doe"},
    product_cart=[{"product_id": "prod_abc", "quantity": 1}],
    success_url="https://shop.example.com/success",
)
print(session.checkout_url)

# Retrieve a payment
payment = client.payments.get_payment_detail("pay_123")

client.close()

Authentication & environments

Every request is authenticated with Authorization: Bearer sk_....

  • sk_sandbox_... keys automatically target https://sandbox-api.bachs.io
  • sk_live_... keys automatically target https://api.bachs.io
  • Override with base_url=... (useful for mocking/staging)

You can also set the BACHS_API_KEY environment variable and omit api_key.

The API surface

Methods are grouped into typed resources on the client:

Resource Highlights
client.payments list/retrieve payments, charge status, payment methods & rails, supported currencies
client.checkouts create/retrieve checkout sessions and API checkouts
client.customers create/update/retrieve customers, customer portal sessions
client.products create/update/list products, pricing, archive/unarchive
client.product_groups bundles of products for multi-plan checkout
client.uploads upload/retrieve/delete product media
client.subscriptions list/retrieve/update/cancel subscriptions
client.refunds create/list/retrieve refunds
client.disputes list/get disputes, evidence upload/update/submit
client.accounts organization balances
client.organizations your organization, checkout settings, connected accounts
client.connected_accounts Connect-style account lifecycle, Tasks/checklist, account links, uploads
client.transfers move funds between platform and connected accounts
client.conversions quote and execute currency conversions
client.payouts destinations, quotes, bank lookup, withdrawals
client.webhooks endpoints, secrets, events, metrics, replay

Every method is fully typed — parameters map 1:1 to the API request body/query, and every response is validated into a typed model (see bachs.models, also exported from the package root). Unknown fields in API responses are preserved rather than dropped, so the SDK tolerates additive API changes.

Conventions

  • Money is always a decimal string (e.g. "29.00") at the currency's precision — the SDK never converts between units.
  • Timestamps are ISO 8601 UTC strings.
  • IDs (cust_, prod_, sub_, chk_, evt_, ...) are opaque strings.

Sending null to clear a field

Request models are serialized with None fields omitted. If you need to send an explicit null (e.g. clearing billing_address on update_customer), pass an empty representation for that field after reviewing the API docs for the endpoint's accepted values.

Pagination

List endpoints return a typed response carrying items (or items + a pagination block). Use the limit/offset (or cursor) parameters and read pagination.next_cursor / pagination.has_more to walk pages:

page = client.payments.list_payments(limit=100)
while True:
    for payment in page.items:
        ...
    if not page.pagination.has_more:
        break
    page = client.payments.list_payments(limit=100, offset=page.pagination.offset + page.pagination.returned)

Error handling

Every failure is raised as a subclass of bachs.BachsError:

try:
    client.refunds.create_refund(charge_id="pay_1", reference="ref_1")
except bachs.NotFoundError as exc:
    print(exc.error_code, exc.detail, exc.doc_url)
except bachs.RateLimitError as exc:
    print(exc.retry_after)  # seconds, from Retry-After
except bachs.ApiServerError as exc:
    pass  # safe to retry
Exception HTTP
BadRequestError 400
AuthenticationError 401
ForbiddenError 403
NotFoundError 404
ConflictError 409
UnprocessableEntityError 422
PreconditionRequiredError 428
RateLimitError 429 (has .retry_after)
ApiServerError 5xx
APIConnectionError transport-level (DNS/timeouts)

Errors carry status_code, error_code, detail, doc_url, and errors (field-level validation details on 400).

Idempotency

All mutating requests accept an idempotency_key= argument that is sent as the Idempotency-Key header. Reuse the same key across retries to avoid duplicate creates.

Retries

429 and 5xx responses are retried automatically (up to max_retries=2, with exponential backoff and Retry-After honoured for rate limits). Configure via BachsClient(max_retries=..., retry_on_429=...).

Webhook verification

Webhooks are the source of truth for fulfilment. Verify every delivery with the endpoint's signing secret:

from fastapi import FastAPI, Request, HTTPException

app = FastAPI()

@app.post("/webhooks")
async def receive(request: Request):
    raw = await request.body()
    try:
        event = bachs.construct_event(
            raw,
            request.headers.get("X-Bachs-Signature", ""),
            "whsec_...",
            timestamp_header=request.headers.get("X-Bachs-Timestamp"),
        )
    except bachs.SignatureVerificationError:
        raise HTTPException(400, "Bad signature")
    if event.event_type == "collection.succeeded":
        ...  # fulfil the order
    return {"status": "ok"}

verify_header returns a bool; construct_event parses and validates in one step. generate_signature is provided for testing.

Async

AsyncBachsClient mirrors the sync client:

async with bachs.AsyncBachsClient(api_key="sk_sandbox_...") as client:
    session = await client.checkouts.create_checkout_session(
        customer={"email": "jane@example.com", "name": "Jane Doe"},
        product_cart=[{"product_id": "prod_abc"}],
    )

Connect & acting on behalf of accounts

Endpoints that support X-Connected-Account-ID (checkout settings, transfers) expose a connected_account_id= parameter:

client.organizations.get_checkout_settings(connected_account_id="org_ca")
client.transfers.create_transfer(
    destination="org_ca", amount="7000.00", currency="NGN",
    connected_account_id="org_ca",
)

Uploads

Upload endpoints accept a file path, bytes, a file-like object, or an httpx (filename, content, content_type) tuple:

upload = client.uploads.create_upload(file="./cover.jpg", scope="product-media")
client.products.create_product(name="Pro", price={"currency": "USD", "amount": "29.00"},
                               media=[upload.upload_id])

Development

python -m venv .venv && .venv/bin/pip install -e .
.venv/bin/python -m pytest

The typed models and resource clients are generated from the Bachs OpenAPI spec (docs.bachs.io/docs/openapi/openapi.json) and checked in under bachs/_models.py, bachs/_resources.py, and bachs/_async_resources.py.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bachs_io-0.0.3.tar.gz (59.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

bachs_io-0.0.3-py3-none-any.whl (55.2 kB view details)

Uploaded Python 3

File details

Details for the file bachs_io-0.0.3.tar.gz.

File metadata

  • Download URL: bachs_io-0.0.3.tar.gz
  • Upload date:
  • Size: 59.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.2

File hashes

Hashes for bachs_io-0.0.3.tar.gz
Algorithm Hash digest
SHA256 06ad6e15d487fb069724ffc88da3e78592d5689eeb2e0792fd506d7ae71663c9
MD5 4619d8752b0f331e5a51bec7b7271c78
BLAKE2b-256 a50b8662f5bd2abf68f244a94b8aa8993068813b38473b1cce5e36dae608a7f2

See more details on using hashes here.

File details

Details for the file bachs_io-0.0.3-py3-none-any.whl.

File metadata

  • Download URL: bachs_io-0.0.3-py3-none-any.whl
  • Upload date:
  • Size: 55.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.2

File hashes

Hashes for bachs_io-0.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 779ab814ff8484bd825e4c288a8b15595c54694b89b17e8a97e8b91ad114bed7
MD5 c94c69bc2d8804a3048a3b0ba45d93da
BLAKE2b-256 7358b61b3d14b8e966547d3561d2455074483843f5a6d1fa07aa09861fdfaaa2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page