Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content
SDKs and tools

TypeScript SDK

@mubit-ai/sdk is for Node.js developers. It hands you the OpenAI or Anthropic client already pointed at Mubit, and it manages your Mubit organization from code. This page covers version 1.0.6.

Install

npm install @mubit-ai/sdk openai          # add @anthropic-ai/sdk if you call Claude

openai and @anthropic-ai/sdk aren't dependencies of the package: install the ones you use. The package needs Node.js 22.12 or newer. It ships ES modules and a CommonJS entry point, and its types come with it.

Set your keys

The SDK uses two kinds of key: an inference key (mbt_ or mw_) to send model calls, and a management key (mwm_) to manage Mubit. SDKs and tools shows how to create each one.

export MUBIT_API_KEY=<your inference key>
export MUBIT_MANAGEMENT_KEY=<your management key>

new Mubit() reads both from the environment. You can also pass them in:

import { Mubit } from "@mubit-ai/sdk";
 
const client = new Mubit({
  apiKey: process.env.MUBIT_API_KEY,
  managementKey: process.env.MUBIT_MANAGEMENT_KEY,
});

Your code needs the key for the job it does. Code that only sends model calls needs only the inference key. Code that only manages Mubit needs only the management key. Without the key a method needs, the SDK throws an error before it sends anything.

OptionWhat it sets
apiKeyThe inference key, for model calls.
managementKeyThe management key, for the management methods.
baseUrlThe Mubit API address. The default is https://api.mubit.ai.
maxRetriesHow many times a failed management call is retried. The default is 2.

Send model calls through Mubit

Your code keeps using the provider's own client. client.calls.openai() and client.calls.anthropic() give you one that already points at Mubit and carries your inference key. Mubit records each call and forwards it to the provider with the provider key stored for your project. Your calls, the tasks they form and the models trained from them then show in the console.

OpenAI
import { Mubit } from "@mubit-ai/sdk";
 
const client = new Mubit();
const openai = client.calls.openai(); // a stock OpenAI client
 
const reply = await openai.chat.completions.create({
  model: "gpt-5-mini",
  messages: [{ role: "user", content: "Classify this ticket: the invoice total is wrong." }],
});
console.log(reply.choices[0].message.content);

Both methods take the provider client's own options, such as timeout, maxRetries and defaultHeaders, and pass them through unchanged:

import { Mubit } from "@mubit-ai/sdk";
 
const client = new Mubit();
const claude = client.calls.anthropic({ timeout: 30 * 1000, maxRetries: 3 });

Other providers, or your own client setup

Any provider client works when you give it Mubit's base URL for that provider and your inference key as its API key:

ProviderBase URL
OpenAIhttps://api.mubit.ai/openai/v1
Anthropichttps://api.mubit.ai/anthropic
Google Geminihttps://api.mubit.ai/gemini
OpenRouter, Groq, Together, Mistral (OpenAI-compatible)https://api.mubit.ai/compat/<provider>/v1, for example https://api.mubit.ai/compat/groq/v1
import Anthropic from "@anthropic-ai/sdk";
 
const claude = new Anthropic({
  baseURL: "https://api.mubit.ai/anthropic",
  apiKey: process.env.MUBIT_API_KEY,
});

Connect covers each provider, and OpenAI-compatible the compatible services. A project can also use a Neon AI Gateway key: see Connect with the Neon AI Gateway.

Manage Mubit from code

With a management key, your code can do what you do in the console. Manage Mubit lists every method. This example reads the tasks, rates a call, trains a new version and rolls it out:

import { Mubit } from "@mubit-ai/sdk";
 
const client = new Mubit();
 
for await (const task of client.tasks.list()) {
  // every task, across all pages
  console.log(task.id, task.name, task.stage);
}
 
const taskId = "task_triage12";
 
const calls = await client.calls.list({ task: taskId, limit: 20 });
await client.calls.feedback(calls.data[0].id, { rating: "down", comment: "Missed the sales tax line." });
 
await client.tasks.train(taskId); // train a new version now
 
const versions = await client.tasks.versions(taskId);
const version = versions.data[0];
await client.versions.rollout(version.id, { canary_percent: 10 }); // serve it on 10% of the task's calls
await client.versions.promote(version.id); // then on all of them
await client.versions.rollback(version.id); // or go back to the previous version

The namespaces are org, projects, keys, providers, managementKeys, calls, tasks, versions, lessons, imports, usage, billing, activity and jobs. Answers are the API's JSON as plain objects.

Follow a job

A long-running operation runs as a job. jobs.wait polls the job until it ends. It throws if the job fails or is canceled, or if the wait passes timeoutMs (60 seconds by default):

import { Mubit } from "@mubit-ai/sdk";
 
const client = new Mubit();
 
const job = await client.jobs.wait("job_example1", { timeoutMs: 5 * 60 * 1000 });
console.log(job.status);

Pages, retries and safe repeats

  • Lists come in pages. A list call returns its first page, as page.data and page.next_cursor. Loop over the result with for await and the client fetches the next pages for you.
  • Busy or failing calls are retried. On a 429 or 5xx answer, or a network error, the client waits, honouring the server's Retry-After when it sends one, and retries up to maxRetries times (2 by default).
  • A retried write isn't applied twice. Every POST carries an Idempotency-Key header. The client makes one for you, or you can pass your own as { idempotencyKey: "..." } in the last argument.

Errors

Every error the management methods throw is a MubitError, so one catch handles all of them. The error has these fields:

FieldWhat it holds
statusThe HTTP status, or null when no answer came.
codeA short reason, such as not_found. A connection that failed has connection_error.
requestIdThe request's id. Quote it when you contact support.
detailsMore about the failure, when there is any.

Each status has its own subclass, so you can also test the class name: ConfigurationError (no key, or a bad option), BadRequestError (400), AuthenticationError (401), PermissionDeniedError (403), NotFoundError (404), ConflictError (409), PayloadTooLargeError (413), RateLimitError (429, after the retries; it also has retryAfter), InternalServerError (500) and ServiceUnavailableError (503).

import { Mubit } from "@mubit-ai/sdk";
 
const client = new Mubit();
 
try {
  await client.tasks.get("task_triage12");
} catch (err) {
  const failure = err as { status?: number | null; code?: string; requestId?: string | null };
  if (failure.status !== 404) throw err;
  console.log(failure.code, failure.requestId);
}

Errors from model calls you send through Mubit are the provider client's own, for example OpenAI.APIError.

ℹ️Note

The package also has helpers for runtime calibration. The guide shows that feature with plain HTTP calls.

Related