Bahini
Open app

Getting started

Authentication

Every request carries a bearer API key scoped to one organization. Keys are created in the console and can be read-only or write-scoped.

Bearer keys#

Create a key under Settings → API keys. The SDK sends it as Authorization: Bearer bah_… on every call. A key is bound to a single org — all runs, agents, and data it touches belong to that org.

 
ts
const bahini = new BahiniClient({
  apiKey: process.env.BAHINI_API_KEY!, // "bah_..."
});

Scopes#

Keys are least-privilege by design. A read-onlykey can list and read (runs, agents, datasets, audit log) but is rejected on any write — creating agents, publishing data, kicking off runs. Give each integration the narrowest scope it needs, and rotate on your policy's schedule.

Methods that mutate state note "requires a write-scoped key" in the reference. A read-only key calling one gets a 403 — surfaced as a BahiniApiError.

Base URL#

Defaults to the hosted platform. For a self-hosted deploy, set baseUrl to your origin — the rest of the API is identical.

 
ts
const bahini = new BahiniClient({
  apiKey: process.env.BAHINI_API_KEY!,
  baseUrl: "https://bahini.your-company.com",
});

Errors#

Any non-2xx response throws a BahiniApiError carrying the HTTP status, a message, and the parsed error body. GET requests and idempotency-keyed POSTs are retried on transient network/5xx failures (linear backoff, 2 retries by default); 4xx is never retried.

 
ts
import { BahiniApiError } from "@bahini/sdk";

try {
  await bahini.runAgent("agent_123", { prompt: "..." });
} catch (err) {
  if (err instanceof BahiniApiError) {
    console.error(err.status, err.message, err.body);
  } else {
    throw err;
  }
}

Who am I?#

Verify a key and read its org + scope with getMe()— a cheap health check for your integration's startup.

 
ts
const me = await bahini.getMe();
console.log(me.org.name, me.scope);