memoair-admin
v0.1.1
Published
Server-side TypeScript SDK for the MemoAir org-key admin API (projects, agents).
Maintainers
Readme
memoair-admin
Server-side TypeScript SDK for the MemoAir org-key admin API.
memoair-admin is the partner-facing companion to MemoAir's Python voice
SDKs. Where the Python SDKs (memoair-voice, memoair-livekit) run inside
a voice worker and operate against a single agent identity, this package
runs inside a partner backend and operates against an entire organisation:
it lets you onboard customers (projects), register voice agents, and list
what's already provisioned -- all authenticated with a single
memoair_pk_* account-scoped API key.
When to use this
You're building a multi-tenant product (think Fundamento, or any partner who serves their own customers on top of MemoAir) and you need a server-side control plane to:
- Create one MemoAir project per customer at onboarding time.
- Register one or more voice agents per project.
- Fan out across every project + agent to power dashboards or audits.
If you're writing a voice worker (the runtime that handles a live call),
you want memoair-voice or memoair-livekit instead. This SDK never
opens a voice session.
Installation
npm install memoair-admin
# or
pnpm add memoair-admin
# or
yarn add memoair-adminRequires Node 18+ (relies on native fetch). Zero runtime dependencies.
Quick start
import { MemoAirAdmin } from "memoair-admin";
const admin = new MemoAirAdmin({
apiKey: process.env.MEMOAIR_API_KEY!, // memoair_pk_*
// baseUrl defaults to https://api.memoair.io
});
await admin.healthCheck(); // "ok"When orgId is needed
Project creation and agent creation infer org from the memoair_pk_* key, so the common onboarding flow does not need orgId. Pass orgId only if you want to call admin.listAgents(), which lists every agent across the org via GET /v1/orgs/{orgID}/agents.
Fundamento walkthrough
A typical partner flow: each Fundamento customer becomes a MemoAir project, each customer-facing voice flow becomes an agent.
import { MemoAirAdmin } from "memoair-admin";
const admin = new MemoAirAdmin({
apiKey: process.env.MEMOAIR_API_KEY!,
});
// 1. Onboard a customer -- creates a MemoAir project under your org.
const customerA = await admin.createProject({
name: "Customer A",
slug: "customer-a",
description: "Onboarded 2026-05-22 via Fundamento",
});
// 2. Register a voice agent for that customer.
const supportBot = await admin.createAgent({
name: "Support Bot",
projectId: customerA.id,
});
// 3. Hand these IDs to your voice worker. The worker runs
// `memoair-voice` / `memoair-livekit` (Node) or the Python packages and
// reads them from env:
//
// MEMOAIR_API_KEY=memoair_pk_... # same org key
// MEMOAIR_PROJECT_ID=<customerA.id>
// MEMOAIR_AGENT_ID=<supportBot.id>
// MEMOAIR_USER_ID=<caller identifier, per-call>For an admin dashboard you can list everything that's already provisioned:
const projects = await admin.listProjects();
const agents = await admin.listAgents(); // cross-project, carries projectSlug/projectName
// Group agents by project for a UI:
const byProject = agents.reduce<Record<string, typeof agents>>((acc, a) => {
(acc[a.projectSlug] ??= []).push(a);
return acc;
}, {});API reference
new MemoAirAdmin(options)
interface MemoAirAdminOptions {
apiKey: string; // memoair_pk_* (required)
orgId?: string; // optional; only needed for listAgents()
baseUrl?: string; // defaults to https://api.memoair.io; trailing
// slashes are stripped automatically
fetch?: typeof fetch; // optional custom fetch (e.g. for edge runtimes)
}Throws synchronously if apiKey is missing.
admin.createProject(input)
POST /v1/projects -- creates a project in the SDK's org. Returns the
full Project row.
const project = await admin.createProject({
name: "Customer A",
slug: "customer-a", // unique within the org
description: "Optional",
});admin.listProjects()
GET /v1/projects -- returns every project in the SDK's org, newest first.
admin.listAgents()
GET /v1/orgs/{orgId}/agents -- returns every agent across every project
in the SDK's org, each row decorated with projectSlug + projectName
so a UI can group results without a second round-trip. Requires
new MemoAirAdmin({ orgId }); project and agent creation do not.
admin.createAgent(input)
POST /v1/projects/{projectId}/agents -- creates an agent under a specific project.
The backend infers org from the API key and verifies that projectId belongs to that org. Cross-org mismatches return 404 (not found or access denied) so project IDs cannot be enumerated.
const agent = await admin.createAgent({
name: "Support Bot",
projectId: project.id,
agentType: "voice",
});admin.healthCheck()
GET /healthz -- returns the text body (typically "ok"). Useful for
boot-time sanity checks.
Error handling
Every non-2xx response throws a MemoAirAdminError:
import { MemoAirAdmin, MemoAirAdminError } from "memoair-admin";
try {
await admin.createProject({ name: "Dup", slug: "dup" });
} catch (err) {
if (err instanceof MemoAirAdminError) {
console.error(err.status); // 400
console.error(err.body); // "slug already taken"
console.error(err.url); // "https://api.memoair.io/v1/projects"
}
}The error carries the original HTTP status, the raw response body, and the full URL so you can surface partner-friendly errors without re-parsing.
Security notes
- Treat
memoair_pk_*keys as production secrets. Anyone holding the key can manage every project + agent in the org. - Mint a separate key per partner backend (Task 11 supports this) so you can revoke a single key without disrupting the rest.
- The SDK never logs the key. It only ever appears in the
Authorizationheader sent to your configuredbaseUrl.
Development
npm install
npm run build # tsc -> dist/
npm run typecheck # tsc --noEmit
npm test # vitest runLicense
MIT
