Changelog · Releases · Maven Central
The Qoder Cloud Agents Java SDK provides typed synchronous and asynchronous clients, with shared authentication, timeouts, retries, pagination, streaming and error handling.
Version 0.2.0 supports both the Forward API and the Managed API in one package. Use ForwardClient / AsyncForwardClient for Forward and ManagedClient / AsyncManagedClient for Managed.
- Installation
- Quick start
- PAT and Service Account authentication
- Streaming
- Asynchronous calls and cancellation
- Pagination
- Timeouts, retries and errors
- Documentation and examples
- Development
- Versioning
- License
Add the Maven dependency; published versions require no local SDK build or additional repository configuration.
<dependency>
<groupId>com.qoder.sdk</groupId>
<artifactId>qoder-cloud-agents-sdk</artifactId>
<version>0.2.0</version>
</dependency>Requirements:
- Java 8 or later; CI covers Java 8, 11, 17, 21 and 25.
- A PAT or Service Account credential for the target region, with access to the resources you call.
Set QODER_PAT in your environment. This complete Forward program connects to Global and lists the enabled models. For the other client, see the Managed quick start.
import com.qoder.cloudagents.ForwardClient;
import com.qoder.cloudagents.forward.Model;
public class QuickStart {
public static void main(String[] args) {
try (ForwardClient client = ForwardClient.builder()
.pat(System.getenv("QODER_PAT"))
.build()) {
for (Model model : client.models().list().data()) {
if (model.isEnabled()) {
System.out.println(model.id());
}
}
}
}
}| Region | Forward BaseURL |
|---|---|
| Global (default) | https://api.qoder.com/api/v1/forward |
| CN | https://api.qoder.com.cn/api/v1/forward |
For CN, add .baseUrl("https://api.qoder.com.cn/api/v1/forward") to the builder. If omitted, the SDK reads QODER_FORWARD_BASE_URL, then uses Global. BaseURLs include the full API root path.
Clients are thread-safe and can be reused. Close the owning client when your application finishes using it. The following snippets assume an open client; replace resource IDs with IDs accessible to your credential.
PAT and SA are parallel authentication modes:
| Mode | Configuration | Token renewal |
|---|---|---|
| PAT | .pat(token) |
Managed by your application |
| SA Key | .credential(ServiceAccountCredential) |
SDK exchanges, caches and refreshes the SAT on demand |
| Existing SAT | .authMode(AuthMode.SA).accessToken(token) |
Managed by your application |
With no explicit credentials, PAT mode reads QODER_ACCESS_TOKEN, then QODER_PAT. An explicit token or credential takes precedence over environment tokens; configure only one explicit source. The SDK does not load .env files or enable SA merely because QODER_SA_KEY is set.
To use automatic SA exchange, set QODER_SA_KEY and configure a credential:
import com.qoder.cloudagents.ForwardClient;
import com.qoder.cloudagents.auth.Region;
import com.qoder.cloudagents.auth.ServiceAccountCredential;
try (ServiceAccountCredential credential = ServiceAccountCredential.builder()
.saKey(System.getenv("QODER_SA_KEY"))
.region(Region.GLOBAL)
.scopes("qca.access", "forward.access")
.build();
ForwardClient client = ForwardClient.builder().credential(credential).build()) {
System.out.println(client.models().list().data().size());
}Business requests use the SAT; the SA Key is sent only to the exchange service. For CN, use both Region.CN and the CN BaseURL. Keep a shared credential open until all clients using it are closed. Failed SA authentication does not fall back to PAT.
Forward also provides explicit administrator/Identity SAT issuance and revocation through serviceAccountTokens() and identities().serviceAccountTokens(). These methods take a per-call SA Key and do not retry automatically. See SAT management and authentication configuration.
Streaming responses are consumed incrementally. Close the stream when finished and handle interruption explicitly; closing a local stream does not cancel server-side work.
The async view shares the client's authentication and transport:
import com.qoder.cloudagents.forward.Template;
import java.util.concurrent.CompletableFuture;
CompletableFuture<Template> pending = client.async().templates().retrieve("tmpl_example");
pending.thenAccept(template -> System.out.println(template.id()));
// When the result is no longer needed: pending.cancel(true);Keep the owning client open until requests complete. Cancel the SDK-returned future to stop its HTTP request and retry timer. ForwardClient.builder().buildAsync() creates an independently owned AsyncForwardClient. Cancelling a request locally does not invoke sessions().cancel(...) on the server. See async ownership and cancellation.
List responses support one-page access and lazy iteration:
import com.qoder.cloudagents.forward.TemplateListParams;
import com.qoder.cloudagents.forward.TemplateListResponse;
TemplateListResponse page = client.templates().list(TemplateListParams.builder().limit(20).build());
for (com.qoder.cloudagents.forward.Template template : page) {
System.out.println(template.id()); // Fetches subsequent pages as needed.
}Use page.data() for only the current page, or hasNextPage() and getNextPage() / getNextPageAsync() for manual pagination. Filters, request options and server order are preserved.
Pass RequestOptions as the last argument to customize a request:
import com.qoder.cloudagents.core.RequestOptions;
import com.qoder.cloudagents.errors.ApiStatusException;
import java.time.Duration;
try {
client.templates().retrieve("tmpl_example", RequestOptions.builder()
.timeout(Duration.ofSeconds(30))
.totalTimeout(Duration.ofSeconds(60))
.maxRetries(1)
.build());
} catch (ApiStatusException error) {
System.err.println("HTTP " + error.statusCode() + ", request ID: " + error.requestId());
}- Timeouts: the connection timeout defaults to 5 seconds; response-header and read/write idle timeouts default to 10 minutes.
timeoutadjusts per-attempt header/idle limits;totalTimeoutbounds the whole request, including credentials and retries. SSE has separate read-lifecycle rules. - Retries: at most 2 retries by default, subject to method safety, body replayability and server hints. HTTP 409 is never retried; non-idempotent writes only qualify for 429 retries. An idempotency key permits other eligible write retries.
- Errors:
ApiExceptionis the request-error base type. HTTP failures expose status and request ID throughApiStatusException; connection, timeout, cancellation and response-validation failures have distinct types. - Responses: models expose
requestId()and unknown JSON fields viafield(name). UsewithResponse()for HTTP status and headers. Request builders distinguish omitted fields from explicitnull.
See client configuration for detailed defaults and Template configuration for typed configuration and field semantics.
- Forward API reference
- Managed API reference
- Client configuration
- Runnable examples
- Contribution guide
With JDK 17+ and Python 3 installed, run from the repository root:
make quality
make testThese commands check formatting, documentation and maintenance scripts, then build the SDK and test the packaged JAR through the independent examples project. Default tests use local mock services. See CONTRIBUTING.md, maintenance and releasing.
Pin the SDK version in your build. Before 1.0, incompatible API changes use a new minor version and include migration notes. See the changelog for upgrading from the RC or earlier internal coordinates.
MIT.