SDK
Explanation — what & why
The Vectros SDK is a typed client library for the platform's REST API. Rather
than hand-rolling HTTP requests, signing headers, and decoding paginated
envelopes, you construct one client and call typed methods grouped by resource:
client.records.createRecord(...), client.search.content(...),
client.inference.ragInference(...), and so on.
The SDK is generated from the API specification, not written by hand. The spec is the single source of truth: the same definition drives the API gateway, the rendered API reference, and the SDK. That is why the method names, request shapes, and response types in your editor match the API exactly — they are the same artifact, expressed in TypeScript.
The SDK does the mechanical work you would otherwise repeat in every project:
- Typed requests and responses — your editor autocompletes fields and flags mistakes before you run anything.
- Streaming as async iteration — chat, RAG, and document-ask endpoints are
server-sent-event streams; the SDK exposes them as async iterables you can
for awaitover. - A uniform list envelope — list, lookup, and version endpoints return a cursor-paginated envelope (see below) so draining a full result set is one loop, the same every time.
Language coverage — state it honestly
The SDK is generated for Node, Java, and Python. In this repository, only the Node SDK is exercised end-to-end — the verified, staging-tested call shapes that back this documentation are all Node. Java and Python are generated from the same spec and follow the same resource grouping, but their idioms and parity are not verified in-tree. Treat the Node snippets here as the authoritative contract and confirm the equivalent call in Java/Python against the generated API reference for those languages.
The list envelope (cursor pagination)
List, lookup, and version endpoints return a uniform envelope:
{ data: T[], nextCursor: string | null }
To drain every page, feed nextCursor back as startFrom until it comes back
null:
const ids: string[] = [];
let cursor: string | null | undefined;
do {
const page = await client.schemas.listSchemas(
cursor ? { startFrom: cursor, limit: 100 } : { limit: 100 },
);
ids.push(...(page.data ?? []).map((s) => s.id!));
cursor = page.nextCursor;
} while (cursor);
Two endpoints are not enveloped and do not paginate this way:
client.search.content(...)returns a results object directly (its hits are onresults), withlimit/offsetfor paging.getUsagereturns its usage payload directly.
How-to
Install
npm install @vectros-ai/sdk
Construct a client
The client takes a token and a target environment (the API base URL):
import { VectrosClient } from '@vectros-ai/sdk';
const client = new VectrosClient({
token: process.env.VECTROS_API_KEY!, // sk_*, ssk_*, or st_*
environment: 'https://api.vectros.ai', // staging: https://api.staging.vectros.ai
});
token accepts any of the three credential types — a root key (sk_*), a
scoped permanent key (ssk_*), or a short-lived scoped token (st_*). The
client makes no distinction; the platform enforces each credential's reach.
Sub-clients are grouped by resource tag:
| Sub-client | Covers |
|---|---|
client.records | structured records |
client.schemas | record/surface schemas |
client.documents | documents (ingest, upload, retrieve) |
client.folders | folder hierarchy |
client.search | unified search |
client.inference | chat, RAG, document-ask, model catalog |
client.identity | users, orgs, clients |
client.auth | ping, scoped-token mint, and related auth calls |
First call — define a schema, write a record, read it back
// 1. Define a record type. HYBRID indexing = keyword + semantic.
const schema = await client.schemas.createSchema({
typeName: 'patient',
displayName: 'Patient Record',
indexMode: 'HYBRID',
allowedSurfaces: ['record'],
fields: [
{ fieldId: 'name', fieldType: 'string', required: true, searchable: true },
{ fieldId: 'notes', fieldType: 'string', searchable: true },
{ fieldId: 'department', fieldType: 'string', filterable: true },
{ fieldId: 'email', fieldType: 'string', required: true },
],
lookupFields: [{ fieldName: 'email', unique: true }],
capabilities: { auditHistory: true },
});
// 2. Write a record. (Synthetic, clearly-fictional data only.)
const record = await client.records.createRecord({
typeName: 'patient',
schemaId: schema.id!,
payload: {
name: 'Jane Doe',
notes: 'presents with hypertension and complains of chest pain',
department: 'cardiology',
email: 'jane.doe@example.test',
},
});
// 3. Read it back.
const loaded = await client.records.getRecord({ id: record.id! });
Expected result: createRecord returns immediately with
indexStatus: 'PENDING_INDEX'; indexing is asynchronous. getRecord returns
the stored record, and once indexing completes indexStatus becomes
'INDEXED'.
Search across records and documents
searchContent is unified — it returns both record and document hits unless you
narrow with contentTypes. It is not enveloped; read results.
const results = await client.search.content({
query: 'hypertension chest pain',
mode: 'HYBRID', // TEXT | SEMANTIC | HYBRID
limit: 50,
});
for (const hit of results.results ?? []) {
console.log(hit.documentId, hit.semanticScore, hit.textScore);
}
Stream a RAG answer
Streaming endpoints are async iterables. Each yielded event has an event
discriminator (search_results, content_delta, done, and so on):
const stream = await client.inference.ragInference({
query: 'What treatment is recommended for stage 1 hypertension?',
search: { mode: 'HYBRID', limit: 5 },
maxTokens: 256,
});
let answer = '';
for await (const ev of stream) {
if (ev.event === 'content_delta') answer += ev.delta ?? '';
if (ev.event === 'done') console.log('charged:', ev.inferenceBalanceCentsCharged);
}
Plain chat (client.inference.chatInference) and document-scoped ask
(client.inference.documentAsk) follow the same async-iterable pattern.
Drain a paginated list
See the envelope loop in the Explanation section above — that is the canonical
drain pattern for any list*, lookup*, or get*Versions call.
Update strategies — full replace vs. partial patch (SDK 0.26+)
The default update is a full replace (PUT-style): you send the complete desired body.
await client.records.updateRecord({
id: record.id!,
body: {
typeName: 'patient',
schemaId: schema.id!,
payload: { name: 'Jane Doe', notes: 'updated note', department: 'cardiology', email: 'jane.doe@example.test' },
},
});
A partial patch (RFC-7386 merge-patch) is available on records, documents,
and folders with SDK 0.26+: send only the fields you want to change; omitted
fields are left untouched, and an explicit null deletes a field.
// (SDK 0.26+) — patch only the notes field.
await client.records.patchRecord({
id: record.id!,
body: { payload: { notes: 'patched note' } },
});
Create a record by type name or by schema id (SDK 0.26+)
With SDK 0.26+, createRecord accepts either typeName or
schemaId (you no longer need both) — supply whichever you have on hand.
Earlier SDK pins expect both; the first-call example above passes both, which
works on every version.
Reference
Client construction
| Option | Type | Notes |
|---|---|---|
token | string | sk_*, ssk_*, or st_*. Required. |
environment | string | API base URL, e.g. https://api.vectros.ai (production) or https://api.staging.vectros.ai (staging). Required. |
Sub-clients (by tag)
records, schemas, documents, folders, search, inference,
identity, auth. Method names mirror the API operations
(createRecord, getRecord, updateRecord, patchRecord, deleteRecord,
listRecords, lookupRecords, getRecordVersions, getRecordTombstone,
createSchema, ingestDocument, uploadDocument, getDocument,
createFolder, chatInference, ragInference, documentAsk,
listInferenceModels, createUser/createOrg/createClient, ping, and so
on). The complete, exhaustive list of methods, parameters, and field types is in
the generated API reference — link to it by name rather than recreating it here.
Envelope shape
| Field | Type | Meaning |
|---|---|---|
data | T[] | The page of items. |
nextCursor | string | null | Pass back as startFrom for the next page; null means no more pages. |
Applies to list*, lookup*, and get*Versions. Does not apply to
search.content or getUsage.
Index modes
HYBRID (keyword + semantic, the general-purpose default), SEMANTIC
(meaning-based only), TEXT (keyword only). Declared per schema (records) or
per document at ingest.
Concurrency
Record and document updates accept an optional expectedVersion in the body for
optimistic concurrency; a mismatch is rejected with HTTP 409. Omit it for
last-writer-wins.
Version reality (read before pinning)
- The API spec is at version 0.27.0. The generated Node SDK is a continuous-integration artifact built from that spec — it is not committed to this repository, so you install it from the package registry.
- Among the in-repo consumers, the CLI and MCP server bundle a 0.26
staging SDK build. (The React toolkit — an auth/UI library, not a data
client — accepts any SDK
>=0.9.0and is dev-tested against a 0.23 staging build.) If you depend on a consumer's bundled SDK, check its pin rather than assuming the latest. - 0.26+ surface — these require SDK 0.26 or newer and are absent on older pins:
patchRecord/patchDocument/patchFolder(RFC-7386 merge-patch).createRecordwithtypeNameorschemaId(the either-or form). Passing both works on all versions.- Because the reference web apps still pin a 0.23 build, these calls are reachable from the SDK, CLI, and MCP server but not through those apps' own UI. If you fork a reference app, plan to wire these calls in yourself.
- 0.27 added an optional lower-cost global-region path for inference
(
allowGlobalRegionon chat / RAG / document-ask) for tenants entitled to it; see Search and RAG reference.
Notes & limits — what the SDK does NOT do
- Schemas have no patch. Schema updates are full-replace (PUT) only; there is
no
patchSchema. - Folders cannot be moved or reparented after creation. There is no move operation.
- There is no identity patch. Users, orgs, and clients update by full replace.
search.contentandgetUsageare not paginated by the cursor envelope — do not look fornextCursoron them.- Indexing is asynchronous. A freshly created/ingested item is
PENDING_INDEXand not immediately searchable; poll its status (or its appearance in search) before asserting it is queryable. - Java/Python parity is unverified in this repository. Only Node is tested end-to-end here.
Where to go next
- cli.md — provision schemas, contexts, and scoped keys from the terminal instead of writing this by hand.
- mcp.md — expose these same operations to an agent as tools.
- blueprints.md — declare a whole schema set + access profile in one file.
- The generated API reference — the exhaustive, per-endpoint contract the SDK is generated from.