Use DVARA from Java
Point an OpenAI-compatible Java client at DVARA when your service 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 source control:
export OPENAI_BASE_URL="http://localhost:8080/v1"
export OPENAI_API_KEY="<your-dvara-api-key>"
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 complete map.
Add the official OpenAI Java client:
<dependency>
<groupId>com.openai</groupId>
<artifactId>openai-java</artifactId>
<version>4.68.0</version>
</dependency>
The client reads OPENAI_BASE_URL and OPENAI_API_KEY. A raw response keeps
DVARA's trace header alongside the parsed Chat Completions body:
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.http.HttpResponseFor;
import com.openai.models.chat.completions.ChatCompletion;
import com.openai.models.chat.completions.ChatCompletionCreateParams;
OpenAIClient client = OpenAIOkHttpClient.fromEnv();
ChatCompletionCreateParams params = ChatCompletionCreateParams.builder()
.model("gpt-4o")
.addSystemMessage("Answer in one sentence.")
.addUserMessage("Why should an API key be rotated?")
.maxTokens(80L)
.build();
HttpResponseFor<ChatCompletion> raw = client.chat().completions()
.withRawResponse()
.create(params);
ChatCompletion completion = raw.parse();
System.out.println(completion.choices().get(0).message().content().orElse(""));
System.out.println("DVARA trace: "
+ raw.headers().values("x-trace-id").stream().findFirst().orElse("missing"));
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
import com.openai.core.http.StreamResponse;
import com.openai.models.chat.completions.ChatCompletionChunk;
ChatCompletionCreateParams streamParams = ChatCompletionCreateParams.builder()
.model("gpt-4o")
.addUserMessage("Write a two-line release note about key rotation.")
.maxTokens(80L)
.build();
try (StreamResponse<ChatCompletionChunk> stream =
client.chat().completions().createStreaming(streamParams)) {
stream.stream()
.flatMap(chunk -> chunk.choices().stream())
.flatMap(choice -> choice.delta().content().stream())
.forEach(System.out::print);
}
System.out.println();
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 1.8 supports basic text and image input, instructions, metadata,
structured output through text.format, and synchronous or streaming Responses
API calls. The same completions:write scope covers this endpoint.
import com.openai.models.responses.Response;
import com.openai.models.responses.ResponseCreateParams;
ResponseCreateParams responseParams = ResponseCreateParams.builder()
.model("gpt-4o")
.instructions("Answer in one sentence.")
.input("Name one practical reason to keep an AI audit trail.")
.build();
Response response = client.responses().create(responseParams);
response.output().stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.text()));
The 1.8 endpoint is stateless. It refuses store: true,
previous_response_id, reusable prompt objects, reasoning items, background
mode, include, tools, and tool_choice with HTTP 400 and
unsupported_capability. Use Chat Completions when the model must return a
function call; your application or agent framework still executes the
function.
Call Anthropic, Bedrock, or Gemini models
DVARA exposes an OpenAI-compatible client surface. Keep using the OpenAI Java client and change the model identifier to one served by your configured Anthropic, Amazon Bedrock, or Google provider:
for (String model : List.of(
"<anthropic-model>", "<bedrock-model>", "<gemini-model>")) {
ChatCompletion result = client.chat().completions().create(
ChatCompletionCreateParams.builder()
.model(model)
.addUserMessage("Reply with the provider name.")
.maxTokens(30L)
.build());
System.out.println(model + ": "
+ result.choices().get(0).message().content().orElse(""));
}
Replace each placeholder with an identifier returned by your deployment. Native Anthropic Messages, Bedrock Converse, and Google GenAI SDK request shapes are not DVARA endpoints.
Connect LangChain4j
Use LangChain4j's OpenAI-compatible model and the full DVARA /v1 base URL:
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>1.20.0</version>
</dependency>
import dev.langchain4j.model.openai.OpenAiChatModel;
OpenAiChatModel model = OpenAiChatModel.builder()
.baseUrl(System.getenv("OPENAI_BASE_URL"))
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("gpt-4o")
.build();
String answer = model.chat("Give one reason to retain model-call evidence.");
System.out.println(answer);
LangChain4j agents use Chat Completions function calling through this model. The agent process executes each selected tool, so enforce tool authorization there as well as any configured DVARA governance.
Connect Spring AI
Use Spring AI's current OpenAI model starter. Manage its version through the Spring AI BOM used by your application:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
Spring AI appends /v1/chat/completions to base-url. Set the DVARA origin,
not the /v1 client base used by the official OpenAI SDK:
spring:
ai:
openai:
base-url: http://localhost:8080
api-key: ${DVARA_API_KEY}
chat:
options:
model: gpt-4o
temperature: 0
Call it through ChatClient:
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
@Service
public class GovernedChatService {
private final ChatClient chatClient;
public GovernedChatService(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
public String answer(String question) {
return chatClient.prompt().user(question).call().content();
}
public Flux<String> stream(String question) {
return chatClient.prompt().user(question).stream().content();
}
}
Spring AI retries independently of DVARA. Its OpenAI client currently defaults
to three retries. Set spring.ai.openai.max-retries deliberately so one
application action does not create more provider attempts than your reliability
and cost policy allows.
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. Use
the official SDK's client.embeddings() service or the corresponding framework
model with the same DVARA base URL and key.
DVARA applies configured request-side controls and records available usage, but it does not run model-text response scans over numeric vectors. The vector dimension is controlled by the selected model.
Handle a refusal
DVARA uses one error envelope for authentication, policy, budget, provider, and
validation failures. The official Java client raises OpenAIServiceException
for a non-success response:
import com.openai.errors.OpenAIServiceException;
try {
ChatCompletion result = client.chat().completions().create(params);
System.out.println(result.choices().get(0).message().content().orElse(""));
} catch (OpenAIServiceException exception) {
System.err.println("DVARA refused the request: HTTP " + exception.statusCode());
System.err.println(exception.body());
}
Parse the returned DVARA error envelope in your service's normal HTTP error
layer and retain its trace_id. For example, a valid key scoped only to
models:read receives HTTP 403, type: "permission_error", and
code: "api_key_scope". See
Error handling for the complete contract.
Continue the integration
- Add request context with DVARA headers.
- Review endpoint boundaries in the LLM API overview.
- Integrate Python or JavaScript and TypeScript.
- Plan a client move with the Migration guide.