Key facts
| Chat endpoint | POST https://api.plugsky.com/v1/chat/completions |
| JVM support | JDK 11+ with Maven and Gradle; coroutines, Reactor and sync styles per the SDK reference |
| Client setup | OpenAIOkHttpClient.builder().apiKey(…).baseUrl("https://api.plugsky.com/v1") |
| Auth | Authorization: Bearer sk-live-… supplied through the builder |
| Kotlin | Same JVM client; wrap blocking calls in withContext(Dispatchers.IO) or use the async client |
| Streaming and tools | SSE streaming, function calling and JSON mode on chat completions |
| Models | 30+ models including plugsky-micro, plugsky-lite and plugsky-pro |
| Product status | Live; audio, images, batch and fine-tuning are coming soon |
TL;DR
- One SDK dependency serves both Java and Kotlin services.
- Override baseUrl to https://api.plugsky.com/v1 and supply your sk-live-… key.
- Reuse one client — it owns the HTTP connection pool.
- Streaming returns a chunk sequence you can bridge into coroutines or Reactor.
- Tool calling and JSON mode use the same builder API as OpenAI.
How it works, step by step
- Add the OpenAI-compatible JVM SDK to your Maven or Gradle build.
- Build one OpenAIOkHttpClient with your base URL and key from the environment.
- Send a ChatCompletionCreateParams request with model plugsky-pro.
- Read completion.choices().get(0).message().content() and handle Optional correctly.
- Add createStreaming for token-by-token output in chat features.
- Define tools with function definitions and handle tool calls in a loop.
- Configure timeouts, retries and idempotency keys for production traffic.
Original data
Try it yourself
Open the OpenAI-compatible API tester →
Add the client to your build
The Plugsky SDK reference lists JDK 11+ with Maven and Gradle for JVM work. The official OpenAI Java SDK is the OpenAI-compatible client most teams already use, and it accepts a custom base URL. Gradle:
implementation("com.openai:openai-java:latest.release")Maven uses the same coordinates, with the current version from Maven Central:
<dependency>
<groupId>com.openai</groupId>
<artifactId>openai-java</artifactId>
<version><!-- current release --></version>
</dependency>Do not ship a key inside the artifact. Read PLUGSKY_API_KEY at startup from your environment or secret manager.
Java: your first completion
Build the client once per application and inject it. The builder carries both the key and the Plugsky base URL:
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.chat.completions.ChatCompletion;
import com.openai.models.chat.completions.ChatCompletionCreateParams;
OpenAIClient client = OpenAIOkHttpClient.builder()
.apiKey(System.getenv("PLUGSKY_API_KEY"))
.baseUrl("https://api.plugsky.com/v1")
.build();
ChatCompletionCreateParams params = ChatCompletionCreateParams.builder()
.model("plugsky-pro")
.addUserMessage("Explain this stack trace in plain English.")
.build();
ChatCompletion completion = client.chat().completions().create(params);
System.out.println(completion.choices().get(0).message().content().orElse(""));The request and response types are generated, so model ids, tool definitions and JSON mode are checked at compile time rather than parsed from strings.
Kotlin: coroutines without losing the types
Kotlin uses the same client. Wrap the blocking call in a dispatcher, or use the SDK's async surface and await the future:
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
suspend fun ask(prompt: String): String = withContext(Dispatchers.IO) {
val params = ChatCompletionCreateParams.builder()
.model("plugsky-lite")
.addUserMessage(prompt)
.build()
client.chat().completions().create(params)
.choices().first()
.message().content()
.orElse("")
}Keep one OpenAIClient in your DI container. Creating a client per request discards the connection pool and adds TLS handshakes under load — a common source of latency spikes in Java services.
Streaming, tools and JSON mode
For chat UIs, use client.chat().completions().createStreaming(params). It returns a sequence of chunks in the OpenAI SSE shape; iterate and append delta content as it arrives, and forward the final usage block to your metrics. For tool calling, build function definitions with JSON-schema parameters, pass them to the request, then loop whenever the response contains tool calls: execute each function, append the tool result message, and call the model again until it answers normally. JSON mode is a one-line addition to the params when you need strict machine-readable output.
One caveat worth planning for: request bodies are capped at 16 MB, and context-window errors return exact token counts, so trim conversation history on the server side rather than retrying a request that can never fit.
Honest comparison
| Capability | Plugsky + openai-java | Raw Java HttpClient | Self-hosted model server |
|---|---|---|---|
| Setup | One SDK dependency plus baseUrl | No dependencies, more glue code | Serving stack plus a client |
| Java and Kotlin | Same builder API; Kotlin wraps calls in withContext | Manual JSON mapping works in both | Depends on the client you write |
| Streaming | createStreaming returns chunks | Parse SSE frames yourself | Engine-dependent |
| Tool calling | Typed function definitions | Build JSON by hand | Varies by runtime |
| JSON mode | responseFormat on the request | Manual validation | Varies |
| Ops | Managed API | Managed API | GPUs, scaling and upgrades |
Frequently asked questions
Which JVM client works with Plugsky?
Any OpenAI-compatible JVM client that allows a custom base URL works, including the official OpenAI Java SDK. The Plugsky SDK reference lists JDK 11+ support with Maven and Gradle.
Can I use the same client from Kotlin?
Yes. The client is a normal JVM library. Wrap blocking calls in withContext(Dispatchers.IO) or use the async surface and await the future.
How do I authenticate?
Build the client with .apiKey(System.getenv("PLUGSKY_API_KEY")) — the SDK sends Authorization: Bearer sk-live-… on every request.
Does streaming work?
Yes. createStreaming returns a sequence of SSE chunks that you can iterate and render incrementally in a chat UI.
Is function calling supported?
Yes. Define tools with JSON-schema parameters and handle tool calls in a loop: execute, append results, call again until the model answers.
How should I deploy the client?
Create one client per application or service, configure connect and read timeouts, and retry 429 and 5xx responses with exponential backoff.
Should I use virtual threads?
On JDK 21+ virtual threads work well for blocking completions. Reusing one client and bounding concurrency still matters more than the threading model.
What is not available yet?
Audio, images, moderation, files, batch, fine-tuning, assistants and the responses endpoint are coming soon; chat, streaming, embeddings and tools are live.