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.",
"Intelligence can answer questions across 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.

Intelligence​

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").