Barbara API SDK for Python
Official Python SDK for the Barbara Edge AI platform API.
Typed, synchronous and asynchronous clients for managing nodes, clusters, applications, models, and related resources.
Overview
The Barbara API covers the full platform: nodes, clusters, applications, models, and everything needed to configure them, over plain HTTP. This SDK wraps it in a typed client, so you get autocomplete, structured response objects, and automatic token refresh instead of raw requests calls and hand-rolled JSON payloads. A synchronous client and an asyncio-native client expose the same methods, so you can start with BarbaraClient and move to AsyncBarbaraClient later without relearning the API.
Contents: Requirements · Installation · Authentication · Quick start · Usage · Error handling · Architecture · API reference · Examples · Roadmap · Contributing · License
Requirements
- Python 3.9 or later
Installation
pip install barbara-api-sdk
Authentication
The SDK authenticates against the Barbara API using OAuth2 password grant. You need four credentials, referred to as Barbara API Credentials:
| Credential | Description |
|---|---|
BBR_API_USERNAME |
Your Barbara Panel username |
BBR_API_PASSWORD |
Your Barbara Panel password |
BBR_API_CLIENT_ID |
OAuth2 client ID, provided by Barbara |
BBR_API_CLIENT_SECRET |
OAuth2 client secret, provided by Barbara |
By default, the client reads credentials from environment variables:
export BBR_API_USERNAME="..."
export BBR_API_PASSWORD="..."
export BBR_API_CLIENT_ID="..."
export BBR_API_CLIENT_SECRET="..."
from barbara import BarbaraClient
client = BarbaraClient.from_env()
Additional optional environment variables:
| Variable | Description | Default |
|---|---|---|
BBR_API_URL |
Barbara API base URL | https://prod.bap.barbara.tech |
BBR_AUTH_URL |
Barbara auth server base URL | https://prod.auth.barbara.tech/auth |
BBR_REALM |
Authentication realm | bbr_prod |
Credentials can also be supplied explicitly instead of through environment variables:
from barbara import BarbaraClient, BarbaraConfig
config = BarbaraConfig(
client_id="...",
client_secret="...",
username="...",
password="...",
)
client = BarbaraClient(config)
Quick start
from barbara import BarbaraClient
with BarbaraClient.from_env() as client:
for node in client.nodes.list():
print(node.node_name, node.status)
node = client.nodes.resolve("my-node-01")
Async usage
AsyncBarbaraClient mirrors BarbaraClient method for method: only await differs.
import asyncio
from barbara import AsyncBarbaraClient
async def main():
async with AsyncBarbaraClient.from_env() as client:
nodes = await client.nodes.list()
asyncio.run(main())
Usage
Nodes
See Node management in Academy.
nodes = client.nodes.list(search="sensor")
node = client.nodes.get("<node-id>")
node = client.nodes.resolve("my-node-01") # look up by node name
nodes = client.nodes.list_by_tags(["production", "line-3"]) # any of the given tags
client.nodes.reboot("<node-id>")
client.nodes.poweroff("<node-id>")
Node global secrets
Barbara-managed secrets shared by every workload on the node — distinct from a Marketplace app's own App Secrets and from Docker-native Swarm Secrets. See Secrets in Academy.
client.nodes.create_global_secrets("<node-id>", {"wifi-psk": "s3cr3t"})
secrets = client.nodes.list_global_secrets("<node-id>")
client.nodes.delete_global_secret("<node-id>", "<secret-id>")
Node global configuration
Corresponds to the Panel's Global Config (node-scoped; see Application configuration types for the full picture — a workload's own App Config is set through client.nodes.workloads, below).
client.nodes.set_global_config("<node-id>", config={"threshold": 5})
config = client.nodes.get_global_config("<node-id>")
Docker credentials
client.nodes.create_docker_credentials(
"<node-id>", [{"user": "bob", "password": "s3cr3t", "server": "docker.io"}]
)
creds = client.nodes.list_docker_credentials("<node-id>")
print(creds[0].server, creds[0].user) # password is never returned by the API
Node identity: name, tags, location, safety actions
See General info in Academy.
client.nodes.update_name("<node-id>", "floor-2-sensor-01")
client.nodes.add_tag("<node-id>", "production")
client.nodes.set_location("<node-id>", lat=40.4168, lng=-3.7038, city="Madrid")
location = client.nodes.get_location("<node-id>")
client.nodes.update_safety_actions(
"<node-id>", trigger_threshold=90, stop_apps=True, prune_volumes=True
)
Barbara Core updates
Barbara Core is the single versioned package that bundles a node's OS and Node Manager together (e.g. Barbara Core 1.10.1.471) — Panel's own update modal shows one version number, not two separate firmwares. See Barbara Core updates in Academy.
client.nodes.update_barbara_core("<node-id>", "update")
client.nodes.update_barbara_core(
"<node-id>", "schedule", schedule_timestamp="2026-01-01T03:00:00Z"
)
client.nodes.cancel_barbara_core_update("<node-id>")
Docker maintenance and volumes
client.nodes.prune_docker("<node-id>", "prunevolumes")
client.nodes.prune_docker_all("<node-id>")
client.nodes.restart_docker_daemon("<node-id>")
client.nodes.create_docker_volume("<node-id>", "shared-cache")
volumes = client.nodes.list_docker_volumes("<node-id>")
client.nodes.delete_docker_volume("<node-id>", volumes[0]["_id"])
See Volumes in Academy.
Telemetry
See Telemetry in Academy.
latency = client.nodes.get_telemetry_latency("<node-id>")
client.nodes.set_telemetry_latency("<node-id>", 30)
telemetry = client.nodes.get_last_telemetry("<node-id>")
print(telemetry["disk"], telemetry["alive"])
Node workloads
Deploy and manage applications running on a node: Docker apps (bring-your-own image), Marketplace apps, and Model deployments. See Docker apps and Marketplace apps in Academy.
client.nodes.workloads.create_docker_workload(
"<node-id>",
app_version_id="<app-version-id>",
application_id="<application-id>",
)
client.nodes.workloads.create_marketplace_workload(
"<node-id>",
app_version_id="<app-version-id>",
application_id="<application-id>",
name="my-workload",
compose_config=[{"name": "modelservice", "ports": {"PORT_NUMBER": "9083"}}],
)
client.nodes.workloads.start("<node-id>", "<workload-id>")
client.nodes.workloads.stop("<node-id>", "<workload-id>")
logs = client.nodes.workloads.get_logs("<node-id>", "<workload-id>")
A workload's own App Config (as opposed to the node-scoped Global Config above):
client.nodes.workloads.set_app_config("<node-id>", "<workload-id>", config={"threshold": 5})
config = client.nodes.workloads.get_app_config("<node-id>", "<workload-id>")
Model workloads
Same body shape as marketplace workloads, deploying a model application version instead. compose_config must exactly match the service template declared by that model version. See Models in Academy.
client.nodes.workloads.create_model_workload(
"<node-id>",
app_version_id="<model-app-version-id>",
application_id="<model-application-id>",
name="my-model-workload",
compose_config=[{"name": "modelservice", "ports": {"PORT_NUMBER": "8501"}}],
)
Node network
The Networking card on the Node Details page in Panel: physical interfaces (Ethernet, WiFi, Mobile), VLANs, hostname, and the Advanced section (VPN, Proxy, Standalone Mode, IPTables). See Network Card overview in Academy.
network = client.nodes.network.get("<node-id>")
client.nodes.network.update_ethernet_interface("<node-id>", "eno1", dhcp=True)
client.nodes.network.enable_proxy("<node-id>", url="http://proxy.example.com:8080")
client.nodes.network.enable_vpn("<node-id>")
client.nodes.network.start_vpn("<node-id>")
hostname = client.nodes.network.get_hostname("<node-id>")
client.nodes.network.set_hostname("<node-id>", "floor-2-sensor-01")
iptables = client.nodes.network.get_iptables("<node-id>") # {"iptables_conf": ..., "iptables_id": ...}
client.nodes.network.update_iptables("<node-id>", iptables_conf="-A INPUT -j ACCEPT")
client.nodes.network.create_vlan_interface(
"<node-id>",
"eno1", # parent physical interface
vlan_id=100,
name="vlan100", # the new VLAN's own name
dhcp=True, ip="", dns="", gateway="", metric=10,
auto_dns=True, ip_aliases=[], dns_aliases=[],
)
client.nodes.network.vlan_interface_exists("<node-id>", "vlan100")
client.nodes.network.delete_vlan_interface("<node-id>", "vlan100")
Every write in this resource does a best-effort, non-blocking check of the caller's token role before sending the request, and emits a UserWarning if it looks insufficient — the API's own response is always the final authority.
Clusters
See Clusters in Academy.
clusters = client.clusters.list()
cluster = client.clusters.get("<cluster-id>")
cluster = client.clusters.resolve("floor-2-cluster") # look up by cluster name
client.clusters.update("<cluster-id>", "new-name")
client.clusters.create_global_secrets("<cluster-id>", {"db-password": "s3cr3t"})
client.clusters.set_global_config("<cluster-id>", config={"threshold": 5})
Creating a cluster and managing membership
client.clusters.create(
"floor-2-cluster",
primary_node={
"nodeId": "<node-id>",
"labels": "eyJ6b25lIjogImZsb29yLTIifQ==", # base64 JSON: {"zone": "floor-2"}
"restrictSwarmTrafficToInterface": False,
"advertiseAddr": "10.0.0.5",
},
enable_cluster_volumes=True,
)
client.clusters.join_node(
"<cluster-id>",
"<node-id>",
labels={"zone": "floor-2"},
restrict_swarm_traffic_to_interface=False,
advertise_addr="10.0.0.6",
)
client.clusters.pause_node("<cluster-id>", "<node-id>")
client.clusters.drain_node("<cluster-id>", "<node-id>")
client.clusters.set_node_active("<cluster-id>", "<node-id>")
client.clusters.leave_node("<cluster-id>", "<node-id>")
Cluster-wide Docker volumes
Unlike node-level Docker volumes, these give a cluster's workloads Swarm-managed high availability — a workload that needs a volume to survive a node failing over must use one of these.
client.clusters.create_swarm_volume("<cluster-id>", "shared-cache")
client.clusters.delete_swarm_volume("<cluster-id>", "<volume-id>")
Docker-native objects declared in an app's own docker-compose.yml (Swarm Config/Swarm Secrets, distinct from the Barbara-managed Global Config/Global Secrets above) are cleaned up the same way: delete_all_swarm_configs, delete_swarm_config, delete_all_swarm_secrets, delete_swarm_secret.
Cluster workloads
The cluster-level equivalent of node workloads: deploy an application across every node in a cluster. Barbara's product docs only ever call this "Workload" — there's no separate "stack" concept in Panel, at either scope. See Add applications in Academy.
client.clusters.workloads.create_docker_workload(
"<cluster-id>",
app_version_id="<app-version-id>",
application_id="<application-id>",
)
client.clusters.workloads.delete("<cluster-id>", "<workload-id>")
Model workloads work the same way, using create_model_workload:
client.clusters.workloads.create_model_workload(
"<cluster-id>",
app_version_id="<model-app-version-id>",
application_id="<model-application-id>",
name="my-model-workload",
compose_config=[{"name": "modelservice", "ports": {"PORT_NUMBER": "8501"}}],
)
Applications
See App Library in Academy.
apps = client.applications.list()
client.applications.create(
"edge-app", "Long description", "Barbara", docker=True, icon_path="./icon.png"
)
client.applications.create_version(
"<application-id>", "./app-v1.tar", "1.0.0", ["amd64"], ["Initial release"]
)
Deploying a Marketplace/Model app from its published template
A Marketplace or Model workload's compose_config/app_secrets must echo back every service declared in the app version's template, or the API rejects the request — default_services builds that starting point from the template's own defaults, ready to hand to create_marketplace_workload/create_model_workload as-is or after overriding individual ports/volumes/env:
app_version = client.applications.get_version("<application-id>", "<app-version-id>")
compose_config, app_secrets = client.applications.default_services(app_version)
client.nodes.workloads.create_marketplace_workload(
"<node-id>",
app_version_id="<app-version-id>",
application_id="<application-id>",
name="my-workload",
compose_config=compose_config,
app_secrets=app_secrets,
)
Models
See Models in Academy.
models = client.models.list()
client.models.create(
"anomaly-detector", "Long description", "Barbara", model_type=0, engine=0
)
client.models.create_version("<model-id>", "./model.onnx", "1.0.0", ["Initial release"])
Config Repository
Reusable, named configuration documents — typed application or global — that a workload's own App Config or a node's/cluster's own Global Config can reference by id (config_id), rather than being one itself. See Application configuration types in Academy.
config = client.configs.create(
name="sensor-thresholds",
description="Per-node alert thresholds",
config={"temperature_max": 80},
)
print(config.config_type) # "application" or "global"
client.nodes.set_global_config("<node-id>", config_id=config.id)
Groups
See Nodes list in Academy for group management in the Panel.
group = client.groups.create(
name="floor-2-sensors",
description="All floor 2 nodes",
node_ids=["<node-id-1>", "<node-id-2>"],
)
Users
See Organization in Academy.
users = client.users.list()
page = client.users.paginate(offset=0, size=50)
print(page.items[0].role) # UserRole.ADMINISTRATOR / SUPERVISOR / EDITOR / VIEWER, or None
Alerts
See the Alert Manager app in Academy.
alerts = client.alerts.list()
client.alerts.ack("<alert-id>")
events = client.alerts.list_events(node_id="<node-id>")
Error handling
All API errors raise a subclass of BarbaraApiError:
from barbara import BarbaraApiError, BarbaraAuthError, BarbaraNotFoundError, BarbaraPermissionError
try:
client.nodes.resolve("unknown-node")
except BarbaraNotFoundError:
...
except BarbaraPermissionError:
...
except BarbaraApiError as e:
print(e.status, e.body)
Architecture
- One client, one resource tree.
BarbaraClientandAsyncBarbaraClientexpose the same resources (.nodes,.clusters,.applications, ...) with identical method signatures. - Automatic token refresh. A request that receives a
401is retried once with a freshly fetched token. - Typed models. Response entities are plain dataclasses. Every entity keeps the original API payload in
.raw. - Typed exceptions.
BarbaraNotFoundError,BarbaraAuthError, andBarbaraPermissionErrorsubclassBarbaraApiErrorso callers can handle specific failure modes. - Product naming throughout. Classes, methods, and fields follow Barbara's own product terminology (Node, Workload, App Config vs. Global Config, Barbara Core, ...) rather than internal API/wire jargon — see the Barbara Academy docs linked throughout this README for the concepts behind each resource.
- An escape hatch for everything else. Every resource method calls
client.request(method, path, ...)internally, and the same authenticated, token-refreshing request method is available directly for any endpoint not yet wrapped by a typed resource. See the examples. When buildingpathyourself, percent-encode any value that isn't a fixed literal (urllib.parse.quote(value, safe="")). Every typed resource method does this for its own id parameters, butclient.request(...)takespathas-is.
API reference
| Resource | Description |
|---|---|
client.nodes |
Node lifecycle, global secrets, global config, docker credentials, Barbara Core updates, and actions (reboot, provision, ...) |
client.nodes.workloads |
Docker/Marketplace/Model applications deployed on a node |
client.nodes.network |
The Networking card — interfaces, hostname, VLANs, VPN, Proxy, Standalone Mode, IPTables, NTP servers |
client.clusters |
Cluster lifecycle, global secrets, global config, docker credentials, and Swarm-managed volumes |
client.clusters.workloads |
Docker/Marketplace/Model applications deployed across a cluster |
client.applications |
Application catalog and versions |
client.models |
Model catalog and versions |
client.configs |
Config Repository — reusable, named configuration documents |
client.groups |
Node groups |
client.users |
Company users (read-only) |
client.alerts |
Alerts and alert events |
Full generated API reference (every method, parameter, and return type): barbaraedge.github.io/barbara-api-sdk-python. For the underlying HTTP API itself, see the Barbara API documentation.
Examples
The examples/ directory has complete, runnable scripts for common use cases:
| Script | Description |
|---|---|
hello_world.py |
The first script to run: confirm your credentials work and list your nodes |
node_info.py |
Read a node's configuration and latest telemetry |
check_barbara_core_updates.py |
Check nodes for an outdated Barbara Core, optionally update them |
network_audit.py |
Audit a node's network config (interfaces, hostname, VPN, proxy, iptables, NTP), optionally add an NTP server |
clone_node.py |
Clone a node's workloads, config, and docker volumes onto another node |
clone_tool.py |
Back up a node's configuration to a file, restore it onto one or more nodes, or wipe a node |
deployment_dashboard.py |
Live terminal dashboard monitoring a fleet against a target deployment state |
Some scripts also demonstrate calling an endpoint through client.request(...) directly (the same low-level method every typed resource is built on) for functionality this SDK doesn't wrap yet.
See examples/README.md for what each one covers, how to configure and run it, and ideas for extending it.
Roadmap
The following areas of the Barbara API are not yet covered by this SDK:
- App Secrets (Marketplace-only, per-app secrets, distinct from a node's Global Secrets)
Contributing
Bug reports and pull requests are welcome on GitHub Issues. See RELEASING.md for the branch model and release process this repository follows.
License
Distributed under the MIT License. See LICENSE for details.
Metadata
Release files for barbara-api-sdk 0.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| barbara_api_sdk-0.6.0.tar.gz | 139.5 kB | With provenance | Details for barbara_api_sdk-0.6.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| barbara_api_sdk-0.6.0-py3-none-any.whl | Python 3 | none | any | Details for barbara_api_sdk-0.6.0-py3-none-any.whl |
Total release size: 200.8 kB
Release files / barbara_api_sdk-0.6.0.tar.gz
| Download URL | barbara_api_sdk-0.6.0.tar.gz |
|---|---|
| Size | 139.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
700b2656911ff184f1c3edd5cbe2604cd16c02d4e612c9021be5f96bf79723fd
|
|
BLAKE2b-256 checksum How to use checksums |
454c3fe084a08ddb6deb963f02cd8d810db72ddb27ba77bfe11c497f43199f29
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 3, 2026.
Transparency logRelease files / barbara_api_sdk-0.6.0-py3-none-any.whl
| Download URL | barbara_api_sdk-0.6.0-py3-none-any.whl |
|---|---|
| Size | 61.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
cda5ced7e14e3df0cb82dbd190759573b236adbf9bc0eef12860b860905c65e7
|
|
BLAKE2b-256 checksum How to use checksums |
c524016ce3508f5fdd4ecdfe94a4dd345d358d0a760f4b2e6d56340bb20bf529
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 3, 2026.
Transparency logSecurity for barbara-api-sdk 0.6.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for barbara_api_sdk-0.6.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 3, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.