Claude API in Java

Call the Anthropic Claude API from Java using the official SDK or the Java HttpClient. Complete examples for text generation, streaming, and tool use in Java 11+.

💥 50p impulse-buy: Power Prompts PDF (first 10 buyers) 30 battle-tested Claude Code prompts · 8-page PDF · paste into CLAUDE.md and never re-type a prompt again · 50p impulse-buy, no commitment

Anthropic ships official SDKs for Python, TypeScript, and Go. For Java, the cleanest path is the REST API via java.net.http.HttpClient (Java 11+). The examples below wrap this in a reusable utility class.

Dependencies (Maven)

<dependency>
  <groupId>com.google.code.gson</groupId>
  <artifactId>gson</artifactId>
  <version>2.10.1</version>
</dependency>

Basic message

import com.google.gson.*;
import java.net.URI;
import java.net.http.*;
import java.net.http.HttpResponse.BodyHandlers;

public class ClaudeClient {

    private static final String API_URL = "https://api.anthropic.com/v1/messages";
    private static final String API_KEY  = System.getenv("ANTHROPIC_API_KEY");
    private static final String MODEL    = "claude-sonnet-4-6-20251001";

    private final HttpClient http = HttpClient.newHttpClient();
    private final Gson gson = new Gson();

    public String chat(String userMessage) throws Exception {
        JsonObject body = new JsonObject();
        body.addProperty("model", MODEL);
        body.addProperty("max_tokens", 1024);

        JsonArray messages = new JsonArray();
        JsonObject msg = new JsonObject();
        msg.addProperty("role", "user");
        JsonArray content = new JsonArray();
        JsonObject textBlock = new JsonObject();
        textBlock.addProperty("type", "text");
        textBlock.addProperty("text", userMessage);
        content.add(textBlock);
        msg.add("content", content);
        messages.add(msg);
        body.add("messages", messages);

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(API_URL))
            .header("Content-Type", "application/json")
            .header("x-api-key", API_KEY)
            .header("anthropic-version", "2023-06-01")
            .POST(HttpRequest.BodyPublishers.ofString(gson.toJson(body)))
            .build();

        HttpResponse<String> response = http.send(request, BodyHandlers.ofString());
        if (response.statusCode() != 200)
            throw new RuntimeException("API error " + response.statusCode() + ": " + response.body());

        JsonObject resp = JsonParser.parseString(response.body()).getAsJsonObject();
        return resp.getAsJsonArray("content")
                   .get(0).getAsJsonObject()
                   .get("text").getAsString();
    }

    public static void main(String[] args) throws Exception {
        ClaudeClient client = new ClaudeClient();
        System.out.println(client.chat("Explain Java virtual threads in two sentences."));
    }
}

Async call with CompletableFuture

public CompletableFuture<String> chatAsync(String userMessage) {
    JsonObject body = buildBody(userMessage);
    HttpRequest request = buildRequest(body);
    return http.sendAsync(request, BodyHandlers.ofString())
        .thenApply(response -> {
            if (response.statusCode() != 200)
                throw new RuntimeException("API error " + response.statusCode());
            return extractText(response.body());
        });
}

Error handling with exponential backoff

public String chatWithRetry(String userMessage, int maxRetries) throws Exception {
    int attempt = 0;
    while (true) {
        HttpResponse<String> response = http.send(buildRequest(buildBody(userMessage)), BodyHandlers.ofString());
        int status = response.statusCode();
        if (status == 200) return extractText(response.body());
        if ((status == 429 || status >= 500) && attempt++ < maxRetries) {
            Thread.sleep((long) Math.pow(2, attempt) * 1000L);
            continue;
        }
        throw new RuntimeException("Non-retryable error " + status);
    }
}

Model and pricing reference

Model IDBest forInput ($/1M)Output ($/1M)
claude-haiku-4-5-20251001High-throughput, low-cost tasks$0.80$4.00
claude-sonnet-4-6-20251001Balanced intelligence + speed$3.00$15.00
claude-opus-4-7-20251001Most capable, complex reasoning$15.00$75.00

Estimate costs for your Java workload at the Claude API Cost Calculator.

Frequently asked questions

Is there an official Java SDK for the Anthropic API?
As of 2026, Anthropic ships official SDKs for Python, TypeScript/Node.js, and Go. For Java, the recommended approach is to call the REST API directly using Java's built-in HttpClient (Java 11+) or a library like OkHttp.
What Java version is needed to call the Claude API?
Java 11 or later is recommended because it ships the java.net.http.HttpClient for async HTTP calls. Older versions (Java 8) can use HttpURLConnection but the code is significantly more verbose.
How do I handle API keys securely in a Java application?
Never hardcode your ANTHROPIC_API_KEY in source code. Read it from an environment variable: System.getenv("ANTHROPIC_API_KEY"). In Spring Boot, use @Value("${ANTHROPIC_API_KEY}"). Store secrets in Vault or AWS Secrets Manager in production.
Can I call the Claude API from an Android app?
Technically yes, but you should not embed your API key in an Android APK — it can be extracted by reverse-engineering. Instead, proxy all Claude API calls through your own backend server that holds the key.
How do I parse the Claude API JSON response in Java?
Use any JSON library: Gson (com.google.code.gson), Jackson (com.fasterxml.jackson.core), or Moshi. Parse the response body string into a JsonObject and extract content[0].text.

Free tools

Cost Calculator → API Cookbook → Diff Summarizer → Skills Browser →

More examples

Claude API Python QuickstartClaude API Node.js / TypeScript QuickstartClaude API Streaming in PythonClaude API Streaming in Node.js / TypeScriptClaude API Tool Use in PythonClaude API Tool Use in Node.js / TypeScript