npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

memoair-admin

v0.1.1

Published

Server-side TypeScript SDK for the MemoAir org-key admin API (projects, agents).

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-admin

Requires 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 Authorization header sent to your configured baseUrl.

Development

npm install
npm run build      # tsc -> dist/
npm run typecheck  # tsc --noEmit
npm test           # vitest run

License

MIT