Python SDK
Install the official Python SDK with pip and read your first Bases and records from Busabase Cloud or a self-hosted server.
busabase is the official Python client for the Busabase REST API. Use it from scripts, notebooks, data pipelines, and Python backends. One client works against Busabase Cloud and any self-hosted Busabase server, and it uses the same base URL, API key, and workspace settings as the CLI and the TypeScript SDK.
- Package:
busabaseon PyPI - Source and issues: github.com/busabase/busabase-python-sdk (MIT)
- Requires Python 3.11 or later. Sync and async calls are both supported.
Every endpoint has a typed model, generated from the Busabase OpenAPI document. A small hand-written layer on top adds configuration from environment variables, bb.<group>.<operation>(...) calls, and a BusabaseError for every failed request.
Install
pip install busabaseOr use uv add busabase in a uv project.
Quick start
from busabase import Busabase
bb = Busabase(api_key="bb_...") # or set BUSABASE_API_KEY
for base in bb.bases.list():
print(base.slug, base.name)
record = bb.records.get(record_id="rec_...")
print(record.head_commit.payload.to_dict()) # the record's field valuesCreate an API key in API keys (a read key is enough for this example), and replace rec_... with the id of a record you can see. The script prints the slug and name of each Base visible to your key, then that record's field values. It only reads data.
Busabase Cloud or self-hosted
| Busabase Cloud | Self-hosted server | |
|---|---|---|
base_url / BUSABASE_BASE_URL | https://busabase.com (the default) | Your server, e.g. http://localhost:15419 |
api_key / BUSABASE_API_KEY | Required. Create one in API keys | Not needed for a local server |
space / BUSABASE_SPACE_ID | Needed when your key can reach more than one workspace | Usually not needed |
bb = Busabase() # everything from the environment
bb = Busabase(base_url="http://localhost:15419") # a local `busabase server`
bb = Busabase(api_key="bb_...", space="spc_...") # a specific Cloud workspacebase_url works with or without a trailing /api/v1.
The SDK reads environment variables, but does not load ~/.busabase/.env by itself. To reuse the connection you saved with busabase-cli login and busabase-cli space use, export that file before running Python:
set -a; . "$HOME/.busabase/.env"; set +a
python quickstart.pyCloud-only endpoints. The SDK covers the full public API. A few groups exist only on Busabase Cloud and return 404 from a self-hosted server: system (health, meta), users.me, and agent_tasks.
Writing: Change Requests
Every write in Busabase is a Change Request. When your key has write access, it merges in the same call and you get the saved object back. Otherwise it waits in the inbox for a person to review. Check which one you got:
from busabase.generated.models import MaterializedRecord, PendingChangeRequest
result = bb.bases.create_change_request(
base_id="bas_...",
body={"fields": {"company": "Acme", "score": 7}, "message": "Add Acme — inbound lead"},
)
if isinstance(result, MaterializedRecord):
print("merged:", result.id)
elif isinstance(result, PendingChangeRequest):
print("waiting for review:", result.id)Don't pass autoMerge. Let the server decide from your key's permissions.
Calling operations
Operations are grouped the way the API is (bases, records, nodes, docs, file_trees, change_requests, search, grep, …), with snake_case names. dir(bb) and dir(bb.records) list them.
bb.records.list(base_id="bas_...", limit=20)
bb.nodes.get("nod_...") # path parameters can be positional
bb.grep(body={"pattern": "acme", "sources": ["records", "nodes"]})
await bb.records.get.asyncio(record_id="rec_...") # asyncA request body can be a plain dict or the generated model. Request and response shapes are listed in the API reference.
Errors
Any HTTP status of 400 or above raises BusabaseError, carrying the server's error envelope:
from busabase import BusabaseError
try:
bb.records.get(record_id="rec_missing")
except BusabaseError as error:
print(error.status, error.code, error.message) # 404 NOT_FOUND Record not found: rec_missingcode is the server's outcome (NOT_FOUND, FORBIDDEN, BAD_REQUEST, CONFLICT, …). For a validation failure, message names each field and data holds the raw issues.
Keep API keys in your server environment, not in notebooks you share or commit. More options, including async usage, timeouts, and proxies, are in the SDK README.
Other ways to connect: Integration overview · CLI · SDK · Python SDK · MCP · OpenAPI / REST · Agent Skills · Webhooks