Skip to main content

🛰️ 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.

📖 Full documentation

CI Security Docs PyPI version Python versions License: MIT Typed


✅ 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

Note Panel credentials can be created at onboarding.barbara.tech. Client credentials are issued by Barbara support.

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

client.nodes.reboot("<node-id>")
client.nodes.poweroff("<node-id>")

Node secrets

See Secrets in Academy.

client.nodes.create_secrets("<node-id>", {"wifi-psk": "s3cr3t"})
secrets = client.nodes.list_secrets("<node-id>")
client.nodes.delete_secret("<node-id>", "<secret-id>")

Node app configuration

Corresponds to the Panel's Global Config (node-scoped; see Application configuration types for the full picture).

client.nodes.set_appconfig("<node-id>", config={"threshold": 5})
config = client.nodes.get_appconfig("<node-id>")

Docker credentials

client.nodes.create_docker_credentials(
    "<node-id>", [{"user": "bob", "password": "s3cr3t", "server": "docker.io"}]
)

Node identity: name, tags, location, safety config

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_config(
    "<node-id>", trigger_threshold=90, stop_apps=True, prune_volumes=True
)

Note get_location is returned as a raw dict rather than a typed object, since node location payloads vary in shape.

Warning set_location currently returns a 500 Internal Server Error regardless of the payload sent. Use the Panel to update a node's location until this is resolved.

OTA (Barbara Core version updates)

See Firmware updates in Academy.

client.nodes.send_ota_update("<node-id>", "update")
client.nodes.send_ota_update(
    "<node-id>", "schedule", schedule_timestamp="2026-01-01T03:00:00Z"
)
client.nodes.cancel_ota_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.

Note create_docker_volume doesn't return an id. Use list_docker_volumes to look one up before calling delete_docker_volume.

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. See Docker apps and Marketplace apps in Academy.

client.nodes.workloads.create_user_workload(
    "<node-id>",
    app_version_id="<app-version-id>",
    application_id="<application-id>",
)

client.nodes.workloads.create_market_workload(
    "<node-id>",
    app_version_id="<app-version-id>",
    application_id="<application-id>",
    name="my-workload",
    services=[{"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>")

Note Creation and update calls do not return the resulting workload state. Call client.nodes.workloads.get(...) afterwards if you need it.

Model workloads

Same body shape as market workloads, deploying a model application version instead — services 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",
    services=[{"name": "modelservice", "ports": {"PORT_NUMBER": "8501"}}],
)

Clusters

See Clusters in Academy.

clusters = client.clusters.list()
cluster = client.clusters.get("<cluster-id>")
client.clusters.update("<cluster-id>", "new-name")

client.clusters.create_secrets("<cluster-id>", {"db-password": "s3cr3t"})
client.clusters.set_appconfig("<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>")

Note primary_node and secondary_nodes take the cluster networking configuration as dicts matching the API schema.

Cluster stacks

The cluster-level equivalent of node workloads — deploy an application across every node in a cluster. See Add applications in Academy.

client.clusters.stacks.create_user_stack(
    "<cluster-id>",
    app_version_id="<app-version-id>",
    application_id="<application-id>",
)

client.clusters.stacks.delete("<cluster-id>", "<stack-id>")

Model stacks work the same way, using create_model_stack:

client.clusters.stacks.create_model_stack(
    "<cluster-id>",
    app_version_id="<model-app-version-id>",
    application_id="<model-application-id>",
    name="my-model-stack",
    services=[{"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"]
)

Tip create and create_version upload files (icon, installable artifact) as multipart/form-data. Pass a local file path — the SDK reads the file and builds the request for you.

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"])

Tip sha256 and size for a model version are computed automatically from the artifact — you don't need to pass them yourself.

App configurations

Reusable, named application configurations that can be referenced by ID elsewhere in the API. See Application configuration types in Academy.

app_config = client.appconfig.create(
    name="sensor-thresholds",
    description="Per-node alert thresholds",
    config={"temperature_max": 80},
)

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)

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. BarbaraClient and AsyncBarbaraClient expose the same resources (.nodes, .clusters, .applications, ...) with identical method signatures.
  • Automatic token refresh. A request that receives a 401 is 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, and BarbaraPermissionError subclass BarbaraApiError so callers can handle specific failure modes.
  • An escape hatch for everything else. Every resource method calls client.request(method, path, ...) internally — the same authenticated, token-refreshing request method is available directly for any endpoint not yet wrapped by a typed resource. See the examples. When building path yourself, 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, but client.request(...) takes path as-is.

📖 API reference

Resource Description
client.nodes Node lifecycle, secrets, app configuration, docker credentials, and actions (reboot, provision, ...)
client.nodes.workloads Applications deployed on a node
client.clusters Cluster lifecycle, secrets, app configuration, and docker credentials
client.clusters.stacks Applications deployed across a cluster
client.applications Application catalog and versions
client.models Model catalog and versions
client.appconfig Reusable application configurations
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
quickstart.py List nodes and look one up by name
node_info.py Read a node's configuration and latest telemetry
check_firmware_updates.py Check nodes for outdated firmware, optionally update them
clone_node.py Clone a node's workloads and app configuration onto another node

Each script also demonstrates 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:

  • Node network configuration (interfaces, NTP, proxy, VPN, iptables)
  • Node standalone mode and VPN peer management

📄 License

Distributed under the MIT License. See LICENSE for details.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

barbara_api_sdk-0.2.1.tar.gz (81.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

barbara_api_sdk-0.2.1-py3-none-any.whl (38.8 kB view details)

Uploaded Python 3

File details

Details for the file barbara_api_sdk-0.2.1.tar.gz.

File metadata

  • Download URL: barbara_api_sdk-0.2.1.tar.gz
  • Upload date:
  • Size: 81.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.3

File hashes

Hashes for barbara_api_sdk-0.2.1.tar.gz
Algorithm Hash digest
SHA256 fe16d9aff66e24920658687ba9ffded1b89dec9fd15a9096c4326f614a7d3e28
MD5 f8ce03cc96ac17285fd2857e2720f0d8
BLAKE2b-256 84104c969078d46bbddd2d6ae6d0100d752d3bc92b5ee738e6a4a58ba76de60a

See more details on using hashes here.

File details

Details for the file barbara_api_sdk-0.2.1-py3-none-any.whl.

File metadata

File hashes

Hashes for barbara_api_sdk-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 2a1fb5e54b76d35fd488c02a7813d6b27279fef5d2e3d7998a8c089622f22272
MD5 38f842ab01b681aa5a8a2de00d0e12e3
BLAKE2b-256 f11cf44af73aaeea2b667d92994291b5ee8700b75223b729064a0e8eb25b44c2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page