Skip to main content
Sign in →
API & SDK

TypeScript SDK

The official @shieldagent/sdk package provides a typed client for the ShieldAgent REST API. Works in Node.js 18+ and modern bundlers.

Installation

Not yet on npm

The @shieldagent/sdk package has not been published to npm yet. Install from the source repository:

bash
git clone https://github.com/shieldagent-io/shieldagent.git
npm install ./shieldagent/backend/packages/sdk-ts

Quick start

example.ts
import { ShieldAgentClient } from '@shieldagent/sdk';

const client = new ShieldAgentClient({
  apiKey: '{your-api-key}',
  baseUrl: 'https://api.shieldagent.io',
});

// List agents for a tenant
const agents = await client.agents.list({ tenantId: 'ten_abc123' });
console.log(agents);

// Register a new agent
const agent = await client.agents.create({
  tenantId: 'ten_abc123',
  name: 'my-assistant',
  description: 'Coding assistant agent',
});
console.log(agent.agentKey); // sa_live_...

// Fetch recent audit events
const events = await client.audit.list({
  tenantId: 'ten_abc123',
  limit: 50,
  order: 'desc',
});

Proxy-forwarding API calls

Use client.apiProxy() to route agent REST calls through ShieldAgent. Every request is authenticated, policy-checked, DLP-scanned, and audit-logged before being forwarded to the registered upstream.

proxy-examples.ts
import { ShieldAgentClient, ForbiddenError, RateLimitError, BadGatewayError } from '@shieldagent/sdk';

const client = new ShieldAgentClient({
  apiKey: '{your-agent-key}',              // agent key, not admin key
  baseUrl: 'https://proxy.shieldagent.io',
});

// ── POST through the proxy ─────────────────────────────────────────────────
const charge = await client.apiProxy('stripe', {
  method: 'POST',
  path: '/charges',
  body: { amount: 2000, currency: 'usd', source: 'tok_visa' },
});

// ── GET a specific resource ────────────────────────────────────────────────
const customer = await client.apiProxy('stripe', {
  method: 'GET',
  path: '/customers/cus_abc123',
});

// ── Send a Slack message ───────────────────────────────────────────────────
await client.apiProxy('slack', {
  method: 'POST',
  path: '/chat.postMessage',
  body: { channel: '#alerts', text: 'Anomaly detected on agent my-assistant' },
});

// ── Call an internal microservice ─────────────────────────────────────────
const result = await client.apiProxy('order-service', {
  method: 'POST',
  path: '/orders',
  body: { customerId: 'cust_42', items: [{ sku: 'ABC', qty: 1 }] },
});

// ── Error handling ─────────────────────────────────────────────────────────
try {
  await client.apiProxy('stripe', { method: 'DELETE', path: '/charges/ch_123' });
} catch (err) {
  if (err instanceof ForbiddenError) {
    // Policy denied the call — ShieldAgent blocked it
    console.error('Blocked by policy:', err.code, err.message);
  } else if (err instanceof RateLimitError) {
    // Per-tenant rate limit exceeded
    console.error('Rate limited. Retry after:', err.retryAfter);
  } else if (err instanceof BadGatewayError) {
    // Upstream unreachable or returned 5xx
    console.error('Upstream error:', err.message);
  }
}

Verdict API — scan & confirm

Use client.scan() to submit a tool call to ShieldAgent before executing it. The proxy returns a verdict (allow / block / human_review) but does not enforce it — your code must check the verdict and block execution when the action is "block". Call client.confirmExecution() afterwards to close the audit loop and support EU AI Act Art. 9 compliance claims.

When the proxy runs on a different host from the Management API, pass proxyUrl to the client constructor.

verdict-api.ts
import { ShieldAgentClient } from '@shieldagent/sdk';

const client = new ShieldAgentClient({
  apiKey: '{your-agent-key}',
  baseUrl: 'https://api.shieldagent.io',      // Management API
  proxyUrl: 'https://proxy.shieldagent.io',   // Proxy (omit if same host)
});

// ── 1. Scan before executing ───────────────────────────────────────────────
const verdict = await client.scan({
  tenantId: 'ten_abc123',
  toolName: 'read_file',
  params: { path: '/etc/passwd' },
  agentId: 'agt_xyz789',           // optional — improves policy matching
  includeFindings: true,           // optional — request detailed findings
});

// IMPORTANT: YOU must enforce the verdict. ShieldAgent does not block the call.
if (verdict.action === 'block') {
  throw new Error(`Tool call blocked: ${verdict.reason}`);
}
if (verdict.action === 'human_review') {
  // Pause and wait for a human reviewer to approve via the dashboard
  throw new Error(`Tool call requires human review (reviewId: ${verdict.reviewId})`);
}

// ── 2. Execute the tool ────────────────────────────────────────────────────
const fileContent = await readFile('/etc/passwd');

// ── 3. Confirm execution to close the audit loop ───────────────────────────
await client.confirmExecution('ten_abc123', verdict.auditEventId, {
  executed: true,
});

// ── Verdict shape ──────────────────────────────────────────────────────────
// verdict.action        — 'allow' | 'block' | 'human_review'
// verdict.reason        — human-readable explanation
// verdict.riskScore     — 0–100 risk score at scan time
// verdict.auditEventId  — use with confirmExecution()
// verdict.reviewId      — review ID when action is 'human_review', else null
// verdict.findings[]    — detailed findings (only when includeFindings: true)

Policy management

policies.ts
// Apply a policy template (e.g. "pii-protection") to a tenant
const result = await client.policyTemplates.apply('ten_abc123', 'pii-protection');
console.log(`Created ${result.policiesCreated} policies from template "${result.templateName}"`);

// Create a custom deny rule — block DELETE on the Stripe endpoint for a specific agent
await client.policies.create('ten_abc123', {
  agentId: agent.id,
  toolName: 'rest:stripe',
  action: 'deny',
  conditions: { method: 'DELETE' },
});

// List active policies for an agent
const policies = await client.policies.list('ten_abc123', { agentId: agent.id });
console.log(policies.data);

Risk monitoring & anomaly detection

risk.ts
// Get current risk scores for all agents
const scores = await client.risk.list('ten_abc123');
const highRisk = scores.data.filter(s => s.riskTier === 'high' || s.riskTier === 'critical');
console.log('High-risk agents:', highRisk.map(s => s.agentName));

// Drill into a specific agent's risk trend
const detail = await client.risk.getDetail('ten_abc123', agent.id);
console.log(`Risk: ${detail.score} (${detail.trend}) — delta 24h: ${detail.deltaVs24h}`);

// Analyze a batch of recent events for anomalies
const anomalies = await client.anomalies.analyzeBatch('ten_abc123', {
  agentId: agent.id,
  windowHours: 24,
});
if (anomalies.anomaliesDetected > 0) {
  console.warn('Anomalies detected:', anomalies.results);
}

Incident & review workflows

incidents.ts
// Open an incident when a critical threat is detected
const incident = await client.incidents.create('ten_abc123', {
  agentId: agent.id,
  title: 'Prompt injection detected in session ses_xyz',
  severity: 'critical',
  type: 'injection',
  data: { sessionId: 'ses_xyz', payload: '...' },
});

// Move incident to "investigating"
await client.incidents.update(incident.id, { status: 'investigating' });

// Process the human-review queue — approve or deny pending tool calls
const pending = await client.reviews.list('ten_abc123', { status: 'pending' });
for (const review of pending.data) {
  const decision = review.toolName.startsWith('rest:stripe') ? 'denied' : 'approved';
  await client.reviews.decide(review.id, { decision, comment: 'Reviewed by on-call' });
}

Error handling

Typed error classes

ForbiddenError403 — ShieldAgent policy blocked the call. Check err.code for the matching rule ID.
RateLimitError429 — Per-tenant or per-agent rate limit exceeded. err.retryAfter gives the reset timestamp.
BadGatewayError502 — Upstream service unreachable or returned 5xx. Safe to retry with backoff.
ShieldAgentErrorBase class for all SDK errors. err.status · err.code · err.message always present.
typescript
import { ShieldAgentError } from '@shieldagent/sdk';

try {
  await client.agents.create({ tenantId: 'bad-id', name: 'x' });
} catch (err) {
  if (err instanceof ShieldAgentError) {
    console.error(err.status, err.code, err.message);
  }
}

Available resources

client.tenantslist, create, update, delete
client.agentslist, create, update, delete, rotateKey
client.policieslist, create, update, delete, activate
client.policyTemplateslist, apply
client.auditlist, verify
client.risklist, getDetail, calculate
client.compliancelistReports, generateReport
client.incidentslist, create, update, getCounts
client.alertslist, create, update, delete, listEvents
client.anomaliesanalyze, analyzeBatch, listEvents
client.reviewslist, decide, getCounts
client.apiProxy()GET, POST, PUT, PATCH, DELETE → upstream
client.scan()submit tool call for security verdict
client.confirmExecution()close audit loop after verdict