Skip to content

TypeScript SDK

The official TypeScript SDK for the InPolicy governance API. Adds type safety, automatic retries on 5xx/network errors, and a clean ergonomic surface.

Terminal window
npm install @inpolicy/sdk
import { InPolicyClient } from '@inpolicy/sdk';
const ip = new InPolicyClient({
apiKey: process.env.INPOLICY_API_KEY!,
// all optional:
baseUrl: 'https://api.inpolicy.ai',
timeoutMs: 30_000,
maxRetries: 2,
userAgent: 'my-support-agent/1.4.0',
});

One client per API key; safe to reuse across requests.

const result = await ip.recordTurn({
sessionId: 'sess_abc',
turn: { role: 'user', content: "I'm 16 — can I buy this?" },
});
console.log(result.activePolicies); // what's active now
console.log(result.injectionBlock); // paste into your system prompt
console.log(result.diff.newlyApplicable); // what just became active

The full RecordTurnInput shape:

{
sessionId: string;
turn: { role: 'user' | 'assistant' | 'tool'; content: string };
recentContext?: string[]; // last 2-3 prior turns, for disambiguation
priorHistory?: string[]; // bootstrap on first call only
endUserContext?: {
ephemeralId?: string;
attributes?: Record<string, unknown>; // { role: 'support_agent', region: 'EU' }
};
policyAreaIds?: string[]; // scope to specific areas
tokenBudget?: number; // injection_block size, default 600
idempotencyKey?: string; // retries within 5 min return cached
checkOutput?: boolean; // only when role='assistant'
ttlSeconds?: number; // override 4h default
}
// Requires post_inference_checking: 'allowed' on the API key
const check = await ip.postInference({
output: draft,
sessionId: 'sess_abc',
});
if (!check.safe) {
if (check.suggestedRedaction) {
return check.suggestedRedaction; // use the remediated text
}
// Otherwise regenerate with stronger prompting
}
// Requires tool_call_governance: 'allowed' on the API key
const ok = await ip.checkToolCall({
sessionId: 'sess_abc',
toolName: 'send_email',
arguments: { to: 'customer@...', subject: '...', body: '...' },
});
if (!ok.allow) {
return `I can't send that email — ${ok.violations[0].explanation}`;
}
await actuallySendEmail();
const snapshot = await ip.getConversationState('sess_abc');
// { turnCount, activePolicies, injectionBlock, bindingLog, updatedAt }
await ip.endConversation('sess_abc'); // purge Redis state, idempotent
import { InPolicyApiError } from '@inpolicy/sdk';
try {
await ip.recordTurn({ ... });
} catch (err) {
if (err instanceof InPolicyApiError) {
if (err.status === 403) {
// Feature gate disabled on the API key (e.g. tried checkOutput without the setting)
} else if (err.status === 429) {
// Rate limited. The SDK retries 5xx automatically but not 429.
} else if (err.status >= 500) {
// SDK already retried `maxRetries` times (default 2)
}
}
// network / timeout errors also reach here, not wrapped in InPolicyApiError
}

The SDK retries:

  • ✅ 5xx responses
  • ✅ Network errors (DNS, connection refused, TCP reset)
  • ✅ Timeouts
  • ❌ 4xx responses (your code is wrong, retrying won’t help)
  • ❌ 429 (backing off is your responsibility; we don’t want to make the rate-limit situation worse)

Exponential backoff with jitter: 100ms, 200ms, 400ms, … capped at 2000ms. Tune with maxRetries (default 2, giving 3 total attempts).

import { InPolicyClient } from '@inpolicy/sdk';
import OpenAI from 'openai';
const ip = new InPolicyClient({ apiKey: process.env.INPOLICY_API_KEY! });
const openai = new OpenAI();
class Conversation {
constructor(public sessionId = crypto.randomUUID()) {}
async say(userMessage: string): Promise<string> {
const pre = await ip.recordTurn({
sessionId: this.sessionId,
turn: { role: 'user', content: userMessage },
});
const res = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [
{ role: 'system', content: `You are a support agent.\n\n${pre.injectionBlock}` },
{ role: 'user', content: userMessage },
],
});
const output = res.choices[0].message.content ?? '';
await ip.recordTurn({
sessionId: this.sessionId,
turn: { role: 'assistant', content: output },
});
return output;
}
async end() {
await ip.endConversation(this.sessionId);
}
}
const chat = new Conversation();
console.log(await chat.say("I'm 16 — can I buy this?"));
console.log(await chat.say("Okay, can I at least see the product page?"));
await chat.end();

Python support is on the roadmap. In the meantime, call the REST API directly. The shape is the same as documented in the API reference, and Python requests/httpx work fine.