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

@administrate.dev/sdk

v0.1.0

Published

TypeScript SDK for the Administrate.dev platform

Readme

Administrate TypeScript SDK

The official TypeScript SDK for the Administrate.dev REST API.

Administrate.dev is AI Agency Management software. It is a monitoring and management platform for AI agencies running n8n and AI automation workflows across multiple clients. It provides a single dashboard to track every workflow, every client, every failure, and all LLM costs, so you can catch problems before clients do and prove the value of your automations.

Key platform features:

  • Multi-instance monitoring — See all n8n instances across every client in one place
  • Error tracking — Real-time failure detection with automatic error categorization
  • LLM cost tracking — Connect OpenAI, Anthropic, Azure, and OpenRouter accounts to attribute costs to specific clients
  • Workflow insights — Execution counts, success rates, and time-saved ROI reporting
  • Sync health — Know instantly when a data sync fails
  • Webhooks & API — Full programmatic access for custom integrations

Installation

npm install @administrate.dev/sdk

Requires Node.js 18+ (uses native fetch). Also works in Deno, Bun, and edge runtimes.

Quick start

import { Administrate } from "@administrate.dev/sdk";

const client = new Administrate({ apiKey: "sk_live_..." });

// Get account info
const account = await client.account.get();
console.log(account.name, account.plan);

// List all clients with auto-pagination
for await (const c of client.clients.list()) {
  console.log(c.name, c.n8n_instances_count);
}

// Check for failed executions across all instances
for await (const execution of client.executions.list({ errorsOnly: true })) {
  console.log(`${execution.workflow_name}: ${execution.error_category}`);
}

// Get LLM cost summary
const costs = await client.llmCosts.summary();
console.log(`Total: $${(costs.data.summary.total_cost_cents / 100).toFixed(2)}`);

Configuration

import { Administrate } from "@administrate.dev/sdk";

const client = new Administrate({
  apiKey: "sk_live_...",       // Required. Must start with "sk_live_"
  baseUrl: "https://...",      // Default: "https://administrate.dev"
  timeout: 30_000,             // Request timeout in milliseconds. Default: 30000
  maxRetries: 3,               // Retry attempts for failed requests. Default: 3
});

You can also pass a custom fetch implementation if you need full control over the HTTP layer:

const client = new Administrate({
  apiKey: "sk_live_...",
  fetch: myCustomFetch,
});

API reference

All API keys are created in Settings > Developers within Administrate.dev. Tokens have three permission levels: read, write, and full.

Account

// Get current token info and account summary
const me = await client.account.me();
console.log(me.token.name, me.token.permission);
console.log(me.account.name, me.account.plan);

// Get full account details
const account = await client.account.get();

// Update account settings
const updated = await client.account.update({
  name: "My Agency",
  billingEmail: "[email protected]",
  timezone: "Australia/Brisbane",
});

Clients

Clients represent the companies you manage automations for.

// List all clients (auto-paginates)
for await (const c of client.clients.list()) {
  console.log(c.name, c.code);
}

// Get a client (includes 7-day metrics)
const c = await client.clients.get("com_abc123");
console.log(c.metrics?.success_rate, c.metrics?.time_saved_minutes);

// Create a client
const newClient = await client.clients.create({
  name: "Acme Corp",
  code: "acme",
  contactEmail: "[email protected]",
  timezone: "America/New_York",
});

// Update a client
const updatedClient = await client.clients.update("com_abc123", { notes: "Enterprise tier" });

// Delete a client (requires full permission)
await client.clients.delete("com_abc123");

Instances

Instances are n8n deployments connected to Administrate.

// List all instances
for await (const inst of client.instances.list()) {
  console.log(inst.name, inst.sync_status);
}

// Filter by client or sync status
for await (const inst of client.instances.list({ clientId: "com_abc123", syncStatus: "error" })) {
  console.log(inst.name, inst.last_sync_error);
}

// Get an instance (includes 7-day metrics)
const inst = await client.instances.get("n8n_abc123");
console.log(inst.metrics?.executions_count, inst.metrics?.success_rate);

// Connect a new n8n instance
const newInst = await client.instances.create({
  clientId: "com_abc123",
  name: "Production n8n",
  baseUrl: "https://n8n.acme.com",
  apiKey: "n8n_api_key_here",
});

// Trigger a sync
const result = await client.instances.sync("n8n_abc123", { syncType: "all" });

// Sync all instances at once
const syncResult = await client.instances.syncAll({ syncType: "workflows" });

// Update an instance
await client.instances.update("n8n_abc123", { name: "Staging n8n" });

// Delete an instance
await client.instances.delete("n8n_abc123");

Workflows

// List workflows with filters
for await (const wf of client.workflows.list({ clientId: "com_abc123", active: true })) {
  console.log(wf.name, wf.is_active);
}

// Search by name
for await (const wf of client.workflows.list({ search: "onboarding" })) {
  console.log(wf.name);
}

// Get a workflow (includes 7-day metrics)
const wf = await client.workflows.get("wfl_abc123");
console.log(wf.metrics?.success_rate, wf.metrics?.time_saved_minutes);

// Set time-saved estimates (for ROI reporting)
const updatedWf = await client.workflows.update("wfl_abc123", {
  minutesSavedPerSuccess: 15,
  minutesSavedPerFailure: 5,
});

Executions

Executions are read-only records of workflow runs synced from n8n.

// List executions with filters
for await (const ex of client.executions.list({
  clientId: "com_abc123",
  status: "failed",
  startDate: "2025-01-01",
  endDate: "2025-01-31",
})) {
  console.log(ex.workflow_name, ex.status, ex.duration_ms);
}

// Get only errors
for await (const ex of client.executions.list({ errorsOnly: true })) {
  console.log(ex.error_category, ex.workflow_name);
}

// Get execution details (includes error message and payload)
const ex = await client.executions.get("exe_abc123");
console.log(ex.error_message);
console.log(ex.error_payload);

Sync runs

// List sync run history
for await (const run of client.syncRuns.list({ instanceId: "n8n_abc123", status: "failed" })) {
  console.log(run.sync_type, run.status, run.duration_seconds);
}

// Get a specific sync run
const run = await client.syncRuns.get("syn_abc123");

// Get sync health across all instances
const entries = await client.syncRuns.health();
for (const entry of entries) {
  console.log(entry.instance_name, entry.sync_status);
  console.log(`  Workflows last synced: ${entry.workflows.last_synced_at}`);
  console.log(`  Executions last synced: ${entry.executions.last_synced_at}`);
}

Users

// List team members
for await (const user of client.users.list()) {
  console.log(user.name, user.email, user.role);
}

// Get a user
const user = await client.users.get("usr_abc123");

// Invite a new team member
const invitation = await client.users.invite({ email: "[email protected]", role: "member" });
console.log(invitation.expires_at);

// Change a user's role
const updatedUser = await client.users.update("usr_abc123", { role: "admin" });

// Remove a user
await client.users.delete("usr_abc123");

Webhooks

// List webhooks
for await (const wh of client.webhooks.list()) {
  console.log(wh.url, wh.events, wh.enabled);
}

// Create a webhook
const wh = await client.webhooks.create({
  url: "https://example.com/hook",
  events: ["execution.failed", "sync.failed"],
  description: "Slack failure alerts",
});
console.log(wh.secret); // Save this — used to verify webhook signatures

// Update a webhook
await client.webhooks.update("whk_abc123", { enabled: false });

// Regenerate the signing secret (old secret becomes invalid immediately)
const regenerated = await client.webhooks.regenerateSecret("whk_abc123");
console.log(regenerated.secret);

// Delete a webhook
await client.webhooks.delete("whk_abc123");

API tokens

// List all tokens
for await (const token of client.apiTokens.list()) {
  console.log(token.name, token.permission, token.token_hint);
}

// Create a token (the plain token is only returned once)
const token = await client.apiTokens.create({
  name: "CI/CD Pipeline",
  permission: "read",
  ipAllowlist: ["10.0.0.0/8"],
  expiresIn: "90_days",
});
console.log(token.token); // sk_live_... — save this immediately

// Update a token
await client.apiTokens.update("tok_abc123", { name: "Updated Name" });

// Revoke a token
await client.apiTokens.delete("tok_abc123");

LLM providers

Connect your AI provider accounts to track costs.

// List providers
for await (const provider of client.llmProviders.list()) {
  console.log(provider.name, provider.provider_type, provider.sync_status);
}

// Get a provider (includes 7-day metrics)
const provider = await client.llmProviders.get("llm_abc123");
console.log(provider.metrics?.total_cost_cents, provider.metrics?.total_tokens);

// Connect a new provider
const newProvider = await client.llmProviders.create({
  name: "OpenAI Production",
  providerType: "openai", // openai, anthropic, openrouter, or azure
  apiKey: "sk-...",
  organizationId: "org-...",
});

// Trigger a cost sync
await client.llmProviders.sync("llm_abc123");

// Update a provider
await client.llmProviders.update("llm_abc123", { name: "OpenAI Staging" });

// Delete a provider
await client.llmProviders.delete("llm_abc123");

LLM projects

Projects are discovered automatically when syncing a provider. Assign them to clients to attribute costs.

// List projects for a provider
for await (const project of client.llmProjects.list("llm_abc123")) {
  console.log(project.name, project.total_cost_cents, project.client_name);
}

// Assign a project to a client
const project = await client.llmProjects.update("llm_abc123", "proj_456", {
  clientId: "com_abc123",
});

LLM costs

// Get cost summary (defaults to last 7 days)
const costs = await client.llmCosts.summary();
console.log(`Total: $${(costs.data.summary.total_cost_cents / 100).toFixed(2)}`);
console.log(`Tokens: ${costs.data.summary.total_tokens.toLocaleString()}`);

// Breakdown by provider
for (const p of costs.data.providers) {
  console.log(`  ${p.name}: $${(p.cost_cents / 100).toFixed(2)}`);
}

// Breakdown by model
for (const m of costs.data.models) {
  console.log(`  ${m.model}: $${(m.cost_cents / 100).toFixed(2)}`);
}

// Daily trend
for (const day of costs.data.daily) {
  console.log(`  ${day.date}: $${(day.cost_cents / 100).toFixed(2)}`);
}

// Custom date range
const monthlyCosts = await client.llmCosts.summary({
  startDate: "2025-01-01",
  endDate: "2025-01-31",
});

// Costs by client
const byClient = await client.llmCosts.byClient();
for (const entry of byClient.data) {
  console.log(`${entry.name}: $${(entry.cost_cents / 100).toFixed(2)}`);
}

// Costs by provider
const byProvider = await client.llmCosts.byProvider();
for (const entry of byProvider.data) {
  console.log(`${entry.name}: $${(entry.cost_cents / 100).toFixed(2)}`);
}

Pagination

All .list() methods return an async iterator that handles pagination automatically. By default, the API returns 25 items per page (max 100).

// Auto-paginate through all results
for await (const c of client.clients.list()) {
  console.log(c.name);
}

// Control page size
for await (const c of client.clients.list({ perPage: 100 })) {
  console.log(c.name);
}

// Get a single page
const page = await client.clients.list({ perPage: 10 }).firstPage();
console.log(page.meta.total, page.meta.total_pages);
for (const c of page) {
  console.log(c.name);
}

Error handling

The SDK throws typed exceptions for all API errors:

import {
  Administrate,
  APIError,
  AuthenticationError,
  NotFoundError,
  RateLimitError,
  ValidationError,
} from "@administrate.dev/sdk";

const client = new Administrate({ apiKey: "sk_live_..." });

try {
  const c = await client.clients.get("com_nonexistent");
} catch (e) {
  if (e instanceof NotFoundError) {
    console.log(`Not found: ${e.message}`);
  } else if (e instanceof AuthenticationError) {
    console.log("Invalid API key");
  } else if (e instanceof RateLimitError) {
    console.log(`Rate limited. Retry after ${e.retryAfter}s`);
  } else if (e instanceof ValidationError) {
    console.log(`Invalid params: ${JSON.stringify(e.body)}`);
  } else if (e instanceof APIError) {
    console.log(`API error ${e.statusCode}: ${e.message}`);
  }
}

Exception hierarchy:

| Exception | Status code | Description | |---|---|---| | AdministrateError | — | Base exception for all SDK errors | | APIError | Any non-2xx | Base for all HTTP API errors | | AuthenticationError | 401 | Invalid or missing API key | | PermissionDeniedError | 403 | Insufficient token permissions | | NotFoundError | 404 | Resource does not exist | | ValidationError | 422 | Invalid request parameters | | RateLimitError | 429 | Rate limit exceeded (has retryAfter) | | InternalServerError | 5xx | Server-side error | | ConnectionError | — | Failed to connect to the API | | TimeoutError | — | Request timed out |

All APIError subclasses expose statusCode and body (parsed JSON or text).

Retries

The SDK automatically retries failed requests with exponential backoff:

  • 429 (rate limited) — Retries after the duration specified in the Retry-After header
  • 5xx (server errors) — Retries with exponential backoff (500ms, 1s, 2s, ...)
  • Connection errors and timeouts — Retried with the same backoff schedule

By default, the SDK retries up to 3 times. Set maxRetries: 0 to disable:

const client = new Administrate({ apiKey: "sk_live_...", maxRetries: 0 });

Requirements

  • Node.js 18+ (or any runtime with native fetch: Deno, Bun, Cloudflare Workers)
  • Zero runtime dependencies

License

MIT