Sdks

Python SDK

Complete guide to using the NovaBilling Python SDK with sync and async support.

Python SDK

The NovaBilling Python SDK provides a fully typed, Pythonic interface to the entire NovaBilling API. It supports both synchronous and asynchronous usage and is compatible with Python 3.8+.

Installation

pip install novabilling

Client Initialization

Synchronous Client

Use NovaBilling for synchronous operations across all resources (customers, plans, subscriptions, invoices, payments, analytics, payment providers, webhooks, auth, and tenant settings).

from novabilling import NovaBilling

client = NovaBilling(
    token="sk_live_a1b2c3d4e5f6g7h8i9j0...",
    # Optional: override the default base URL
    base_url="https://api.novabilling.com"
)

Async Client

Use AsyncNovaBilling for asynchronous operations. See the Async Support section for details.

from novabilling import AsyncNovaBilling

client = AsyncNovaBilling(
    token="sk_live_a1b2c3d4e5f6g7h8i9j0..."
)

Authentication

All API calls require a token parameter passed at client initialization. This token is sent as a Bearer token with every request. There is no automatic environment variable reading -- you must always provide the token explicitly.

import os
from novabilling import NovaBilling

client = NovaBilling(
    token=os.environ["NOVABILLING_TOKEN"]
)

Customers

Customers represent the people or businesses you bill. Every subscription, invoice, and payment is linked to a customer. Each customer has a unique email within your tenant and can have metadata for storing your application-specific data.

Create a Customer

customer = client.customers.create(
    external_id="usr_12345",
    email="john@example.com",
    currency="NGN",
    name="John Doe",
    metadata={
        "plan": "enterprise",
        "source": "website"
    }
)

print(f"Created customer: {customer.data.id}")

Get a Customer

customer = client.customers.get("cus_x1y2z3a4b5c6")

print(f"Name: {customer.data.name}")
print(f"Email: {customer.data.email}")

Update a Customer

updated = client.customers.update(
    "cus_x1y2z3a4b5c6",
    name="John A. Doe",
    metadata={
        "plan": "enterprise",
        "notes": "VIP customer"
    }
)

List Customers

customers = client.customers.list(
    page=1,
    limit=20,
    search="john",
    sort_by="created_at",
    sort_order="desc"
)

print(f"Total customers: {customers.meta.total}")
for customer in customers.data:
    print(f"{customer.name} ({customer.email})")

Delete a Customer

client.customers.delete("cus_x1y2z3a4b5c6")
print("Customer deleted")

Get Customer Subscriptions

subscriptions = client.customers.get_subscriptions("cus_x1y2z3a4b5c6")

for sub in subscriptions.data:
    print(f"{sub.id}: {sub.status} - Plan: {sub.plan_id}")

Get Customer Invoices

invoices = client.customers.get_invoices("cus_x1y2z3a4b5c6")

for invoice in invoices.data:
    print(f"{invoice.id}: {invoice.status} - {invoice.currency} {invoice.amount}")

Plans

Plans define what you sell -- the product tiers, billing frequency, and included features. Each plan has a unique code and can have prices in multiple currencies. Plans can be deactivated to prevent new subscriptions without affecting existing ones.

Create a Plan

plan = client.plans.create(
    name="Pro Plan",
    code="pro_monthly",
    billing_interval="monthly",
    description="Professional plan with advanced features",
    features=[
        "Unlimited projects",
        "Priority support",
        "Advanced analytics",
        "API access",
        "Custom integrations"
    ]
)

print(f"Created plan: {plan.data.id}")

List Plans

plans = client.plans.list(
    active=True
)

for plan in plans.data:
    print(f"{plan.name} ({plan.code}): {plan.billing_interval}")

Update a Plan

updated = client.plans.update(
    "pln_d7e8f9g0h1i2",
    name="Pro Plan v2",
    features=[
        "Unlimited projects",
        "Priority support",
        "Advanced analytics",
        "API access",
        "Custom integrations",
        "Dedicated account manager"
    ]
)

Deactivate a Plan

deactivated = client.plans.update(
    "pln_d7e8f9g0h1i2",
    active=False
)

Subscriptions

Subscriptions connect customers to plans and manage the recurring billing lifecycle. A subscription tracks the current billing period, status (active, paused, canceled), and handles automatic renewals. You can pause, resume, cancel, or change the plan of any active subscription.

Create a Subscription

subscription = client.subscriptions.create(
    customer_id="cus_x1y2z3a4b5c6",
    plan_id="pln_d7e8f9g0h1i2",
    currency="NGN",
    metadata={
        "source": "website",
        "campaign": "launch_promo"
    }
)

print(f"Subscription status: {subscription.data.status}")
print(f"Current period ends: {subscription.data.current_period_end}")

Cancel a Subscription

canceled = client.subscriptions.cancel(
    "sub_j3k4l5m6n7o8",
    cancel_at_period_end=True  # Continue access until period ends
)
print(f"Subscription will cancel at: {canceled.data.current_period_end}")

Pause a Subscription

paused = client.subscriptions.pause("sub_j3k4l5m6n7o8")
print("Subscription paused")

Resume a Subscription

resumed = client.subscriptions.resume("sub_j3k4l5m6n7o8")
print("Subscription resumed")

Change Plan

updated = client.subscriptions.change_plan(
    "sub_j3k4l5m6n7o8",
    plan_id="pln_newplan123"
)
print(f"Plan changed. New period end: {updated.data.current_period_end}")

List Subscriptions

subscriptions = client.subscriptions.list(
    customer_id="cus_x1y2z3a4b5c6",
    status="active",
    page=1,
    limit=20
)

for sub in subscriptions.data:
    print(f"{sub.id}: {sub.status} - Plan: {sub.plan_id}")

Invoices

Invoices are billing documents that track amounts owed by customers. They can be created automatically from subscriptions or manually for one-off charges. Invoices go through a lifecycle: draft, finalized, paid, or voided. You can also generate PDF versions for download.

Create an Invoice

from novabilling.types import InvoiceItemDto

invoice = client.invoices.create(
    customer_id="cus_x1y2z3a4b5c6",
    items=[
        InvoiceItemDto(
            description="Pro Plan - Monthly",
            amount=15000,
            quantity=1
        ),
        InvoiceItemDto(
            description="Additional API calls (500)",
            amount=2500,
            quantity=1
        )
    ],
    due_date="2025-02-28T00:00:00Z",
    notes="Thank you for your business!"
)

print(f"Invoice ID: {invoice.data.id}")
print(f"Total: {invoice.data.currency} {invoice.data.total}")

List Invoices

invoices = client.invoices.list(
    customer_id="cus_x1y2z3a4b5c6",
    status="finalized",
    page=1,
    limit=10
)

for invoice in invoices.data:
    print(f"{invoice.id}: {invoice.status} - {invoice.currency} {invoice.total}")

Finalize an Invoice

finalized = client.invoices.finalize("inv_p1q2r3s4t5u6")
print(f"Invoice finalized. PDF URL: {finalized.data.pdf_url}")

Void an Invoice

voided = client.invoices.void("inv_p1q2r3s4t5u6")
print(f"Invoice voided: {voided.data.status}")

Mark an Invoice as Paid

paid = client.invoices.mark_paid("inv_p1q2r3s4t5u6")
print(f"Invoice marked paid: {paid.data.status}")

Get Invoice PDF

pdf = client.invoices.get_pdf("inv_p1q2r3s4t5u6")
print(f"PDF URL: {pdf.data.url}")

Payments

Payments are read-only records created automatically when invoices are paid through a payment provider. You can list, retrieve, and refund payments.

List Payments

payments = client.payments.list(
    customer_id="cus_x1y2z3a4b5c6",
    status="successful",
    page=1,
    limit=20
)

total = 0
for payment in payments.data:
    total += payment.amount
    print(f"{payment.id}: {payment.currency} {payment.amount} - {payment.status}")

print(f"Total paid: {total}")

Get a Payment

payment = client.payments.get("pay_v1w2x3y4z5a6")

print(f"Payment ID: {payment.data.id}")
print(f"Status: {payment.data.status}")
print(f"Amount: {payment.data.currency} {payment.data.amount}")

Refund a Payment

refund = client.payments.refund(
    "pay_v1w2x3y4z5a6",
    amount=15000,  # Partial refund
    reason="Customer requested plan downgrade"
)

print(f"Refund ID: {refund.data.id}")
print(f"Refund status: {refund.data.status}")

Payment Providers

Payment providers are the external services that process payments on your behalf. NovaBilling supports Stripe, Flutterwave, Paystack, and M-Pesa. Configure one or more providers and set priorities to control the fallback order when a provider is unavailable.

List Payment Providers

providers = client.payment_providers.list()

for provider in providers.data:
    print(f"{provider.name}: {provider.type} - {'Active' if provider.active else 'Inactive'}")

Configure a Payment Provider

provider = client.payment_providers.create(
    type="stripe",
    name="Stripe Production",
    credentials={
        "secret_key": "sk_live_...",
        "publishable_key": "pk_live_..."
    }
)

print(f"Provider configured: {provider.data.id}")

Webhooks

Webhooks let you receive real-time HTTP notifications when events happen in your NovaBilling account, such as successful payments, subscription cancellations, or failed charges. Register an endpoint URL and choose which events to subscribe to.

List Webhooks

webhooks = client.webhooks.list()

for webhook in webhooks.data:
    print(f"{webhook.url}: {webhook.status}")

Create a Webhook

webhook = client.webhooks.create(
    url="https://yourapp.com/webhooks/novabilling",
    events=["invoice.finalized", "payment.successful", "subscription.canceled"]
)

print(f"Webhook ID: {webhook.data.id}")
print(f"Secret: {webhook.data.secret}")

Error Handling

The SDK raises typed exceptions for different error scenarios.

from novabilling import NovaBilling
from novabilling import (
    BadRequestError,
    NotFoundError,
    UnauthorizedError,
    ConflictError
)

client = NovaBilling(token="sk_live_...")

try:
    customer = client.customers.get("cus_nonexistent")
except NotFoundError as e:
    print(f"Customer not found: {e.message}")
except BadRequestError as e:
    print(f"Bad request: {e.message}")
except UnauthorizedError as e:
    print(f"Authentication failed: {e.message}")
except ConflictError as e:
    print(f"Conflict: {e.message}")
except Exception as e:
    print(f"Unexpected error: {e}")

Error Types

Exception ClassHTTP StatusDescription
BadRequestError400Request body or parameters are invalid
UnauthorizedError401Missing or invalid authentication credentials
NotFoundError404The requested resource does not exist
ConflictError409Resource state conflict (e.g., duplicate email)

Async Support

The SDK provides a fully asynchronous client for use with asyncio.

import asyncio
from novabilling import AsyncNovaBilling

async def main():
    client = AsyncNovaBilling(
        token="sk_live_a1b2c3d4e5f6g7h8i9j0..."
    )

    # All methods are async
    customer = await client.customers.create(
        external_id="usr_12345",
        email="john@example.com",
        currency="NGN",
        name="John Doe"
    )
    print(f"Created customer: {customer.data.id}")

    # Concurrent requests
    customer_task = client.customers.get("cus_x1y2z3a4b5c6")
    plans_task = client.plans.list(active=True)

    customer, plans = await asyncio.gather(customer_task, plans_task)
    print(f"Customer: {customer.data.name}")
    print(f"Active plans: {plans.meta.total}")

asyncio.run(main())

Pagination

Manual Pagination

page = 1
has_more = True

while has_more:
    response = client.customers.list(page=page, limit=100)

    for customer in response.data:
        print(customer.name)

    has_more = page * 100 < response.meta.total
    page += 1

Type Hints

The SDK includes comprehensive type hints for all models and methods. This enables IDE autocompletion, static type checking with mypy, and documentation tooltips.

from novabilling.types import (
    Customer,
    Plan,
    Subscription,
    Invoice,
    InvoiceItemDto,
    Payment,
    PaginatedResponse,
    Currency,
    BillingInterval,
    SubscriptionStatus,
    InvoiceStatus,
    PaymentStatus
)
from typing import List

def process_customers(customers: List[Customer]) -> None:
    for customer in customers:
        print(f"Processing {customer.name} ({customer.id})")

# Type-safe literals
currency: Currency = "NGN"
interval: BillingInterval = "monthly"

Configuration Options

client = NovaBilling(
    # Required
    token="sk_live_...",

    # Optional
    base_url="https://api.novabilling.com",  # Custom base URL
    timeout=60.0,                             # Request timeout in seconds (default: 60)
    follow_redirects=True,                    # Follow HTTP redirects (default: True)
)

Next Steps

Copyright © 2026