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

# Python SDK

<Card title="GitHub">
  [https://github.com/bronlabs/bron-sdk-python](https://github.com/bronlabs/bron-sdk-python)
</Card>

## Install

Install directly from the GitHub repository:

```bash theme={"system"}
pip install git+https://github.com/bronlabs/bron-sdk-python.git
```

Or pin to a tag in `requirements.txt`:

```
bron-sdk-python @ git+https://github.com/bronlabs/bron-sdk-python.git@v0.2.4
```

## Authenticate

<Note>
  Need a JWK keypair? Install the [Bron CLI](/sdk/cli) and run `bron config init --name default --workspace <workspaceId> --key-file ~/.config/bron/keys/me.jwk --generate-key` — it generates the JWK, stores it at `0600`, prints the public half to paste into the Bron UI, and registers the profile. Same key file works directly with the SDK via `BRON_API_KEY_FILE`.
</Note>

```sh theme={"system"}
export BRON_API_KEY='{"kty":"EC","x":"VqW0Rzw4At***ADF2iFCzxc","y":"9AylQ7HHI0vRT0C***PqWuf2yT8","crv":"P-256","d":"DCQ0jrmYw8***9i64igNKuP0","kid":"cmdos3lj50000sayo6pl45zly"}'
export BRON_WORKSPACE_ID='htotobpkg7xqjfxenjid3n1o'
```

The SDK generates an ES256 JWT per request from your private JWK and sends it in `Authorization: ApiKey <jwt>`. No token caching, no revocation flow.

## Quickstart

All public API methods are async — use `await` (or `asyncio.run(...)`) and close with `await client.aclose()`.

```python theme={"system"}
import asyncio
import os
import uuid

from bron_sdk_python import BronClient
from bron_sdk_python.types.create_transaction import CreateTransaction
from bron_sdk_python.types.transaction_type import TransactionType


async def main() -> None:
    client = BronClient(
        api_key=os.environ["BRON_API_KEY"],
        workspace_id=os.environ["BRON_WORKSPACE_ID"],
    )

    ws = await client.workspaces.get_workspace_by_id()
    print(f"your workspace: {ws}")

    accounts = await client.accounts.get_accounts()
    print("accounts:")
    for a in accounts.get("accounts", []):
        print(f" - {a.get('accountId')} {a.get('accountName')}")
    if not accounts.get("accounts"):
        await client.aclose()
        return

    account_id = accounts["accounts"][0]["accountId"]

    balances = await client.balances.get_balances({"accountIds": [account_id], "limit": 5})
    print("balances (limit 5):")
    for b in balances.get("balances", []):
        print(f" - {b.get('assetId')} {b.get('symbol')} {b.get('totalBalance')}")

    # Create a USDC withdrawal on Ethereum to a saved address-book record.
    tx_body: CreateTransaction = {
        "accountId": account_id,
        "externalId": str(uuid.uuid4()),
        "transactionType": TransactionType.WITHDRAWAL.value,
        "params": {
            "amount": "100",
            "assetId": "5000",
            "networkId": "ETH",
            "toAddressBookRecordId": "<recordId>",
        },
    }
    tx = await client.transactions.create_transaction(tx_body)
    print(f"created tx: {tx.get('transactionId')}")

    await client.aclose()


if __name__ == "__main__":
    asyncio.run(main())
```

## Subscriptions (WebSocket)

Live subscriptions are not yet exposed in the Python SDK; they are available today in the [Golang SDK](/sdk/golang#subscriptions-websocket) and will land here in a subsequent release. The wire protocol is identical (a subscription is "GET extended" — same query, server replays the historical match then streams live updates of the same response shape).

## Errors

Non-2xx responses raise a `BronAPIError` whose attributes mirror the API envelope (`code`, `trace`, `details`):

```python theme={"system"}
from bron_sdk_python import BronAPIError

try:
    await client.accounts.get_accounts()
except BronAPIError as e:
    print(f"api error code={e.code} trace={e.trace}")
```

Branch on `e.code` (stable identifier) — never on the human message. Quote `e.trace` in any user-facing report.

## Configuration

The `BronClient` constructor accepts:

* `api_key` — private JWK as a JSON string (required).
* `workspace_id` — workspace ID (required).
* `base_url` — API base URL (defaults to `https://api.bron.org`).
* `proxy` — `http://[user:pass@]host:port` for outbound requests through a corporate proxy. Standard `HTTPS_PROXY` / `HTTP_PROXY` env vars are honored too.

Methods accept typed query objects or compatible dicts.

## Where to next

<CardGroup cols={2}>
  <Card title="API reference" icon="book-open" href="/api-reference/getting-started">
    Endpoints, request/response shapes, OpenAPI spec.
  </Card>

  <Card title="CLI overview" icon="terminal" href="/sdk/cli">
    `bron` binary — same auth, same data path, no client code.
  </Card>

  <Card title="Errors & exit codes" icon="triangle-exclamation" href="/sdk/cli/errors">
    Error envelope shape, stable codes, retry strategy.
  </Card>

  <Card title="Authentication & profiles" icon="key" href="/sdk/cli/auth">
    Keypair lifecycle, env-var overrides, proxy setup, rotation.
  </Card>
</CardGroup>
