SDKs
Vibedasher ships official, fully-typed SDKs for TypeScript and Python, generated from the API's OpenAPI spec so they stay in lockstep with the platform. They're how your own code reaches the maintained platform: run SQL against your datasets, trigger refreshes, manage connections and access rights, wire a dashboard to live data, or automate anything the MCP tools do from a script instead of an agent.
| Language | Package | Documented here |
|---|---|---|
| TypeScript | @vibedasher/client | 4.1.5 |
| Python | vibedasher | 4.3.19 |
Both SDKs authenticate with an API key in the X-Api-Key header. Mint one in the app
under Settings → API keys at cloud.vibedasher.com — see
Authentication. (The SDKs are the code path; if your agent is
driving Vibedasher over MCP, it signs in with vibedasher login instead and needs no key
at all — see Build with your agent.)
Neither client needs to be told which region your account lives in. With no base URL and no
region, both resolve to https://api.vibedasher.com/api, which routes each request by the
credential it carries — see
One host, routed by your credential.
Passing region is still supported and pins the client to that region's own hostname,
https://api.{region}.vibedasher.com/api; an explicit baseUrl / base_url overrides both.
(region became optional in @vibedasher/client 4.1.5 and vibedasher 4.3.19.)
Looking for a specific endpoint? Browse the full API Reference — every operation grouped by resource, with curl / Python / TypeScript request samples generated from the same signatures the SDKs are built from.
The shape of every call
Both SDKs expose the same resource-grouped fluent client. Construct it once, then call
methods grouped by resource. Signatures are flat: path parameters first (in path
order), then the request body, then one optional trailing options object holding the query
parameters. There are no path / query / body wrapper objects.
Resources are the same 23 in both languages, camelCase in TypeScript and snake_case in Python:
accounts, aiProviders, apiKeys, chats, connections, dashboardSubscriptions,
datasets, dbt, embedTokens, folders, groups, images, questions, refreshes,
skills, sql, subscriptions, tasks, templates, tools, upload, users, viz.
A non-2xx response raises — VibedasherApiError in both languages. Methods never
resolve to an error union, so you do not check a result before using it.
TypeScript
npm install @vibedasher/client
import { Vibedasher, VibedasherApiError } from '@vibedasher/client';
const client = new Vibedasher({
apiKey: process.env.VIBEDASHER_API_KEY!,
});
// List datasets — query params go in the trailing options object
const page = await client.datasets.list({ limit: 50 });
// Create — the body is positional
const created = await client.datasets.create({ name: 'Sales', type: 'csv' });
// Fetch one by id — path params are positional
const one = await client.datasets.get(created.dataset.id);
// Update — path param, then body
const updated = await client.datasets.update(one.dataset.id, { name: 'Sales 2026' });
Every method is typed end to end: the argument types and the resolved response type come
from the spec, and the per-resource interfaces (DatasetsResource,
DatasetsListOptions, …) and model types (DatasetResponse, DatasetUpdate, …) are
exported from the package root if you want to annotate a variable.
Running SQL
client.query is the hand-written method the generated surface does not have: one call
in, typed columnar results out.
const result = await client.query({
sql: 'SELECT country, SUM(revenue) AS revenue FROM sales GROUP BY 1',
});
console.log(result.columns, result.rows);
datasetIds is optional — omit it and the server resolves the dataset set from the aliases
your SQL references, applying exactly the same authorization.
Uploading a CSV
const uploaded = await client.datasets.upload({
name: 'Sales',
content: 'country,revenue\nFR,10\nDE,12\n',
});
console.log(uploaded.cleanSQLName); // the alias to use in client.query SQL
Escape hatch
The underlying fetch client is on the instance as client.http if you need
interceptors, a custom fetch, or per-call overrides. There is no module-level singleton
to configure: each Vibedasher instance owns its own client, so two clients in one process
never clobber each other's base URL or key.
Python
pip install vibedasher
from vibedasher import Vibedasher, VibedasherApiError
from vibedasher.models import DatasetCreate, DatasetUpdate
client = Vibedasher(api_key="<your-api-key>")
# List datasets — query params are keyword-only
page = client.datasets.list(limit=50)
# Create — the body is the first positional argument
created = client.datasets.create(DatasetCreate(name="Sales", type_="csv"))
# Fetch one by id — path params are positional
one = client.datasets.get(created.dataset.id)
# Update — path param, then body
updated = client.datasets.update(one.dataset.id, DatasetUpdate(name="Sales 2026"))
Request and response models live in vibedasher.models. Resource attributes are
snake_case (client.datasets, client.api_keys, client.ai_providers,
client.embed_tokens, client.viz, …), and so are the
methods.
Running SQL
result = client.query(sql="SELECT country, SUM(revenue) AS revenue FROM sales GROUP BY 1")
print(result.columns, result.rows)
Uploading a CSV
uploaded = client.datasets.upload(name="Sales", content="country,revenue\nFR,10\nDE,12\n")
print(uploaded["cleanSQLName"]) # the alias to use in client.query SQL
Escape hatch
The flat operation modules under vibedasher.api.<tag> are still shipped for anything the
facade does not cover. Build a raw client with create_client and call .sync(),
.sync_detailed(), .asyncio(), or .asyncio_detailed():
from vibedasher import create_client
from vibedasher.api.datasets import read_datasets
raw = create_client(api_key="<your-api-key>")
datasets = read_datasets.sync(client=raw)
Error handling
Both SDKs raise on a non-2xx response, so the happy path reads straight through and errors are caught where you want to handle them.
TypeScript:
import { Vibedasher, VibedasherApiError } from '@vibedasher/client';
try {
const page = await client.datasets.list({ limit: 50 });
console.log(page.datasets);
} catch (err) {
if (err instanceof VibedasherApiError) {
console.error(`Request failed (${err.status})`, err.detail, err.requestId);
} else {
throw err;
}
}
Python:
from vibedasher import VibedasherApiError
try:
page = client.datasets.list(limit=50)
except VibedasherApiError as err:
print(f"Request failed ({err.status_code})", err.detail, err.request_id)
Common status codes: 401/403 (missing or invalid API key, or a key used on a session-only route), 404 (not found, or a viz that isn't published), 422 (request validation error). Each endpoint's reference page lists the exact responses it can return.
Pagination
List endpoints return a page of results plus a nextKey cursor. You rarely need to drive
that cursor yourself: every listable resource carries iterAll() (TypeScript) /
iter_all() (Python), which walks the pages and yields rows.
TypeScript:
for await (const ds of client.datasets.iterAll()) {
handle(ds);
}
Python:
for ds in client.datasets.iter_all():
handle(ds)
Both also expose the page-level form (iterPages() / iter_pages()) when you want the
envelope rather than the rows. Driving the cursor by hand still works — pass nextKey back
as exclusiveStartKey (exclusive_start_key in Python) and stop when it comes back
null/None — but the iterators also detect a cursor that stops advancing and raise
rather than looping forever.
The wire name — what the cURL tab and every reference page's parameter table show — is
always exclusiveStartKey; the TypeScript SDK keeps that camelCase spelling as its option
key, and the Python SDK exposes the same parameter as the exclusive_start_key keyword.
It is one cursor, spelled per language — never both on one request.
Response typing caveat
Some API routes currently return loosely-typed responses (object / Any) because they
declare a generic response shape on the backend. Request bodies, query/path params, and an
increasing set of responses are fully typed. Response types are being hardened
module-by-module — upgrade the SDK to pick up improvements.
The SDKs are generated, never hand-edited. If you spot a gap, it's almost always upstream in the API's OpenAPI spec — reach out via the contact page.