Skip to main content

Java SDK

Java 11+ client for the public VectorAmp API.

Install

Gradle:

repositories { mavenCentral() }

dependencies {
implementation 'com.vectoramp:vectoramp-java:0.1.0'
}

Maven:

<dependency>
<groupId>com.vectoramp</groupId>
<artifactId>vectoramp-java</artifactId>
<version>0.1.0</version>
</dependency>

Configure

The default base URL is https://api.vectoramp.com. VectorAmpClient.create(...) reads the API key from your code or from VECTORAMP_API_KEY. Auth uses X-API-Key.

VectorAmpClient client = VectorAmpClient.builder(System.getenv("VECTORAMP_API_KEY"))
.timeout(java.time.Duration.ofSeconds(60))
.build();

Quickstart

A minimal init, a one-call create, then object → method calls. Only a name is required: the embedding defaults to VectorAmp-Embedding-4B (dim 2560), the metric defaults to cosine, and the index is always SABLE.

import com.vectoramp.VectorAmpClient;
import com.vectoramp.models.*;

try (VectorAmpClient client = VectorAmpClient.create(System.getenv("VECTORAMP_API_KEY"))) {
// One-call create: name only.
Dataset dataset = client.datasets().create("product-docs");

// Object -> method style: call instance methods on the dataset directly.
dataset.addTexts(java.util.List.of(
"VectorAmp ships a high-performance SABLE vector index.",
"The API supports RAG over ingested datasets."
));

SearchResponse results = dataset.search("How does VectorAmp search documents?");
AskResponse answer = dataset.ask("What index does VectorAmp use?");

System.out.println(results.getResults());
System.out.println(answer.getAnswer());
}
info

Dataset creation always requests SABLE. The SDK always sends index_type: "sable" and never exposes other index types.

Creating datasets

// Minimal: name only (defaults applied).
Dataset docs = client.datasets().create("docs");

// Hybrid dense + sparse dataset.
Dataset hybrid = client.datasets().create("hybrid-docs", true);

// Full control, including an OpenAI embedding (dim inferred from the model).
Dataset custom = client.datasets().create(
CreateDatasetRequest.builder("openai-docs")
.embedding(EmbeddingConfig.openai("small")) // text-embedding-3-small, dim 1536
.metric("cosine")
.hybrid(true)
.build()
);

// Custom/unknown embedding model: provide dim explicitly.
Dataset bespoke = client.datasets().create(
CreateDatasetRequest.builder("bespoke")
.embedding(EmbeddingConfig.of("acme", "acme-embed-v2"))
.dim(768)
.build()
);

Object and service styles

create, get, and list return Dataset resource objects that keep the raw payload (getRawData()), the dataset id, and bound services. The id-based service methods remain available.

// Object -> method style (preferred)
Page<Dataset> page = client.datasets().list(50, 0);
Dataset dataset = client.datasets().get(page.getItems().get(0).getId());
SearchResponse results = dataset.search("release notes");
dataset.delete();

// Service style
SearchResponse explicit = client.datasets().search("dataset-uuid", "release notes");
client.datasets().delete("dataset-uuid");

Vector ids accept a String or a number. Numeric ids are sent as JSON numbers, so the API preserves them exactly.

dataset.insert(java.util.List.of(
VectorRecord.of("doc-001", java.util.List.of(0.1, 0.2, 0.3), java.util.Map.of("title", "Intro")),
VectorRecord.of(42L, java.util.List.of(0.4, 0.5, 0.6), null) // serialized as "id": 42
));

// addTexts embeds through /datasets/{id}/embed, copies the text into metadata.text, then inserts.
dataset.addText("hello world");
dataset.addTexts(java.util.List.of("hello", "world"));

top_k defaults to 10. Add options only when you need them.

// Bare text query.
SearchResponse results = dataset.search("machine learning best practices");

// Filtered search with the optional model reranker.
SearchResponse filtered = dataset.search(
SearchRequest.text("machine learning best practices")
.filters(java.util.Map.of("category", "research"))
.includeDocuments(true)
.rerank(true) // expands to vectoramp / VectorAmp-Rerank-v1
);

// Hybrid dense/sparse search.
SearchResponse hybridResults = dataset.search(
SearchRequest.text("zero downtime upgrade").hybrid("zero downtime", 0.5)
);

// Vector search.
SearchResponse vectorResults = dataset.search(
SearchRequest.vector(java.util.List.of(0.1, 0.2, 0.3))
);
tip

rerank(true) enables the optional model reranker after initial retrieval. The separate rerankDepthOverride(...) only tunes SABLE's vector-index candidate depth and is not the model reranker.

Organization secrets and vector deletion

Store external provider credentials as organization secrets, then reference the secret from datasets. The default OpenAI BYOM reference is emb:openai:api_key.

// One-step convenience: saves/updates the OpenAI org secret, then creates
// the dataset with embedding.secretRef = "emb:openai:api_key".
Dataset dataset = client.datasets().createWithOpenAIApiKey(
CreateDatasetRequest.builder().name("openai-docs").build(),
System.getenv("OPENAI_API_KEY")
);

// Or manage the secret explicitly.
client.orgSecrets().putOpenAIApiKey(System.getenv("OPENAI_API_KEY"));

// Delete individual vector ids from search.
client.datasets().deleteVectors(dataset.getId(), DeleteVectorsRequest.of("doc-001", 42));

Ingestion

Typed source helpers cover web, s3, gcs, gdrive, jira, confluence, and file_upload. Use GenericSource as an escape hatch for new source types.

Source web = client.ingestion().createWeb("https://docs.vectoramp.com");
Source s3 = client.ingestion().createS3("my-docs-bucket");
Source gdrive = client.ingestion().createGoogleDrive("google-drive-folder-id");
Source jira = client.ingestion().createJira("atlassian-cloud-id");
Source confluence = client.ingestion().createConfluence("atlassian-cloud-id");
Source uploadSource = client.ingestion().createFileUpload("dataset-uuid");

// Names and advanced config are available when you need them.
Source deepWeb = client.ingestion().createWeb(
WebSource.builder("docs-site").url("https://docs.vectoramp.com").crawlDepth(2).build()
);

Source spaces = client.ingestion().createConfluence(
ConfluenceSource.builder("eng-confluence")
.cloudId("atlassian-cloud-id")
.spaces(java.util.List.of("ENG", "DOCS"))
.includeAttachments(true)
.build()
);

IngestionJob job = client.ingestion().startJob(web.getId(), "dataset-uuid");

Dataset resource objects can create a typed source and start ingestion in one flow:

Source source = dataset.ingestSource(WebSource.of("https://docs.vectoramp.com"));
IngestionJob job = dataset.ingestSource(source.getId());

Manage and clean up sources

Validate a config, delete a source, or find and remove sources nothing is using.

// Validate without persisting.
client.ingestion().validateSource("web", java.util.Map.of("start_urls", java.util.List.of("https://docs.example.com")));

// See what's using a source (active schedules + in-flight jobs).
SourceReferences refs = client.ingestion().getSourceReferences("source-uuid"); // getSchedules(), getScheduleCount(), getActiveJobCount(), isInUse()

// Delete. Throws a 409 on an in-use source unless force is true (force also disables its schedules).
client.ingestion().deleteSource("source-uuid");
client.ingestion().deleteSource("source-uuid", true);

// Find unused sources, or remove all of them in one call.
SourceList unused = client.ingestion().listUnusedSources();
CleanupResult result = client.ingestion().cleanupUnusedSources(); // getDeleted(), getCount()

Authenticated sources & connections

Authenticate a gdrive/gcs/confluence/jira source with a headless service account, or a reusable connection granted once in the browser.

// Option 1 — service account (headless, no browser).
Source drive = client.ingestion().createGoogleDrive(
GoogleDriveSource.builder("drive-service-account")
.folderIds(java.util.List.of("google-drive-folder-id"))
.serviceAccountJson(System.getenv("GOOGLE_SERVICE_ACCOUNT_JSON"))
.build()
);

// Option 2 — connection (interactive once, reused server-side).
// connect(...) creates the grant, opens/prints the authorization URL, and polls until connected.
Connection conn = client.connections().connect("google", "gdrive");
Source driveViaConn = client.ingestion().createGoogleDrive(
GoogleDriveSource.builder("drive-connection")
.folderIds(java.util.List.of("google-drive-folder-id"))
.connectionId(conn.getId())
.build()
);

Drive the grant flow yourself when you need to:

Connection conn = client.connections().create("google", "gdrive"); // getStatus() == "pending", getAuthorizationUrl()
System.out.println("Open in a browser: " + conn.getAuthorizationUrl());
Connection refreshed = client.connections().get(conn.getId()); // poll until getStatus().equals("connected")
java.util.List<Connection> google = client.connections().list("google");
client.connections().delete(conn.getId());

Minimal file upload ingestion

dataset.ingestFiles(...) models the REST upload flow: it creates or uses a file_upload source and returns an upload session. PUT file bytes to each upload target, then complete the upload.

UploadSession session = dataset.ingestFiles(java.util.List.of(
FileUpload.fromPath(java.nio.file.Path.of("docs/whitepaper.pdf"))
));
// PUT file bytes to each session.getUploads().get(i).getUploadUrl() with your HTTP client.
dataset.completeUpload(session);

Dataset documents

Document listing is cursor-based. Pass getNextCursor() into the next request. Downloads return retained original bytes; the default transport follows redirects to storage.

DatasetDocumentPage docs = dataset.listDocuments(50, null, "ready");
for (DatasetDocument doc : docs.getDocuments()) {
if (Boolean.TRUE.equals(doc.getDownloadAvailable())) {
byte[] original = dataset.downloadDocument(doc.getId());
}
}
if (docs.getNextCursor() != null) {
DatasetDocumentPage next = dataset.listDocuments(50, docs.getNextCursor(), "ready");
}

The SDK follows download redirects and returns raw bytes. Storage buckets, object keys, and payload references are never exposed.

Ask / RAG

ask defaults top_k=5, includes sources, and queries all accessible datasets when unscoped. query(...) is an alias for ask(...).

// Top-level convenience.
AskResponse response = client.ask(
AskRequest.of("What are the key features?").allDatasets().topK(5).includeSources(true)
);

// Or via the intelligence client.
AskResponse scoped = client.intelligence().query(
AskRequest.of("Summarize the roadmap").datasetId("dataset-uuid")
);

// Streaming SSE.
try (java.util.stream.Stream<SseEvent> events = client.askStream(
AskRequest.of("Summarize the roadmap").datasetId("dataset-uuid")
)) {
events.forEach(event -> System.out.print(event.getContent()));
}

Multi-turn conversations

The Intelligence API is stateless. To ask a follow-up, send the prior turns as conversation history; you decide how many previous messages to include.

AskResponse answer = client.ask(
AskRequest.of("Which of those help with relevance?")
.message("user", "What are the key features?")
.message("assistant", "Hybrid search, reranking, and managed ingestion.")
);

Persistent Intelligence sessions

IntelligenceSession session = client.intelligence().createSession(
SessionCreateRequest.of("Q4 planning").datasetId("dataset-uuid")
);
client.intelligence().appendMessage(session.getId(), SessionMessageCreateRequest.user("Summarize the latest planning docs"));
java.util.List<SessionMessage> history = client.intelligence().listMessages(session.getId());
java.util.List<IntelligenceSession> recent = client.intelligence().listSessions(50);
client.intelligence().deleteSession(session.getId());

answer.getSources() contains source-level citations. Inline [1] markers refer to sources[0]; previewRef is an opaque preview token, never a raw storage key.

Schedules

Schedule schedule = client.schedules().create(
CreateScheduleRequest.builder()
.sourceId("source-uuid")
.datasetId("dataset-uuid")
.cron("0 2 * * *")
.timezone("UTC")
.build()
);
client.schedules().trigger(schedule.getId());
client.schedules().update(schedule.getId(), UpdateScheduleRequest.builder().enabled(false).build());

Method reference

Both access styles work everywhere the language allows: client.datasets().search(id, ...) and datasetObj.search(...). Required arguments are listed first; optional arguments note their default.

client.datasets() / Dataset

MethodObject-styleArgs
list(limit?, offset?)limit, offset optional (API defaults)
create(name)name; embedding vectoramp/VectorAmp-Embedding-4B, dim 2560, metric cosine
create(name, hybrid)hybrid -> hybrid:true
create(name, dim, metric, embedding)full explicit form
create(CreateDatasetRequest)builder: dim?, metric? (cosine), embedding?, hybrid?, metadata?
get(id)id
delete(id)ds.delete()id
stats(id)ds.stats()id
search(id, query)ds.search(query)query (text, vector, or SearchRequest); top_k default 10; rerank(true), hybrid(...), filters, includeDocuments, includeMetadata
insert(id, vectors)ds.insert(vectors)vectors (VectorRecord with String or numeric id)
embed(id, texts)ds.embed(texts)texts
addText(id, text) / addTexts(id, texts)ds.addText(text) / ds.addTexts(texts)texts; AddTextsRequest for ids/metadata
listDocuments(id, limit?, cursor?, status?)ds.listDocuments(...)cursor pagination
downloadDocument(id, docId)ds.downloadDocument(docId)raw bytes
ingestSource(id, source)ds.ingestSource(source)typed builder or existing source id
ingestFiles(id, files)ds.ingestFiles(files)returns UploadSession; completeUpload(session)
ask(id, query)ds.ask(query)query (String or AskRequest); top_k default 5

client.intelligence()

MethodArgs
ask(query) / query(query)query (String or AskRequest); top_k default 5, sources on, all datasets
askStream(query) / stream(query)returns Stream<SseEvent>
createSession(title | SessionCreateRequest)optional title/workspace/dataset/metadata
listSessions(limit?)returns List<IntelligenceSession>
getSession(id) / deleteSession(id)id
appendMessage(sessionId, role, content | request)role, content, optional metadata
listMessages(sessionId, limit?)returns List<SessionMessage>

client.ingestion()

MethodArgs
listSources(limit?, offset?) / getSource(id)pagination / id
createSource(CreateSourceRequest | IngestionSourceInput)generic create
createWeb/createS3/createGCS/createGoogleDrive/createJira/createConfluence/createFileUpload(...)typed convenience creators
validateSource(sourceType, config)validate without persisting
getSourceReferences(id)active schedules + in-flight jobs (scheduleCount, activeJobCount, inUse)
deleteSource(id) / deleteSource(id, force)delete (409 if in use unless force, which also disables its schedules)
listUnusedSources() / cleanupUnusedSources()list / delete all sources nothing is using
startJob(sourceId, datasetId, pipelineId?)start ingestion
listJobs(datasetId?, limit?, offset?) / getJob(id) / retryJob(id)jobs
initializeUpload(sourceId, files) / completeUpload(sourceId, jobId, fileIds)presigned upload flow

client.connections()

MethodArgs
list(provider?)optional google/atlassian filter
create(provider, sourceType?)returns Connection (status: "pending", getAuthorizationUrl())
get(id)poll until getStatus() is connected
delete(id)revoke and delete
connect(provider, sourceType?)create + open authorization URL + poll until connected

client.schedules()

list(limit?, offset?), get(id), create(CreateScheduleRequest), update(id, UpdateScheduleRequest), delete(id), trigger(id).

Source helpers

WebSource, S3Source, GCSSource, GoogleDriveSource, JiraSource, ConfluenceSource, FileUploadSource, and GenericSource provide .of(...)/.builder(...) factories. Each maps to its API source_type (web, s3, gcs, gdrive, jira, confluence, file_upload). Embedding helper: EmbeddingConfig.openai("small" | "large").