---
title: "Getting started"
sidebar_label: "Getting started"
description: "Install the Barbara API SDK for Python, authenticate, and run your first calls: list your nodes, read live telemetry, and make your first write."
lastmod: "2026-09-03"
---

import { SdkVersionNotice } from '@site/src/components/VersionNotice';
import { UpdateInProgressNotice } from '@site/src/components/VersionNotice';
import ConceptLink from '@site/src/components/ConceptLink';

<SdkVersionNotice sdkArticleVersion="v0.6.0" />
<!--
<UpdateInProgressNotice />
-->

## Overview

This guide takes you from an empty Python environment to your **first authenticated calls** against the Barbara API. You'll install the **Barbara API SDK for Python**, set up **authentication**, and run three short examples: **listing your nodes**, **reading a node's live telemetry**, and making **your first write call**.

Every other guide in this section assumes you've completed the steps here: a working `BarbaraClient` and a node id in hand. **In about 15 minutes**, you'll have a working script talking to your Barbara fleet, and enough context to follow the rest of the guides field by field.

:::info[Concept]
**Node.** The machine an operator manages from Barbara Panel: a physical gateway, a virtual machine, or a hosted sandbox, running the Barbara agent and reporting its own status and telemetry back.

<ConceptLink to="/platform/node-lifecycle/general-info/" />
:::

## Install the SDK

The SDK requires Python **3.9** or later.

```bash
pip install barbara-api-sdk
```

## Authenticate

The SDK authenticates against the Barbara API using the OAuth2 password grant. You need four values, referred to throughout Barbara's documentation as the **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 |

`BBR_API_USERNAME` and `BBR_API_PASSWORD` are the **same credentials** used to log into the Barbara Panel, the same login screen behind [Add a Marketplace app to your Library](/platform/apps-and-models/add-a-marketplace-app-to-your-library/). `BBR_API_CLIENT_ID` and `BBR_API_CLIENT_SECRET` identify your *application* rather than you personally, and are **issued separately by [Barbara support](mailto:support@barbara.tech)**. Nothing in Barbara Panel's UI generates these two, since they exist purely for machine-to-machine access.

**Export all four** as environment variables:

```bash
export BBR_API_USERNAME="..."
export BBR_API_PASSWORD="..."
export BBR_API_CLIENT_ID="..."
export BBR_API_CLIENT_SECRET="..."
```

:::note[Looking for the full reference?]
See [Config & auth](/api/barbara-api-sdk-python/reference/config/) in the Reference for the `BarbaraConfig` alternative (useful when credentials come from a secrets manager), the API/auth server URL variables, and how token refresh works.
:::

## Import and create a client

With the environment variables in place, [`BarbaraClient.from_env()`](/api/barbara-api-sdk-python/reference/client/) picks them up automatically:

```python
from barbara import BarbaraClient

with BarbaraClient.from_env() as client:
    ...
```

`BarbaraClient` is a **context manager**: using `with` **ensures the underlying HTTP connection pool is closed** once you're done. Every resource lives off this client as an attribute (`client.nodes`, `client.clusters`, `client.applications`, ...), and every one of those resources is itself an object with methods on it, not a bare function, so `client.nodes.list()` and `client.clusters.list()` share the **same shape by design**.

:::tip[Async client available]
See the [Client](/api/barbara-api-sdk-python/reference/client/) reference page for **`AsyncBarbaraClient`**, the async counterpart used inside async applications, and for the `http2`/`max_retries` constructor options if you need multiplexed connections or automatic retries on transient errors.
:::

## List your nodes

[`client.nodes`](/api/barbara-api-sdk-python/reference/nodes/) covers everything node-related. In the product, a **node** is a physical or virtual machine running the Barbara agent, anything from a small industrial gateway to a server-grade box: the unit onto which you deploy applications and models. The SDK's `client.nodes` mirrors what you'd otherwise manage from the **[Nodes List](/platform/node-lifecycle/nodes-list/)** in Panel. **Listing your fleet is the simplest possible call:**

```python
from barbara import BarbaraClient

with BarbaraClient.from_env() as client:
    for node in client.nodes.list():
        print(node.node_name, node.status)
```

[`client.nodes.list()`](/api/barbara-api-sdk-python/reference/nodes/#list) returns a `List[`[`Node`](/api/barbara-api-sdk-python/reference/models/#node)`]`, **one Python object per row** you'd see in the Nodes List. Each `Node` carries:

| Field | Type | What it is |
|---|---|---|
| `id` | `str` | The node's internal 24-character identifier, the same value used by every other `client.nodes.*` method that takes a `node_id` |
| `node_name` | `str` | The human-assigned name shown in Panel's **Node Name** column, also called the node's *Barbara ID* elsewhere in this guide |
| `status` | `Optional[Dict[str, Any]]` | A raw dict mirroring Panel's [node lifecycle state](/platform/node-lifecycle/node-management/) (**Activated**, **Deactivated**, ...) |
| `cluster_id` | `Optional[str]` | The id of the [cluster](/api/barbara-api-sdk-python/guides/clusters-and-stacks/) this node belongs to, or `None` if it isn't in one |
| `raw` | `Dict[str, Any]` | The full, untyped API response for this node, in case you need a field the SDK hasn't wrapped yet |

:::note[list() returns one page]
`list()` returns a **single page**; the server applies its own default page size when you don't ask for a specific `size`. If your fleet is larger than one page, use [`client.nodes.paginate()`](/api/barbara-api-sdk-python/reference/nodes/#paginate) instead, which accepts **`size`** and **`from_`** and returns a [`Page`](/api/barbara-api-sdk-python/reference/models/#page) with a `total` field so you know how many pages remain.
:::

## Look up a node and read its telemetry

Nodes are addressed internally by the 24-character `id` from the table above, but Panel shows them by their human-assigned name, the **Barbara ID** (for example `factory-line-3-cam01`), the same identifier documented in [Get the Barbara ID of the node](/platform/install-barbara-core/finding-your-nodes-barbaraid/). [`resolve()`](/api/barbara-api-sdk-python/reference/nodes/#resolve) **looks a node up by that name** and returns the matching `Node`, so you don't need to know its internal id ahead of time:

```python
node = client.nodes.resolve("factory-line-3-cam01")

telemetry = client.nodes.get_last_telemetry(node.id)
print(telemetry["disk"], telemetry["alive"])
```

[`get_last_telemetry(node_id)`](/api/barbara-api-sdk-python/reference/nodes/#get_last_telemetry) takes the internal `id` you just resolved, not the node name, and **returns the same data shown on the [Telemetry](/platform/node-lifecycle/telemetry/) card** of the Node Details page: CPU load, RAM, disk, temperature, and per-process resource usage, as a raw, deeply nested dict rather than a typed object, since the shape varies by node and agent version. Index into it the same way you'd read any JSON response, for example `telemetry["disk"]["percent"]` for the disk-usage percentage the Telemetry card shows.

:::tip[resolve() costs an extra request]
`resolve()` costs an extra search request under the hood, since the API only accepts an id, not a name, for most endpoints. If you already have a node's internal `id`, for example saved from a previous run or from `list()`, call [`client.nodes.get(node_id)`](/api/barbara-api-sdk-python/reference/nodes/#get) directly instead.
:::

## Make your first write call

Everything so far has been **read-only**. Writes follow the same shape, just with the value you want to set as an argument instead of a return value. **Tagging a node** is the simplest one: tags are the free-form labels you'd otherwise add from the **Tags** field of the [General Info](/platform/node-lifecycle/general-info/) card.

```python
client.nodes.add_tag(node.id, "provisioned-by-sdk")

node = client.nodes.get(node.id)
print(node.raw["tags"])
```

[`add_tag(node_id, tag)`](/api/barbara-api-sdk-python/reference/nodes/#add_tag) takes the same `node_id` as every other node method and a plain string for the tag, there's no separate "create tag" object to look up first. It **returns `None`**: the SDK's write methods generally don't echo back the object they just changed, so the second call above re-fetches the node with `get()` to confirm the tag landed.

:::tip[Read-after-write]
Call a write method, then `get()` if you need to see the result. This pattern comes up throughout the guides that follow.
:::

## Summary

You **installed the SDK**, **authenticated** against the Barbara API, and made your first calls: **listing your fleet**, **reading a node's live telemetry**, and **writing your first change back** with a tag.

With one client, you can now script against every resource the Barbara Panel exposes, without clicking through the UI by hand.

For the concepts behind the resource tree (nodes, clusters, applications, models, ...) and narrative examples covering deployments, clusters, and error handling, see the [Overview](/api/barbara-api-sdk-python/). For every method, parameter, and return type, see the [Reference](/api/barbara-api-sdk-python/reference/nodes/) section. To go deeper on organizing your fleet with tags and groups, continue to [Node identity, tags, groups & safety actions](/api/barbara-api-sdk-python/guides/node-identity-tags-groups-safety/).
