AI compatibility quickstart
Create a runtime, start a budgeted session, wrap an OpenAI-compatible client, track a tool, and flush exported events.
Quickstart
This is the smallest end-to-end shape for the current public TypeScript SDK.
1. Install
npm install captar openai2. Create the runtime
import OpenAI from 'openai';
import { createCaptar } from 'captar';
const client = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
const captar = createCaptar({
project: 'support-bot',
controlPlane: {
hookId: process.env.CAPTAR_HOOK_ID!,
baseUrl: process.env.CAPTAR_CONTROL_PLANE_URL,
syncPolicy: true,
},
});If you do not want hosted policy sync or ingestion yet, omit controlPlane and start with local runtime
control.
3. Start a session
const session = await captar.startSession({
budget: {
maxSpendUsd: 1,
finalizationReserveUsd: 0.1,
maxRepeatedCalls: 3,
},
metadata: {
feature: 'support-chat',
},
policy: {
call: {
allowedModels: ['gpt-4.1-mini'],
maxEstimatedCostUsd: 0.5,
maxOutputTokens: 300,
retriesCeiling: 1,
},
tool: {
allowedTools: ['zendesk.createComment'],
maxCallsPerSession: 2,
},
},
});4. Wrap the provider client
const openai = captar.wrapOpenAI(client, { session });
const response = await openai.responses.create({
model: 'gpt-4.1-mini',
input: 'Help me answer this support ticket.',
max_output_tokens: 200,
});Before the provider call, Captar estimates cost, evaluates policy, and reserves session budget. After the response, it records provider usage and reconciles the reservation against actual cost.
5. Track an external tool
const tool = captar.trackTool('zendesk.createComment', {
session,
args: { ticketId: 'ticket_123' },
estimate: 0.02,
});
await tool.run(async () => {
return { ok: true };
});Tool execution shares the same session/trace context and emits started, completed, blocked, or failed lifecycle events.
6. Close and flush
await session.close();
await captar.flush();flush() is especially useful in scripts, jobs, serverless handlers, or other short-lived processes where
you do not want pending export work to be abandoned.
OpenRouter
Use an OpenRouter-configured OpenAI client and set the provider identity explicitly:
const openrouter = captar.wrapOpenAI(openrouterClient, {
session,
provider: 'openrouter',
});
await openrouter.chat.completions.create({
model: 'openrouter/free',
messages: [{ role: 'user', content: 'Hello' }],
});When an OpenAI-compatible provider supplies an authoritative numeric usage.cost, Captar uses it as the
actual committed USD cost. Otherwise the pricing registry remains the fallback.