Spring AI OpenRouter Integration

Integrate OpenRouter with Spring AI: Switch Between 400+ AI Models with Zero Code Changes

Learn how to integrate OpenRouter with Spring AI in your Java Spring Boot application. This guide provides a step-by-step tutorial for using a single API to access multiple LLMs like Claude, Gemini, Llama, OpenAI, and many more.

1. Introduction

The AI landscape is evolving rapidly, with new models such as GPT, Claude, Gemini, and Llama emerging almost weekly. While this gives developers incredible choice, it also creates a significant challenge: each AI provider has its own API, making it difficult to switch between models without rewriting code.

What if you could access hundreds of AI models through a single, unified API? That’s exactly what OpenRouter provides – a universal adapter that lets you seamlessly switch between different AI models without changing your application code.

In this comprehensive guide, we’ll build a Smart Chat Assistant using Spring AI and OpenRouter. This assistant will be able to switch between different AI models with just a configuration change.

2. What is OpenRouter? Your Universal AI Model Adapter

OpenRouter is a unified API gateway that provides access to 400+ AI models from different providers through a single, unified API endpoint. The provided endpoint is compatible with the OpenAI API specification. Instead of managing separate API keys and different client libraries for each AI provider, you can access GPT-4, Claude, Llama, Gemini, and 400+ other models with just one integration.

3. Why Choose OpenRouter?

Using OpenRouter offers several key benefits:

  • One API: A single, OpenAI-compatible API format for all models.
  • One API Key: A single key to access models from various providers.
  • Unified Billing: A single place to manage costs for all the models you use.
  • Model Discovery: An easy way to find and compare models, including many free ones perfect for testing.
  • Cost Optimization: Choose the best model for your budget and requirements
  • Real-time Monitoring: Track usage and costs in a comprehensive dashboard
  • Model Flexibility: Switch between models without code changes


4. Getting Your OpenRouter API Key

Before we write any code, you’ll need an OpenRouter API key:

  1. Sign Up: Go to OpenRouter.ai and click the Sign in button to create a free account. You can sign up using your email address or simply use your GitHub or Google account for quick access.
  2. Generate a Key: Once logged in, click your account icon in the top right, go to Keys, and click Create API Key.
  3. Save Your Key: Give your key a name (e.g., spring-ai-poc), click Create, and copy the generated key. Store it securely! You won’t be able to see it again.

5. Finding a Model on OpenRouter

OpenRouter’s catalog is its superpower.

  1. Navigate to the Models page on the site.
  2. You’ll see a huge list of models. You can filter them by provider, see their pricing per million tokens, and check their context window size.
  3. Crucially, you’ll find a selection of free, rate-limited models. These are fantastic for development and proof-of-concepts (POCs). Look for models with a “Free” tag, like google/gemini-2.0-flash-exp:free.

For our example, we’ll use a free model. Remember the model’s identifier (e.g., google/gemini-2.0-flash-exp:free), as we’ll need it for our configuration.



6. Building Our Smart Chat Assistant by Integrating OpenRouter with Spring AI

We’ll build a simple yet powerful Smart Chat Assistant that demonstrates OpenRouter integration with Spring AI.

⚙️ Project Structure & Setup

Below is the folder structure of our Spring Boot application:

spring-ai-openrouter-integration
├── src
│   └── main
│       ├── java
│       │   └── com
│       │       └──bootcamptoprod  
│       │               ├── controller
│       │               │   └── ChatController.java
│       │               ├── service
│       │               │   └── ChatService.java
│       │               ├── dto
│       │               │   └── ChatRequest.java
│       │               │   └── ChatResponse.java
│       │               ├── SpringAiOpenRouterIntegrationApplication.java
│       └── resources
│           └── application.yml
└── pom.xml
Project Structure

Explanation:

  • SpringAiOpenRouterIntegrationApplication.java: The main entry point that starts the Spring Boot application.
  • ChatController.java:  Exposes a single REST endpoint, /api/chat/message, to receive user messages and return AI-generated responses.
  • ChatService.java: Contains the core logic for interacting with the ChatClient to send a prompt to OpenRouter and process the reply.
  • ChatRequest.java & ChatResponse.java: Simple record classes that define the JSON structure for API requests and responses.
  • application.yml: Configures Spring AI to use the OpenRouter API endpoint, key, and a specific model.
  • pom.xml: Declares the necessary Maven dependencies for Spring Web and the Spring AI OpenAI starter.


Let’s set up our project with the necessary dependencies and configurations.

Step 1: Add Maven Dependencies

First, let’s set up our Maven project. The key insight here is that OpenRouter uses an OpenAI-compatible API. This means we can use the existing spring-ai-starter-model-openai dependency to communicate with it!

Add below dependencies to pom.xml file.

<dependencies>
    <!-- Spring Boot Web for building RESTful web services -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- OpenAI Model Support – configureable for various AI providers (e.g. OpenAI, Google Gemini) -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-model-openai</artifactId>
    </dependency>

<dependencyManagement>
    <dependencies>
        <!-- Spring AI bill of materials to align all spring-ai versions -->
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>${spring-ai.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
pom.xml

In this configuration:

  • spring-boot-starter-web: The standard dependency for building web applications in Spring Boot, enabling us to create our @RestController to handle incoming HTTP requests.
  • spring-ai-starter-model-openai: This is our key to OpenRouter. Because OpenRouter provides an OpenAI-compatible API, we use this starter to get the auto-configured ChatClient and all the necessary components to communicate with its unified endpoint.
  • spring-ai-bom: This Spring AI Bill of Materials (BOM), located in the <dependencyManagement> section, simplifies our setup. It manages the versions of all Spring AI modules, ensuring they are compatible and preventing potential library version conflicts.

Step 2: Configure Application Properties

Now, let’s configure our application and add configuration related to AI using application.yml.

spring:
  application:
    name: spring-ai-openrouter-integration
  ai:
    openai:
      api-key: ${OPENROUTER_API_KEY}
      # This is the crucial part: we override the base URL to point to OpenRouter.
      base-url: https://openrouter.ai/api
      chat:
        options:
          # Here we specify the model from the OpenRouter website.
          model: google/gemini-2.0-flash-exp:free
application.yaml

📄 Configuration Overview

This application.yml file is the heart of our integration, instructing Spring AI to communicate with OpenRouter instead of the default OpenAI service.

👉 AI (OpenAI Starter) Settings:

  • api‑key: Your secret key for authenticating with the AI service. Keep this safe and out of source control.
  • base‑url: This is the crucial override. We change the default API endpoint from OpenAI to OpenRouter, redirecting all our AI requests to the OpenRouter gateway.
  • model: This property defines which specific model from the vast OpenRouter catalog will process our prompts. Here, we’re using a free model, but you can swap this value to any other model identifier (e.g., anthropic/claude-sonnet-4) to instantly change the AI you’re using.

Make sure to set the OPENROUTER_API_KEY environment variable in your system or IDE for the application to authenticate successfully.



Step 3: Create Data Transfer Objects (DTOs)

These simple Java record classes define the structure of our API’s request and response JSON.

package com.bootcamptoprod.dto;

public record ChatRequest(
        String message  // The user's input message
) {
}
ChatRequest.java
package com.bootcamptoprod.dto;

public record ChatResponse(
        String response // The AI's response message
) {
}
ChatResponse.java

Explanation:

  • What they do: ChatRequest holds the incoming message, and ChatResponse holds the outgoing AI reply.
  • Why they’re needed: They provide a clean, type-safe way to handle JSON data.
  • How they fit: The controller uses them to automatically serialize and deserialize the request/response bodies.

Step 4: Create Service Class

This class contains the core logic for interacting with the AI model.

package com.bootcamptoprod.service;

import com.bootcamptoprod.dto.ChatRequest;
import com.bootcamptoprod.dto.ChatResponse;
import org.springframework.ai.chat.client.ChatClient;

public class ChatService {

    private final ChatClient chatClient;

    /**
     * Constructor injection for ChatClient
     * ChatClient.Builder is auto-configured by Spring AI
     */
    public ChatService(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder.build();
    }

    /**
     * Processes user messages through OpenRouter AI models
     */
    public ChatResponse processMessage(ChatRequest chatRequest) {
        System.out.println("📨 Processing message: " + chatRequest.message());

        try {
            // Send the user's message to the AI model via OpenRouter
            String content = chatClient.prompt()
                    .user(chatRequest.message())  // Set the user's message
                    .call()                       // Make the API call
                    .content();                   // Extract the response content

            System.out.println("✅ AI response received successfully");
            return new ChatResponse(content);

        } catch (Exception e) {
            // Log the error for debugging while providing user-friendly response
            System.err.println("❌ Error processing message: " + e.getMessage());
            return new ChatResponse("Sorry, an error occurred while processing your message. Please try again.");
        }
    }
}
ChatService.java

Explanation:

  • AI Interaction: The primary function of this class is to communicate with the AI model (via OpenRouter) using the injected Spring AI ChatClient. It acts as the business logic layer, abstracting the AI interaction away from the controller.
  • Request-Response Logic: It handles standard, synchronous AI interactions.
    • processMessage: This method takes the user’s input from ChatRequest, uses the ChatClient to execute a prompt via .call(), and retrieves the complete AI response using .content(). It returns this content wrapped in a ChatResponse and includes error handling for API failures.


Step 5: Create Controller

The ChatController acts as the public-facing entry point for our application, exposing our “Smart Chat Assistant” to clients through a simple REST API endpoint.

package com.bootcamptoprod.controller;

import com.bootcamptoprod.dto.ChatRequest;
import com.bootcamptoprod.dto.ChatResponse;
import com.bootcamptoprod.service.ChatService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/chat")
public class ChatController {

    private final ChatService chatService;

    public ChatController(ChatService chatService) {
        this.chatService = chatService;
    }

    /**
     * Handles POST requests to /api/chat/message
     * Processes user messages and returns AI responses
     */
    @PostMapping("/message")
    public ResponseEntity<ChatResponse> sendMessage(@RequestBody ChatRequest chatRequest) {
        System.out.println("🔄 Received chat request from client");

        // Process the message through our service
        ChatResponse chatResponse = chatService.processMessage(chatRequest);

        System.out.println("📬 Sending response back to client");
        return ResponseEntity.ok(chatResponse);
    }
}
ChatController.java

Explanation:

  • Purpose: The ChatController is our application’s “front door.” It is responsible for handling incoming web requests and delegating them to the ChatService for processing.
  • Its job is to:
    • Expose an API Endpoint: It defines a single POST endpoint at /api/chat/message, which is the address clients will send their chat requests to.
    • Receive User Input: It uses the @RequestBody annotation to automatically convert the JSON body of the incoming request into a ChatRequest DTO, efficiently capturing the user’s message.
    • Delegate to Service: It calls the chatService.processMessage() method, passing the user’s request. Once the service returns a ChatResponse, the controller wraps it in a ResponseEntity and sends it back to the client, completing the request-response cycle.

Step 6: Application Entry Point

Now, let’s define the main class that boots our Spring Boot app.

package com.bootcamptoprod;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringAiOpenRouterIntegrationApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringAiOpenRouterIntegrationApplication.class, args);
    }
}
SpringAiOpenRouterIntegrationApplication.java

Explanation:

  • Main Class to Run the Application: SpringAiOpenRouterIntegrationApplication is the starting point of our application. When you run this class, Spring Boot initializes all components and starts the embedded server.


7. Testing the OpenRouter Integration with Spring AI

  1. Run the application: Start the SpringAiOpenrouterIntegrationApplication from your IDE.
  2. Test with curl: Open a terminal and run the following command:
curl -X POST http://localhost:8080/api/chat/message \
-H "Content-Type: application/json" \
-d '{"message": "What is the capital of India?"}'
cURL

Expected Result: You should see a JSON response like this:

{
  "response": "The capital of India is New Delhi. It's located in the northern part of the country and serves as the political and administrative center."
}
Terminal / CMD


8. Monitoring Usage on the OpenRouter Dashboard

One of the useful features of OpenRouter is its dashboard, where you can monitor your API usage in near real-time. After making a few API calls to your application, follow these steps to review your usage statistics:

  1. Navigate to the Activity page. Once logged in, you can get there in two ways:
  2. To see specific data, select the time range by setting the From and To dates.

What You’ll See on the Dashboard

📌 On the dashboard, you will find detailed metrics, including:

  • Overall statistics.
  • Which models were called
  • The number of input and output tokens used.
  • The cost incurred for each call (even if it’s $0.00 for free models).
  • Throughput information in tokens per second.

This level of detail is incredibly helpful for tracking expenses, debugging, and understanding model performance.

9. A Note on Free vs. Paid Models

While the free models on OpenRouter are excellent for getting started and for POCs, they come with caveats:

  • Rate Limits: Free models have rate limits that restrict the number of requests you can make in a given period. For detailed information on these limits, you can visit the official OpenRouter API documentation here: https://openrouter.ai/docs/api-reference/limits.
  • Availability: They are not guaranteed to be available long-term and can be removed without notice.
  • Limited Selection: The catalog of free models is relatively small compared to the vast number of powerful, state-of-the-art paid models available on the platform.

For any serious application or production environment, you should switch to a paid model. The process is straightforward:

  • Add a payment method to your OpenRouter account and purchase credits.
  • For uninterrupted service in production, you can also configure auto top-up.
  • Once your account has a credit balance, simply update the model property in your application.yml to a paid model identifier (e.g., openai/gpt-4.1 | google/gemini-2.5-pro | anthropic/claude-sonnet-4).


10. Source Code

The complete source code for this “Smart Chat Assistant” example, showcasing the integration between Spring AI and OpenRouter, is available on GitHub. You can clone the repository and run it locally to see it in action.

🔗 Spring AI + OpenRouter Demo: https://github.com/BootcampToProd/spring-ai-openrouter-integration

11. Things to Consider

When integrating OpenRouter with Spring AI, keep these important points in mind:

  1. API Key Security: Never hardcode API keys in your source code. Use environment variables or secure configuration management systems like Spring Cloud Config or HashiCorp Vault.
  2. Rate Limiting: Different models have different rate limits. Implement proper retry logic and consider using circuit breakers for production applications.
  3. Data Privacy: OpenRouter acts as a proxy. Understand their data privacy and retention policies before sending sensitive information.
  4. Error Handling: OpenRouter returns a standard JSON error object for issues like insufficient credits (402) or rate limits (429), often with a corresponding HTTP status code. Your application must parse this error structure to handle failures gracefully; find a complete list on the official API Errors documentation.
  5. Model Availability: Not every model from every provider is available. Always check the OpenRouter model list first.
  6. Model Selection Strategy: Consider implementing dynamic model selection based on factors like cost, performance requirements, and current availability.
  7. Monitoring and Alerting: Set up monitoring for API usage, error rates, and costs. Consider using tools like Spring Boot Actuator and Micrometer for comprehensive monitoring.
  8. Content Filtering: Implement input validation and content filtering to prevent abuse and ensure compliance with your application’s policies.
  9. Timeout Configuration: Configure appropriate timeouts for AI API calls, as response times can vary significantly between models and based on request complexity.
  10. Model Versioning: Keep track of model versions and their capabilities. Some models may be deprecated or updated, affecting your application’s behavior.


12. FAQs

Can I use OpenRouter for free?

How do I switch between different AI models?

How do I handle rate limiting?

How do I monitor my API usage and costs?

Is OpenRouter suitable for production use?

Why use OpenRouter instead of directly using the Google or OpenAI API?

Do I need an OpenAI account to use OpenRouter?

Why are we using the spring-ai-starter-model-openai dependency for OpenRouter?

13. Conclusion

Integrating OpenRouter with Spring AI opens up a world of possibilities for Java developers. With access to 400+ AI models through a single, unified API, you can build sophisticated AI-powered applications without the complexity of managing multiple provider integrations.

The key takeaways from this integration are the flexibility to switch between models, the comprehensive monitoring capabilities, and the ability to start with free models for development before scaling to paid models for production. Whether you’re building a simple chatbot or a complex AI-powered application, this foundation provides the scalability and flexibility you need.

14. Learn More

#

Interested in learning more?

Spring AI Routing Workflow: Intelligent Request Routing with LLM-Powered Classification



Add a Comment

Your email address will not be published.