Use DVARA from JavaScript and TypeScript
Point an OpenAI-compatible JavaScript client at DVARA when your application needs policy, PII controls, audit evidence, and cost attribution around model calls. The client API stays familiar; DVARA governs each request before it reaches a configured provider.
Send your first governed request
You need a running DVARA deployment, a registered provider that serves the model in your request, and a workspace API key. Follow the Quickstart if you do not have them yet.
Set the connection outside your source code:
export DVARA_BASE_URL="http://localhost:8080/v1"
export DVARA_API_KEY="<your-dvara-api-key>"
npm install openai
Use a key with completions:write. A key with no scopes is unrestricted, but a
key with any scopes can call only the endpoint families named by those scopes.
See Authenticate data-plane calls
for the full map.
The OpenAI JavaScript client can return the parsed body and the HTTP headers together, which lets you keep DVARA's trace ID:
import OpenAI from "openai";
const client = new OpenAI({
baseURL: process.env.DVARA_BASE_URL,
apiKey: process.env.DVARA_API_KEY,
});
const { data, response } = await client.chat.completions
.create({
model: "gpt-4o",
messages: [
{ role: "system", content: "Answer in one sentence." },
{ role: "user", content: "Why should an API key be rotated?" },
],
max_tokens: 80,
})
.withResponse();
console.log(data.choices[0].message.content);
console.log("DVARA trace:", response.headers.get("x-trace-id"));
Example output:
Regular rotation limits the time a leaked API key can be used.
DVARA trace: 043793a6ac754c9c9d1bc5d4f525f827
The wording and token counts vary by model. When audit storage is configured,
search for the trace ID in Flightdeck or your audit output. The completed call
has a GATEWAY_RESPONSE event with its model, provider, outcome, and available
usage data.
The model must be served by a provider registered in your DVARA deployment.
Use GET /v1/models to inspect the current provider result, then use the exact
identifier your deployment exposes.
Stream a Chat Completions response
const stream = await client.chat.completions.create({
model: "gpt-4o",
messages: [
{
role: "user",
content: "Write a two-line release note about key rotation.",
},
],
max_tokens: 80,
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}
process.stdout.write("\n");
Streaming response enforcement follows the workspace's configured streaming posture. It is not the same as buffering and scanning a complete non-streaming response. See Streaming before using a stream for regulated content.
Use the Responses API
DVARA supports text and image input, instructions, metadata, structured
output through text.format, your own function tools with tool_choice
(from 1.9.0), and synchronous or streaming Responses API calls. The same
completions:write scope covers this endpoint.
const { data, response } = await client.responses
.create({
model: "gpt-4o",
instructions: "Answer in one sentence.",
input: "Name one practical reason to keep an AI audit trail.",
})
.withResponse();
console.log(data.output_text);
console.log("DVARA trace:", response.headers.get("x-trace-id"));
The endpoint is stateless. It refuses store: true,
previous_response_id, reusable prompt objects, background mode, built-in
tools such as web search, any include other than
reasoning.encrypted_content, and a service_tier other than auto or
default, with HTTP 400 and unsupported_capability. When the model returns
a function call, your application or agent framework still executes the
function.
Request structured JSON
Use a JSON Schema on Chat Completions when the configured provider supports it:
const result = await client.chat.completions.create({
model: "gpt-4o",
messages: [
{
role: "user",
content: "Return two controls for protecting API keys.",
},
],
response_format: {
type: "json_schema",
json_schema: {
name: "api_key_controls",
strict: true,
schema: {
type: "object",
properties: {
controls: {
type: "array",
items: {
type: "object",
properties: {
name: { type: "string" },
reason: { type: "string" },
},
required: ["name", "reason"],
additionalProperties: false,
},
},
},
required: ["controls"],
additionalProperties: false,
},
},
},
});
console.log(JSON.parse(result.choices[0].message.content ?? "{}"));
DVARA validates the request shape and passes the schema to the selected provider. Provider support still determines whether that model can produce a strict structured response. See Structured outputs for the provider matrix and failure behavior.
Receive a function call
Chat Completions accepts OpenAI-style function definitions. DVARA governs the model call and, when configured, scans tool-call arguments. It does not execute the JavaScript function.
const result = await client.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: "Multiply 42 by 17." }],
tools: [
{
type: "function",
function: {
name: "multiply",
description: "Multiply two integers.",
parameters: {
type: "object",
properties: {
a: { type: "integer" },
b: { type: "integer" },
},
required: ["a", "b"],
additionalProperties: false,
},
},
},
],
tool_choice: "auto",
});
const call = result.choices[0].message.tool_calls?.[0];
if (call?.type === "function") {
console.log(call.function.name, JSON.parse(call.function.arguments));
}
Expected shape:
multiply { a: 42, b: 17 }
Validate the arguments and authorize the action before executing a tool. A model-generated function call is a proposal, not a trusted instruction.
Create embeddings
An embeddings call needs embeddings:write when the key has a nonempty scope
list. The embedding model must be available through a configured provider.
const response = await client.embeddings.create({
model: "text-embedding-3-small",
input: [
"Rotate provider credentials every 90 days.",
"Review failed authentication events each day.",
],
});
console.log(response.data.length, "vectors");
console.log(response.data[0].embedding.length, "dimensions");
The vector dimension is controlled by the model. DVARA applies configured request-side controls and records available usage, but it does not run model-text response scans over numeric vectors.
Call Anthropic, Bedrock, or Gemini models
DVARA exposes an OpenAI-compatible client surface. Keep using the OpenAI JavaScript client and change the model identifier to one served by your configured Anthropic, Amazon Bedrock, or Google provider:
for (const model of [
"<anthropic-model>",
"<bedrock-model>",
"<gemini-model>",
]) {
const result = await client.chat.completions.create({
model,
messages: [{ role: "user", content: "Reply with the provider name." }],
max_tokens: 30,
});
console.log(model, result.choices[0].message.content);
}
Replace each placeholder with an identifier returned by your deployment.
The Bedrock Converse request shape is not a DVARA endpoint. From 1.9.0 the
Google GenAI SDK can keep its own shape: set its base URL to
<gateway>/v1/gemini and its API key to a DVARA workspace key. See
Govern Gemini CLI, which uses the same endpoint.
From 1.8.5 the Anthropic SDK can keep its own shape: DVARA serves the Anthropic
Messages API at /v1/messages. Set the SDK's baseURL to the Gateway, with no
/v1, and its API key to a DVARA workspace key. See
Govern Claude Code, which uses the same endpoint.
Connect the AI SDK
Use the AI SDK's OpenAI-compatible provider so the transport targets Chat Completions explicitly. This avoids assuming that DVARA implements every provider-specific OpenAI Responses feature.
npm install ai @ai-sdk/openai-compatible
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
import { generateText, streamText } from "ai";
const dvara = createOpenAICompatible({
name: "dvara",
baseURL: process.env.DVARA_BASE_URL!,
apiKey: process.env.DVARA_API_KEY!,
includeUsage: true,
});
const { text } = await generateText({
model: dvara("gpt-4o"),
prompt: "Give one reason to retain model-call evidence.",
});
console.log(text);
const result = streamText({
model: dvara("gpt-4o"),
prompt: "Write a two-line release note about key rotation.",
});
for await (const chunk of result.textStream) {
process.stdout.write(chunk);
}
Handle a refusal
DVARA uses one error envelope for authentication, policy, budget, provider, and
validation failures. Keep the trace_id; it connects the application failure
to DVARA logs and, when configured, audit evidence.
import OpenAI from "openai";
try {
const result = await client.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: "Summarize this contract." }],
});
console.log(result.choices[0].message.content);
} catch (error) {
if (!(error instanceof OpenAI.APIError)) throw error;
const body = (error.error ?? {}) as {
code?: string;
message?: string;
trace_id?: string;
};
console.error(`HTTP ${error.status}: ${body.code} — ${body.message}`);
console.error("DVARA trace:", body.trace_id);
}
For example, a valid key scoped only to models:read receives HTTP 403 with
type: "permission_error" and code: "api_key_scope". See
Error handling for the complete status and
error-code contract.
Continue the integration
- Add request context with DVARA headers.
- Review endpoint boundaries in the LLM API overview.
- Integrate Python or Java.
- Plan a client move with the Migration guide.