Java SDK
Integrate document ingestion and talent-graph queries into JVM applications with the synchronous Java client.
Every call works in your company workspace, which is identified by your API key. Requires Java 17 or later.
Install
Version 1.0.0 is on Maven Central. Add this dependency to your pom.xml:
<dependency> <groupId>ai.workerbee</groupId> <artifactId>workerbee-sdk</artifactId> <version>1.0.0</version> </dependency>
For Gradle:
repositories {
mavenCentral()
}
dependencies {
implementation("ai.workerbee:workerbee-sdk:1.0.0")
}To use the library without a build tool, download the JAR (ai.workerbee:workerbee-sdk:1.0.0); Maven and Gradle resolve its dependencies automatically. The Java package is ai.workerbee.sdk. To upgrade, change the dependency version. The source is in the workerbee-sdk repository on GitHub.
Configure authentication
Create a key in Settings → Workspaces & SDK → SDK API keys. Upload-and-query examples need files:write, files:read, and graph:read. Restrict the key to Default or allow all company workspaces. Store the full key in your application’s secret manager or environment.
export WORKERBEE_API_KEY="YOUR_API_KEY"
A key restricted to workspaces other than Default can’t use these methods, and its restrictions aren’t widened automatically.
try (var wb = Workerbee.builder()
.timeout(Duration.ofSeconds(60))
.maxRetries(3)
.build()) {
for (var file : wb.listFiles()) {
System.out.println(file.id() + " " + file.status());
}
}The client reads your key from WORKERBEE_API_KEY; the builder also accepts apiKey(...). This fragment uses the imports shown in the complete quickstart below. Use Duration for timeouts. Collections are lazy Iterable values.
Upload a resume and query skills
Add Quickstart.java to your application, set the key, and run it with the SDK and its dependencies on the classpath. Put a resume at ./resume.pdf.
import ai.workerbee.sdk.*;
import java.nio.file.Path;
import java.time.Duration;
import java.util.List;
public class Quickstart {
public static void main(String[] args) {
// Production by default; reads WORKERBEE_API_KEY.
try (var wb = Workerbee.builder().build()) {
var resume = wb.uploadFile(Path.of("./resume.pdf"), new UploadOptions()
.documentTypes("resume")
.externalId("employee-123")
.sourceSystem("hris")
.sourceDocumentId("employee-123-resume")
.sourceRevision("v1")
.idempotencyKey("employee-123-resume-v1"));
System.out.println(resume.id() + " " + resume.status());
resume.waitUntilReady(Duration.ofMinutes(10), Duration.ofSeconds(2));
var response = wb.chat(
List.of(Message.user("List this employee's skills")),
new Subject("employee-123", "hris"), 20);
if (response.refused()) {
System.out.println(response.raw().path("refusal_reason").asText());
} else if (!response.clarification().isMissingNode()
&& !response.clarification().isNull()) {
System.out.println(response.clarification());
} else {
System.out.println(response.interpretation());
response.rows().forEach(System.out::println);
System.out.println(response.references());
}
}
}
}A wait succeeds at PROCESSED. Inspect adapter outcomes, readiness, and has_queryable_content: stored-only or irrelevant content may not appear in answers, and graph visibility may lag ingestion. A wait timeout does not cancel server processing.
Document types and formats
| Document type | How to use it |
|---|---|
resume | Employee resume. Use a stable employee external ID and source system. |
job_description | Job description. Use your job or requisition external ID. |
performance_review / review | Employee review. Supply employee identity. Reviews are linked to the employee, but their evidence isn’t added to graph queries yet. |
call_transcript | Written call or meeting transcript; no audio transcription. Currently stored with a deferred adapter and no searchable graph content. |
other | Generic content or ZIP default. Use this type on its own. |
try (var wb = Workerbee.builder().build()) {
var jd = wb.uploadFile(Path.of("./job-description.pdf"), new UploadOptions()
.documentTypes("job_description")
.externalId("requisition-456").sourceSystem("hris"));
var review = wb.uploadFile(Path.of("./review.pdf"), new UploadOptions()
.documentTypes("performance_review")
.externalId("employee-123").sourceSystem("hris"));
System.out.println(jd.id() + " " + review.id());
}Java uses fluent camelCase setters: documentTypes, externalId, sourceSystem, sourceDocumentId, sourceRevision, and idempotencyKey. Wire fields use snake_case; the SDK handles that conversion.
Declare types in document_types, not inside metadata. Supported formats include PDF, DOCX, TXT, Markdown, JSON, and ZIP; SRT and VTT are accepted as text. JSON is document text, not an arbitrary graph-property payload. Legacy DOC files, scanned PDFs, audio and video aren’t supported.
| Default limit | Value |
|---|---|
| Single document | 25 MiB |
| ZIP upload | 100 MiB |
| Expanded ZIP | 500 MiB |
| ZIP entries | 200 |
Limits can differ by deployment. Nested archives and unsafe paths are rejected. In a mixed resume/JD document, provide typed subjects for employee and job identities. A mixed document is not a ZIP and does not trigger ZIP matching.
Source revisions and retries
Keep external_id and source_system stable across an employee’s uploads and queries. Names alone are not reliable identities. source_document_id identifies a source document; source_revision identifies an immutable version. Change the revision when bytes change; reusing one for different content returns SOURCE_REVISION_CONFLICT.
Use an idempotency_key for retries of the same upload request. Reusing it for different input is a conflict. The clients retry eligible safe requests and transient failures; unkeyed upload creation is not blindly retried.
ZIP uploads and matching
For mixed-document ZIP uploads, include workerbee-manifest.json at the archive root so Workerbee knows the document type and identity of each included file. Declare every document using its exact archive path, including subdirectories. An entry’s types replace the ZIP default; an entry omitted from the manifest inherits that default, so do not rely on filenames to identify resumes or job descriptions. The manifest itself is control information, not an ingested document.
{
"files": {
"resumes/employee-123.pdf": {
"document_types": ["resume"],
"external_id": "employee-123",
"metadata": {"match_job_paths": ["jobs/platform-engineer.pdf"]}
},
"jobs/platform-engineer.pdf": {
"document_types": ["job_description"],
"external_id": "requisition-456"
}
}
}hiring-bundle.zip ├── workerbee-manifest.json ├── resumes/employee-123.pdf └── jobs/platform-engineer.pdf
The example below packages local ./resume.pdf and ./job-description.pdf under those paths, writes the manifest, then uploads the ZIP with the generic other default and hris source system. Per-file declarations select the resume and job-description processing. One invalid child does not discard successful siblings.
Use this fragment inside a method declared with throws java.io.IOException, with the imports from the quickstart. ZIP creation uses the Java standard library.
String manifest = """
{
"files": {
"resumes/employee-123.pdf": {
"document_types": ["resume"],
"external_id": "employee-123",
"metadata": {"match_job_paths": ["jobs/platform-engineer.pdf"]}
},
"jobs/platform-engineer.pdf": {
"document_types": ["job_description"],
"external_id": "requisition-456"
}
}
}
""";
try (var bundle = new java.util.zip.ZipOutputStream(
java.nio.file.Files.newOutputStream(Path.of("hiring-bundle.zip")))) {
bundle.putNextEntry(new java.util.zip.ZipEntry("workerbee-manifest.json"));
bundle.write(manifest.getBytes(java.nio.charset.StandardCharsets.UTF_8));
bundle.closeEntry();
bundle.putNextEntry(new java.util.zip.ZipEntry("resumes/employee-123.pdf"));
java.nio.file.Files.copy(Path.of("./resume.pdf"), bundle);
bundle.closeEntry();
bundle.putNextEntry(new java.util.zip.ZipEntry("jobs/platform-engineer.pdf"));
java.nio.file.Files.copy(Path.of("./job-description.pdf"), bundle);
bundle.closeEntry();
}
try (var wb = Workerbee.builder().build()) {
var archive = wb.uploadFile(Path.of("./hiring-bundle.zip"), new UploadOptions()
.documentTypes("other").sourceSystem("hris"));
try {
archive.waitUntilReady(Duration.ofMinutes(10), Duration.ofSeconds(2));
} catch (WorkerbeeException error) {
if (error.kind() != WorkerbeeException.Kind.PARTIAL_SUCCESS) throw error;
archive = error.file();
}
for (var child : archive.childrenFiles()) {
System.out.println(child.data().path("archive_path").asText()
+ " " + child.id() + " " + child.status());
}
System.out.println(archive.adapters());
}With ZIP auto-matching enabled, a ZIP containing one JD and resumes adds successfully processed employees to that JD’s Internal Talent pool. Multiple JDs require explicit metadata.match_job_paths on each resume; paths must identify JDs in the same ZIP. Resume-only archives do not assign employees to a job.
Matching runs separately from ingestion. Inspect the parent’s archive_matching adapter: PENDING/RUNNING, NEEDS_REVIEW, or SUCCEEDED. Retryable scoring failures are recovered by the backend. A processed ZIP can still have matching in progress.
For individual uploads, open Workspaces & SDK → Employees, choose an employee and job, then select Match and open ranking. The SDK doesn’t expose employee-profile or direct job-matching methods; chat is not a replacement for a match operation.
Manage files
try (var wb = Workerbee.builder().build()) {
for (var file : wb.listFiles("PROCESSED", 50)) {
System.out.println(file.id() + " " + file.filename());
}
var file = wb.getFile("YOUR_FILE_ID");
file.refresh();
file.download(Path.of("./downloaded-source.pdf"));
// Only when intended:
// file.retry();
// file.delete();
}Lists paginate as you iterate. file.data() returns a JSON snapshot; adapters() exposes processing outcomes. Retrying failed processing preserves successful adapters. Deleting a source does not remove an employee from an existing job pool.
Chat responses
Check refusal and clarification before consuming rows. interpretation describes the query; row fields depend on the question. references retain available source identities, and audit provides query context. Not every result or aggregate has a reference.
A subject selects the employee using the same external ID and source system used for ingestion. Without one, supported inventory queries may be company-wide. Workspace restrictions control resource access; do not treat workspace selection or a chat subject as a department-level privacy boundary.
Java returns Jackson JsonNode values for rows, references, and clarification. response.raw() preserves fields such as refusal reason, audit, primitive, and graph. Access known fields with path(...) rather than assuming a fixed row class.
Handle errors and processing states
| Outcome | Action |
|---|---|
PROCESSED | Inspect adapters and queryable-content indicators before expecting graph results. |
NEEDS_REVIEW | Resolve identity or processing ambiguity in the Work Intelligence Console (WIC). |
PARTIAL_SUCCESS | Inspect failed adapters or ZIP children; preserve successful results. |
FAILED | Read the error and retry only when appropriate. |
DELETED | The source was deleted; stop polling. |
| Wait timeout | Processing continues. Refresh the same file later. |
try (var wb = Workerbee.builder().build()) {
var file = wb.getFile("YOUR_FILE_ID");
file.waitUntilReady(Duration.ofMinutes(10), Duration.ofSeconds(2));
} catch (WorkerbeeException error) {
System.err.println(error.kind() + " " + error.code());
System.err.println("Request ID: " + error.requestId());
if (error.kind() == WorkerbeeException.Kind.READY_TIMEOUT) {
System.err.println("Processing continues on the server.");
}
if (error.file() != null) {
System.err.println(error.file().status());
System.err.println(error.file().adapters());
}
}kind() distinguishes authentication, permission, validation, conflict, rate-limit, connection, server, upload, and processing failures. status(), code(), requestId(), retryable(), and details() retain available error context. A processing failure includes file().
Last updated