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 await over.
  • 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 on results), with limit/offset for paging.
  • getUsage returns 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-clientCovers
client.recordsstructured records
client.schemasrecord/surface schemas
client.documentsdocuments (ingest, upload, retrieve)
client.foldersfolder hierarchy
client.searchunified search
client.inferencechat, RAG, document-ask, model catalog
client.identityusers, orgs, clients
client.authping, 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

OptionTypeNotes
tokenstringsk_*, ssk_*, or st_*. Required.
environmentstringAPI 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

FieldTypeMeaning
dataT[]The page of items.
nextCursorstring | nullPass 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.0 and 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).
    • createRecord with typeName or schemaId (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 (allowGlobalRegion on 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.content and getUsage are not paginated by the cursor envelope — do not look for nextCursor on them.
  • Indexing is asynchronous. A freshly created/ingested item is PENDING_INDEX and 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.