> ## Documentation Index
> Fetch the complete documentation index at: https://docs.usebila.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Python SDK

> Complete reference for the Bila Python SDK with all available methods and examples

## Overview

The Bila Python SDK provides convenient access to the Bila REST API from any Python 3.9+ application. It includes type definitions for all request params and response fields, and offers both synchronous and asynchronous clients.

<CardGroup cols={2}>
  <Card title="Fully Typed" icon="shield-check">
    Type definitions for every request param and response field.
  </Card>

  <Card title="Sync & Async" icon="code">
    Synchronous and asynchronous clients powered by httpx.
  </Card>

  <Card title="Comprehensive" icon="boxes-stacked">
    Access to all Bila API features: Accounts, Transfers, Collections, and more.
  </Card>

  <Card title="Stainless Generated" icon="bolt">
    Consistently structured and always up-to-date with the latest API changes.
  </Card>
</CardGroup>

## Installation

```bash theme={null}
pip install usebila
```

## Quick Start

```python theme={null}
import os
from usebila import Bila
 
client = Bila(
    api_key=os.environ.get("BILA_API_KEY"),  # This is the default and can be omitted
    environment="sandbox",  # defaults to "production"
)
 
accounts = client.accounts.list()
print(accounts.message)
```

While you can provide an `api_key` keyword argument, it's recommended to use [python-dotenv](https://pypi.org/project/python-dotenv/) to add `BILA_API_KEY="My API Key"` to your `.env` file so your API key isn't stored in source control.

## API Classes

The SDK is organized into resources, each handling a specific domain:

| Resource                                  | Description                                                  |
| ----------------------------------------- | ------------------------------------------------------------ |
| [Accounts](#accounts)                     | Retrieve accounts, list accounts, and check balances         |
| [TransferRecipients](#transferrecipients) | Manage payout recipients for bank and mobile money transfers |
| [Transfers](#transfers)                   | Send payouts via bank transfer and mobile money              |
| [Collections](#collections)               | Collect payments via mobile money                            |
| [Transactions](#transactions)             | Retrieve and list transaction history                        |
| [Webhooks](#webhooks)                     | Configure webhooks and manage delivery history               |
| [Banks](#banks)                           | List supported banks and financial institutions              |
| [Resolve](#resolve)                       | Verify bank account and mobile money details                 |

## Accounts

Manage your Bila wallets and check balances.

Types: `AccountRetrieveResponse`, `AccountListResponse`, `AccountGetBalanceResponse`

### Methods

**`client.accounts.retrieve(id)`**

Retrieve details for a specific account.

```python theme={null}
ACCOUNT_ID = "68f11209-451f-4a15-bfcd-d916eb8b09f4"
 
account = client.accounts.retrieve(ACCOUNT_ID)
print("retrieve:", account)
```

Returns: `AccountRetrieveResponse`

**`client.accounts.list(**params)`**

List all accounts associated with your profile.

```python theme={null}
accounts = client.accounts.list(page=1, per_page=50)
print("list:", accounts)
```

Returns: `AccountListResponse`

**`client.accounts.get_balance(id)`**

Check the real-time balance of an account.

```python theme={null}
balance = client.accounts.get_balance(ACCOUNT_ID)
print("get_balance:", balance)
```

Returns: `AccountGetBalanceResponse`

## TransferRecipients

Manage payout recipients for bank and mobile money transfers.

Types: `TransferRecipientRetrieveResponse`, `TransferRecipientListResponse`, `TransferRecipientCreateBankAccountResponse`, `TransferRecipientCreateMobileMoneyResponse`

### Methods

**`client.transfer_recipients.retrieve(id)`**

Retrieve details for a specific transfer recipient.

```python theme={null}
TRANSFER_RECIPIENT_ID = "68f11209-451f-4a15-bfcd-d916eb8b09f4"
 
recipient = client.transfer_recipients.retrieve(TRANSFER_RECIPIENT_ID)
print("retrieve:", recipient)
```

Returns: `TransferRecipientRetrieveResponse`

**`client.transfer_recipients.list(**params)`**

List all transfer recipients.

```python theme={null}
recipients = client.transfer_recipients.list(page=1, per_page=50)
print("list:", recipients)
```

Returns: `TransferRecipientListResponse`

**`client.transfer_recipients.create_bank_account(**params)`**

Create a new bank account transfer recipient.

```python theme={null}
bank_recipient = client.transfer_recipients.create_bank_account(
    account_number="1234567890",
    bank_id="bank-001",
    country="zm",
    name="John Doe",
)
print("create_bank_account:", bank_recipient)
```

Returns: `TransferRecipientCreateBankAccountResponse`

**`client.transfer_recipients.create_mobile_money(**params)`**

Create a new mobile money transfer recipient.

```python theme={null}
mobile_recipient = client.transfer_recipients.create_mobile_money(
    phone="0977433571",
    operator="airtel",
    country="zm",
    name="Jane Doe",
)
print("create_mobile_money:", mobile_recipient)
```

Returns: `TransferRecipientCreateMobileMoneyResponse`

## Transfers

Send funds to bank accounts or mobile money wallets.

Types: `TransferRetrieveResponse`, `TransferListResponse`, `TransferGetStatusByReferenceResponse`, `TransferInitiateBankTransferResponse`, `TransferInitiateMobileMoneyTransferResponse`

### Methods

**`client.transfers.retrieve(id)`**

Retrieve details for a specific transfer.

```python theme={null}
TRANSFER_ID = "68f11209-451f-4a15-bfcd-d916eb8b09f4"
 
transfer = client.transfers.retrieve(TRANSFER_ID)
print("retrieve:", transfer)
```

Returns: `TransferRetrieveResponse`

**`client.transfers.list(**params)`**

List all transfers.

```python theme={null}
transfers = client.transfers.list(
    account_id="68f11209-451f-4a15-bfcd-d916eb8b09f4",
    start_date="2024-01-01T00:00:00Z",
    end_date="2024-12-31T23:59:59Z",
    page=1,
    per_page=50,
    status="pending",
    type="bank-account",
)
print("list:", transfers)
```

Returns: `TransferListResponse`

**`client.transfers.get_status_by_reference(reference)`**

Get the status of a transfer by its reference.

```python theme={null}
BANK_REFERENCE = "transfer-001"
 
status = client.transfers.get_status_by_reference(BANK_REFERENCE)
print("get_status_by_reference:", status)
```

Returns: `TransferGetStatusByReferenceResponse`

**`client.transfers.initiate_bank_transfer(**params)`**

Initiate a bank transfer.

```python theme={null}
bank_transfer = client.transfers.initiate_bank_transfer(
    account_id="68f11209-451f-4a15-bfcd-d916eb8b09f4",
    amount=1000,
    reference="transfer-001",
    account_number="1234567890",
    bank_id="bank-001",
    country="zm",
    narration="Payment for services",
    recipient_name="Jane Doe",
    transfer_recipient_id="68f11209-451f-4a15-bfcd-d916eb8b09f4",
    wallet_id="68f11209-451f-4a15-bfcd-d916eb8b09f4",
)
print("initiate_bank_transfer:", bank_transfer)
```

Returns: `TransferInitiateBankTransferResponse`

**`client.transfers.initiate_mobile_money_transfer(**params)`**

Initiate a mobile money transfer.

```python theme={null}
mobile_transfer = client.transfers.initiate_mobile_money_transfer(
    amount=250,
    country="zm",
    operator="airtel",
    phone="0977433571",
    reference="mobile-transfer-001",
    narration="Mobile money payout",
    recipient_name="Jane Doe",
    wallet_id="68f11209-451f-4a15-bfcd-d916eb8b09f4",
)
print("initiate_mobile_money_transfer:", mobile_transfer)
```

Returns: `TransferInitiateMobileMoneyTransferResponse`

## Collections

Accept mobile money payments from customers.

Types: `CollectionRetrieveResponse`, `CollectionListResponse`, `CollectionGetStatusByReferenceResponse`, `CollectionInitiateMobileMoneyCollectionResponse`

### Methods

**`client.collections.retrieve(id)`**

Retrieve details for a specific collection.

```python theme={null}
COLLECTION_ID = "68f11209-451f-4a15-bfcd-d916eb8b09f4"
 
collection = client.collections.retrieve(COLLECTION_ID)
print("retrieve:", collection)
```

Returns: `CollectionRetrieveResponse`

**`client.collections.list(**params)`**

List all collections.

```python theme={null}
collections = client.collections.list(
    account_id="68f11209-451f-4a15-bfcd-d916eb8b09f4",
    start_date="2024-01-01T00:00:00Z",
    end_date="2024-12-31T23:59:59Z",
    page=1,
    per_page=50,
    status="pending",
)
print("list:", collections)
```

Returns: `CollectionListResponse`

**`client.collections.get_status_by_reference(reference)`**

Get the status of a collection by its reference.

```python theme={null}
REFERENCE = "collection-001"
 
status = client.collections.get_status_by_reference(REFERENCE)
print("get_status_by_reference:", status)
```

Returns: `CollectionGetStatusByReferenceResponse`

**`client.collections.initiate_mobile_money_collection(**params)`**

Initiate a mobile money collection.

```python theme={null}
initiated = client.collections.initiate_mobile_money_collection(
    amount=100.5,
    country="zm",
    operator="airtel",
    phone="0977433571",
    reference="collection-001",
    wallet_id="68f11209-451f-4a15-bfcd-d916eb8b09f4",
    bearer="customer",
    customer_name="John Doe",
    narration="Payment for subscription",
)
print("initiate_mobile_money_collection:", initiated)
```

Returns: `CollectionInitiateMobileMoneyCollectionResponse`

## Transactions

View and manage transaction history.

Types: `TransactionRetrieveResponse`, `TransactionListResponse`

### Methods

**`client.transactions.retrieve(id)`**

Retrieve details for a specific transaction.

```python theme={null}
TRANSACTION_ID = "68f11209-451f-4a15-bfcd-d916eb8b09f4"
 
transaction = client.transactions.retrieve(TRANSACTION_ID)
print("retrieve:", transaction)
```

Returns: `TransactionRetrieveResponse`

**`client.transactions.list(**params)`**

List all transactions.

```python theme={null}
transactions = client.transactions.list(page=1, per_page=50)
print("list:", transactions)
```

Returns: `TransactionListResponse`

## Webhooks

Configure endpoints to receive real-time event notifications.

Types: `WebhookCreateResponse`, `WebhookUpdateResponse`, `WebhookListResponse`, `WebhookGetDeliveriesResponse`, `WebhookListEventsResponse`, `WebhookRotateSecretResponse`

### Methods

**`client.webhooks.create(**params)`**

Register a new webhook endpoint.

```python theme={null}
webhook = client.webhooks.create(
    events=["payment.completed", "withdrawal.completed", "transfer.completed"],
    url="https://example.com/webhooks",
)
print("create:", webhook)
```

Returns: `WebhookCreateResponse`

**`client.webhooks.update(id, **params)`**

Update an existing webhook.

```python theme={null}
WEBHOOK_ID = "68f11209-451f-4a15-bfcd-d916eb8b09f4"
 
updated_webhook = client.webhooks.update(
    WEBHOOK_ID,
    events=["payment.completed", "collection.completed", "transfer.failed"],
    url="https://example.com/webhooks/v2",
    is_active=True,
)
print("update:", updated_webhook)
```

Returns: `WebhookUpdateResponse`

**`client.webhooks.list()`**

List all registered webhooks.

```python theme={null}
webhooks = client.webhooks.list()
print("list:", webhooks)
```

Returns: `WebhookListResponse`

**`client.webhooks.deactivate(id)`**

Deactivate a webhook.

```python theme={null}
deactivated = client.webhooks.deactivate(WEBHOOK_ID)
print("deactivate:", deactivated)
```

Returns: `BilaResponse`

**`client.webhooks.get_deliveries(id, **params)`**

Get delivery history for a specific webhook.

```python theme={null}
deliveries = client.webhooks.get_deliveries(
    WEBHOOK_ID,
    start_date="2026-04-01T00:00:00.000Z",
    end_date="2026-04-30T23:59:59.999Z",
    event_type="payment.completed",
    page=1,
    per_page=20,
    status="DELIVERED",
)
print("get_deliveries:", deliveries)
```

Returns: `WebhookGetDeliveriesResponse`

**`client.webhooks.list_events()`**

List all supported webhook events.

```python theme={null}
events = client.webhooks.list_events()
print("list_events:", events)
```

Returns: `WebhookListEventsResponse`

**`client.webhooks.rotate_secret(id)`**

Rotate the signing secret for a webhook.

```python theme={null}
rotated = client.webhooks.rotate_secret(WEBHOOK_ID)
print("rotate_secret:", rotated)
```

Returns: `WebhookRotateSecretResponse`

## Banks

Utilities for listing supported financial institutions.

Types: `BankListResponse`

### Methods

**`client.banks.list(**params)`**

List supported banks for a specific country.

```python theme={null}
banks = client.banks.list(country="zm")
print("list:", banks)
```

Returns: `BankListResponse`

## Resolve

Utilities for verifying account details.

Types: `ResolveBankAccountResponse`, `ResolveMobileMoneyResponse`

### Methods

**`client.resolve.bank_account(**params)`**

Verify the owner of a bank account.

```python theme={null}
resolution = client.resolve.bank_account(
    account_number="1234567890",
    bank_id="bank-001",
)
print("bank_account:", resolution)
```

Returns: `ResolveBankAccountResponse`

**`client.resolve.mobile_money(**params)`**

Verify mobile money details.

```python theme={null}
resolution = client.resolve.mobile_money(
    phone="0977433571",
    operator="airtel",
    country="zm",
)
print("mobile_money:", resolution)
```

Returns: `ResolveMobileMoneyResponse`

## Async Usage

Import `AsyncBila` instead of `Bila` and use `await` with each API call. Functionality between the synchronous and asynchronous clients is otherwise identical.

```python theme={null}
import os
import asyncio
from usebila import AsyncBila
 
client = AsyncBila(
    api_key=os.environ.get("BILA_API_KEY"),
    environment="sandbox",
)
 
 
async def main() -> None:
    accounts = await client.accounts.list()
    print(accounts.message)
 
 
asyncio.run(main())
```

## Error Handling

When the library is unable to connect to the API, a subclass of `usebila.APIConnectionError` is raised. When the API returns a non-success status code (4xx or 5xx), a subclass of `usebila.APIStatusError` is raised, containing `status_code` and `response` properties. All errors inherit from `usebila.APIError`.

```python theme={null}
import usebila
from usebila import Bila
 
client = Bila()
 
try:
    client.accounts.list()
except usebila.APIConnectionError as e:
    print("The server could not be reached")
    print(e.__cause__)
except usebila.RateLimitError as e:
    print("A 429 status code was received; we should back off a bit.")
except usebila.APIStatusError as e:
    print("Another non-200-range status code was received")
    print(e.status_code)
    print(e.response)
```

| Status Code | Error Type                 |
| ----------- | -------------------------- |
| 400         | `BadRequestError`          |
| 401         | `AuthenticationError`      |
| 403         | `PermissionDeniedError`    |
| 404         | `NotFoundError`            |
| 422         | `UnprocessableEntityError` |
| 429         | `RateLimitError`           |
| >=500       | `InternalServerError`      |
| N/A         | `APIConnectionError`       |

## Type Definitions

Every API method has typed request params and responses. Types are available from `usebila.types`:

```python theme={null}
from usebila import Bila
from usebila.types import AccountListResponse, CollectionListParams
 
client = Bila(
    api_key="Your API key",
    environment="sandbox",
)
 
# Response type — what the API returns
accounts: AccountListResponse = client.accounts.list()
 
# Request type — what you send to the API
params: CollectionListParams = {
    "account_id": "your-wallet-id",
    "page": 1,
    "per_page": 50,
}
collections = client.collections.list(**params)
```

Type names follow a simple pattern:

| Kind           | Pattern                      | Example                    |
| -------------- | ---------------------------- | -------------------------- |
| Response       | `{Resource}{Action}Response` | `TransferRetrieveResponse` |
| Request params | `{Resource}{Action}Params`   | `WebhookCreateParams`      |

## Best Practices

<Steps>
  <Step title="Use Environment Variables">
    Store API credentials in environment variables, never in source code. Consider using python-dotenv to load `BILA_API_KEY` from a `.env` file.
  </Step>

  <Step title="Implement Webhook Signature Verification">
    Always verify webhook signatures to ensure events are legitimately from Bila and haven't been tampered with.
  </Step>

  <Step title="Handle Errors Gracefully">
    Catch `usebila.APIConnectionError`, `usebila.RateLimitError`, and `usebila.APIStatusError` separately to handle each failure mode appropriately.
  </Step>
</Steps>

## Next Steps

<CardGroup cols={2}>
  <Card title="SDK Quickstart" icon="rocket" href="/docs/sdks/sdk-quickstart">
    Complete integration guide with examples
  </Card>

  <Card title="Transfers" icon="right-left" href="/docs/sdks/python-sdk-reference#transfers">
    Learn about initiating transfers
  </Card>

  <Card title="Webhooks" icon="bell" href="/docs/sdks/python-sdk-reference#webhooks">
    Set up webhook notifications
  </Card>

  <Card title="API Reference" icon="file-lines" href="/docs/api-reference">
    Complete REST API documentation
  </Card>
</CardGroup>
