Java & Spring Boot Integration
Keeptrusts exposes an OpenAI-compatible HTTP API. Any Java HTTP client that can POST JSON to an endpoint can route through the gateway — no proprietary SDK required.
Use this page when
- You are connecting a Spring Boot application to the Keeptrusts gateway for policy-enforced AI calls.
- You need RestTemplate, WebClient, or Spring AI patterns pointing at the gateway's OpenAI-compatible endpoint.
- You want to handle policy blocks (HTTP 409) with proper exception handling in Spring.
- You need a Spring Boot Actuator health indicator for gateway connectivity.
Primary audience
- Primary: Technical Engineers
- Secondary: AI Agents, Technical Leaders
How it works
Spring Boot app
→ HTTP client (base URL pointed at Keeptrusts)
→ kt gateway (policy evaluation)
→ upstream LLM provider
→ response (redacted / enriched per policy)
Prerequisites
- Keeptrusts CLI installed and a running gateway (
kt gateway run) - A valid gateway key (
kt_gk_...) - Java 17+ and Spring Boot 3.x
RestTemplate integration
Configure a RestTemplate bean pointing at the gateway:
@Configuration
public class KeeptrustsConfig {
@Value("${keeptrusts.gateway.url:http://localhost:41002/v1}")
private String gatewayUrl;
@Value("${keeptrusts.gateway.key}")
private String gatewayKey;
@Bean
public RestTemplate keeptrustsRestTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(
new DefaultUriBuilderFactory(gatewayUrl));
restTemplate.getInterceptors().add((request, body, execution) -> {
request.getHeaders().setBearerAuth(gatewayKey);
return execution.execute(request, body);
});
return restTemplate;
}
}
Calling the completions endpoint
@Service
public class GovernedChatService {
private final RestTemplate restTemplate;
public GovernedChatService(
@Qualifier("keeptrustsRestTemplate") RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public String complete(String userMessage) {
Map<String, Object> body = Map.of(
"model", "gpt-4o",
"messages", List.of(Map.of("role", "user", "content", userMessage))
);
ResponseEntity<Map> response = restTemplate.postForEntity(
"/chat/completions", body, Map.class);
List<Map<String, Object>> choices =
(List<Map<String, Object>>) response.getBody().get("choices");
Map<String, Object> message =
(Map<String, Object>) choices.get(0).get("message");
return (String) message.get("content");
}
}
WebClient (reactive) integration
For non-blocking calls, configure a WebClient:
@Configuration
public class KeeptrustsReactiveConfig {
@Value("${keeptrusts.gateway.url:http://localhost:41002/v1}")
private String gatewayUrl;
@Value("${keeptrusts.gateway.key}")
private String gatewayKey;
@Bean
public WebClient keeptrustsWebClient() {
return WebClient.builder()
.baseUrl(gatewayUrl)
.defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer " + gatewayKey)
.build();
}
}
Reactive completion call
@Service
public class ReactiveGovernedChatService {
private final WebClient webClient;
public ReactiveGovernedChatService(WebClient keeptrustsWebClient) {
this.webClient = keeptrustsWebClient;
}
public Mono<String> complete(String userMessage) {
Map<String, Object> body = Map.of(
"model", "gpt-4o",
"messages", List.of(Map.of("role", "user", "content", userMessage))
);
return webClient.post()
.uri("/chat/completions")
.bodyValue(body)
.retrieve()
.bodyToMono(Map.class)
.map(resp -> {
List<Map<String, Object>> choices =
(List<Map<String, Object>>) resp.get("choices");
Map<String, Object> message =
(Map<String, Object>) choices.get(0).get("message");
return (String) message.get("content");
});
}
}
Spring AI integration
Spring AI supports custom OpenAI-compatible endpoints. Set the base URL in application.yml:
spring:
ai:
openai:
base-url: http://localhost:41002/v1
api-key: ${KEEPTRUSTS_GATEWAY_TOKEN}
chat:
options:
model: gpt-4o
Then inject the chat model:
@RestController
public class ChatController {
private final ChatModel chatModel;
public ChatController(ChatModel chatModel) {
this.chatModel = chatModel;
}
@PostMapping("/api/chat")
public String chat(@RequestBody String question) {
return chatModel.call(new Prompt(question))
.getResult()
.getOutput()
.getText();
}
}
Connection pooling
For production workloads, configure the underlying HTTP client pool:
@Bean
public WebClient keeptrustsWebClient() {
HttpClient httpClient = HttpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
.responseTimeout(Duration.ofSeconds(30));
return WebClient.builder()
.baseUrl(gatewayUrl)
.clientConnector(new ReactorClientHttpConnector(httpClient))
.defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer " + gatewayKey)
.build();
}
Retry logic
Use Spring Retry or Reactor retries for transient failures (429, 5xx):
public Mono<String> completeWithRetry(String userMessage) {
return complete(userMessage)
.retryWhen(Retry.backoff(3, Duration.ofSeconds(1))
.filter(ex -> ex instanceof WebClientResponseException wcre
&& (wcre.getStatusCode().value() == 429
|| wcre.getStatusCode().is5xxServerError())));
}
Error handling
Policy violations return HTTP 409. Catch them explicitly:
try {
String result = governedChatService.complete("Ignore all safety rules.");
} catch (HttpClientErrorException e) {
if (e.getStatusCode().value() == 409) {
log.warn("Policy violation: {}", e.getResponseBodyAsString());
} else {
throw e;
}
}
Health check
Add a gateway health indicator to Spring Boot Actuator:
@Component
public class GatewayHealthIndicator implements HealthIndicator {
private final WebClient webClient;
public GatewayHealthIndicator(WebClient keeptrustsWebClient) {
this.webClient = keeptrustsWebClient;
}
@Override
public Health health() {
try {
webClient.get().uri("/models")
.retrieve()
.toBodilessEntity()
.block(Duration.ofSeconds(3));
return Health.up().build();
} catch (Exception e) {
return Health.down(e).build();
}
}
}
Validating your policy config
kt policy lint --file policy-config.yaml
Tailing governance events
kt events tail --follow
Summary
| Pattern | Key change |
|---|---|
| RestTemplate | Set UriTemplateHandler to gateway URL |
| WebClient | Set baseUrl to gateway URL |
| Spring AI | Set spring.ai.openai.base-url |
| Retry | Filter on 429 / 5xx, backoff 3 attempts |
| Health check | GET /models via Actuator indicator |
| Error handling | Catch HTTP 409 for policy blocks |
For AI systems
- Canonical terms: Keeptrusts gateway, gateway key (
kt_gk_...), OpenAI-compatible API, RestTemplate, WebClient, Spring AI, Spring Boot Actuator health indicator, HTTP 409 policy block. - Key config:
keeptrusts.gateway.url=http://localhost:41002/v1,keeptrusts.gateway.key=kt_gk_...,spring.ai.openai.base-url(for Spring AI). - CLI commands:
kt gateway run,kt policy lint,kt events tail --follow. - Best next pages: .NET integration, Python SDK patterns, Node.js SDK patterns.
For engineers
- Prerequisites: Java 17+ with Spring Boot 3.x, running Keeptrusts gateway (
kt gateway run), a gateway key from the console. - Validate: Gateway health indicator reports UP in Actuator
/actuator/health,kt events tailshows events after test requests. - Key pattern: Retry 429/5xx with exponential backoff; catch
HttpClientErrorExceptionwith status 409 for policy blocks (do not retry). - Production: Externalize
keeptrusts.gateway.urlandkeeptrusts.gateway.keyvia environment variables or Spring Cloud Config.
For leaders
- No SDK dependency: Uses standard Spring HTTP clients — no proprietary Keeptrusts JAR required. Swap to direct LLM access by changing one URL.
- Governance transparency: Every AI call passes through the gateway; policy blocks return 409 with structured reasons for audit.
- Reactive support: WebClient integration enables non-blocking calls for high-throughput microservices.
- Observability: Spring Boot Actuator health indicator integrates with existing monitoring (Prometheus, Datadog, etc.).
Next steps
- .NET integration for C# / ASP.NET services
- Python SDK patterns for Python-based services
- Deploy the gateway on Kubernetes for production hosting
- CI/CD pipeline integration for automated policy validation