Skip to main content
Coming soon. @wardin/sdk is not yet published to npm — the interface documented here is final and ships with the v1 launch. Until then npm install @wardin/sdk won’t resolve.
A typed TypeScript client for the Wardin control-plane REST API, with resource-method ergonomics (wardin.receipts.list()). Every path, parameter, and response is generated from the same OpenAPI spec that powers the API Reference — so the client can’t drift from the contract.

Install

npm install @wardin/sdk
Requirements: Node.js ≥ 18 (uses the global fetch). The package is ESM-only (import, not require).

Quickstart

import { createWardinClient } from '@wardin/sdk';

const wardin = createWardinClient({ apiKey: process.env.WARDIN_API_KEY! }); // wardin_sk_...

// List virtual keys
const keys = await wardin.keys.list();

// Create a key with a monthly budget + rate limit
await wardin.keys.create({
  label: 'alice-dev',
  keyClass: 'interactive',
  budgetUsd: 50,
  rpmLimit: 60,
});

// Fetch a receipt — verified server-side (ED25519 signature + hash chain)
const receipt = await wardin.receipts.get(receiptId);
receipt.verified; // true

// Filter the signed receipt chain
const recent = await wardin.receipts.list({ actor: 'alice', provider: 'anthropic' });

Authentication

Pass a secret API key (wardin_sk_...); it’s sent as Authorization: Bearer. Create one with POST /v1/keys or in the Console. Treat it as a secret — server-side only, never ship it to a browser.

Configuration

createWardinClient({
  apiKey: process.env.WARDIN_API_KEY!,
  // Defaults to https://api.wardin.ai. Point at your own deployment, or
  // http://localhost:3000/api in local dev (the API serves the /api prefix).
  baseUrl: 'https://api.wardin.ai',
});

Resources

Every method is fully typed (request body, params, response). On a non-2xx response a method throws WardinApiError; on success it returns the parsed body. Each method maps to a REST endpoint in the API Reference.
ResourceMethods
wardin.keyslist() · create(body) · delete(id) · setLimits(id, body) · assign(id, body)
wardin.budgetslist() · update(id, body)
wardin.policieslist() · create(body) · delete(id)
wardin.providerslist() · test(provider)
wardin.receiptslist(query?) · get(id) · verifyChain(id, query) · export(query?)string
wardin.complianceframeworks() · coverage(framework) · evidenceBundle(query?)
A budget is created together with a key (keys.create with budgetUsd) — there is no standalone create, so budgets exposes only list + update. receipts.export(query?) returns the matched set as a raw JSONL/CSV string (pass { format: 'jsonl' | 'csv' } plus the same filters as receipts.list).

Common operations

Create a virtual key with a monthly budget and rate limit:
const { id } = await wardin.keys.create({
  label: 'ci-pipeline',
  keyClass: 'ci', // 'interactive' | 'ci'
  budgetUsd: 100,
  rpmLimit: 120,
});
Filter the signed receipt chain — every gateway request is a queryable receipt:
const recent = await wardin.receipts.list({
  actor: 'alice',
  provider: 'anthropic',
  from: '2026-07-01T00:00:00Z',
  limit: 50,
});
Export evidence for an auditor — a filtered JSONL stream, or a self-contained, offline-verifiable bundle:
const jsonl = await wardin.receipts.export({ format: 'jsonl', from: '2026-07-01T00:00:00Z' });
const bundle = await wardin.compliance.evidenceBundle({ range: '30d' });
Check framework coverage across the receipt chain:
const frameworks = await wardin.compliance.frameworks();
const euAiAct = await wardin.compliance.coverage('eu_ai_act');
Verify a receipt was signed and unbroken in the chain:
const receipt = await wardin.receipts.get(receiptId);
if (!receipt.verified) throw new Error('receipt failed verification');

Pagination

receipts.list is cursor-paginated, newest first. Each response returns nextCursor for the following page (absent once you reach the end) — loop until it’s gone:
let cursor: number | undefined;
const all = [];
do {
  const page = await wardin.receipts.list({ limit: 100, cursor });
  all.push(...page.receipts);
  cursor = page.nextCursor ?? undefined;
} while (cursor);
The same filters (from, to, actor, provider, model, check, upstreamStatus) apply to every page. For a large historical pull, prefer receipts.export() — it streams the whole matched set in one call.

Error handling

import { WardinApiError } from '@wardin/sdk';

try {
  await wardin.keys.create({ label: '', keyClass: 'interactive', budgetUsd: 50 });
} catch (e) {
  if (e instanceof WardinApiError) {
    console.error(e.status, e.body); // HTTP status + typed error body
  }
}

Escape hatch — any endpoint

Any endpoint not wrapped as a resource method is reachable on wardin.raw, the underlying openapi-fetch client. It returns { data, error } (it does not throw) and is fully typed:
const { data, error } = await wardin.raw.GET('/v1/usage', {
  params: { query: { period: '2026-07' } },
});

Offline evidence verification

This SDK drives the control plane. To verify a tenant’s signed receipt chain offline, without trusting Wardin, export an Evidence Bundle (wardin.compliance.evidenceBundle()) and check it with the open-source wardin-verify CLI — see Offline Verification.

Versioning

The SDK follows semantic versioning. Its types are generated from the committed OpenAPI spec (app DTOs → openapi.json → SDK), and a CI gate fails on any drift, so a published version always matches the contract it was built against. Breaking changes to the /v1 contract ship as a new major with release notes.

Other languages

TypeScript is the first SDK. Python and Go clients are planned — until then, any language can call the REST API directly, or generate a client from the OpenAPI spec.