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());
}
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");
Insert, add text, and search
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))
);
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
| Method | Object-style | Args |
|---|---|---|
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()
| Method | Args |
|---|---|
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()
| Method | Args |
|---|---|
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()
| Method | Args |
|---|---|
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").