Typed TypeScript/JavaScript SDK to discover, inspect, probe, call, and audit real-world API capabilities from your own agents and applications.
@qverisai/sdk v0.9.0 is the latest tested release. It is a thin, typed wrapper over the QVeris REST API (discover, inspect, probe, call, credits, usage, ledger). It has zero runtime dependencies — it uses the platform fetch (Node.js 18+) — and mirrors the wire semantics of the Python SDK and the MCP server.
next_action and usage/ledger records to review an uncertain outcome before submitting again.includeProbe: true; the default interface still has three tools.The optional AI adapter requires AI SDK 5–7 and Zod 3.25.76 or 4. Upgrade applications using AI SDK 4 before installing the adapter. The core client has no runtime dependencies and does not require these peers.
Capability Query can spend credits. Set an explicit max_credits ceiling when using it; a Probe quote does not reserve that price or authorize spending.
npm install @qverisai/sdk
Requires Node.js 18+ (native fetch). The package is ESM-only.
The SDK reads your API key from the QVERIS_API_KEY environment variable:
export QVERIS_API_KEY="sk-..."
Create a key in Dashboard / API Keys. Create the client from the environment, or pass configuration explicitly:
import { Qveris } from '@qverisai/sdk';
const qveris = Qveris.fromEnv();
// or
const explicit = new Qveris({ apiKey: 'sk-...' });
Endpoint priority is explicit baseUrl > QVERIS_BASE_URL > the built-in default. API keys never select the endpoint. To target a custom endpoint, pass baseUrl explicitly or set QVERIS_BASE_URL:
const client = new Qveris({ apiKey: 'sk-...', baseUrl: 'https://qveris.ai/api/v1' });
The default workflow is discover → call, then optionally audit what happened. inspect and probe are conditional checks, not mandatory stages. All methods return promises.
For provider comparison, Inspect every candidate when current scope or a complete contract must be confirmed; a Discover summary is not confirmation. Probe every candidate when the comparison requires a current quote. Reuse may preserve an exact route, never business parameters or results: build parameters from the current request, and make a fresh Call for current, latest, today, or other time-sensitive data.
import { Qveris } from '@qverisai/sdk';
const qveris = Qveris.fromEnv();
// 1. Discover capabilities with natural language (free)
const discovered = await qveris.discover('weather forecast API', { limit: 5 });
const params: Record<string, unknown> = { city: 'London' };
const matchesType = (type: string, value: unknown) => {
if (type === 'string') return typeof value === 'string';
if (type === 'integer') return typeof value === 'number' && Number.isFinite(value) && Number.isInteger(value);
if (type === 'number') return typeof value === 'number' && Number.isFinite(value);
if (type === 'boolean') return typeof value === 'boolean';
if (type === 'array') return Array.isArray(value);
if (type === 'object') return value !== null && typeof value === 'object' && !Array.isArray(value);
return false;
};
const supportsRequest = (candidate: (typeof discovered.results)[number]) => {
if (!candidate.params) return false;
const definitions = new Map(candidate.params.map((parameter) => [parameter.name, parameter]));
if (definitions.size !== candidate.params.length) return false;
return Object.entries(params).every(([name, value]) => {
const parameter = definitions.get(name);
return Boolean(parameter && matchesType(parameter.type, value) &&
(!parameter.enum || parameter.enum.some((allowed) => Object.is(allowed, value))));
}) &&
candidate.params.every((parameter) =>
!parameter.required || Object.prototype.hasOwnProperty.call(params, parameter.name),
);
};
let tool = discovered.results.find(supportsRequest);
// 2. Inspect only if discovery omitted the contract needed for selection
if (!tool) {
const details = await qveris.inspect(
discovered.results.slice(0, 3).map((candidate) => candidate.tool_id),
{ searchId: discovered.search_id },
);
tool = details.results.find(supportsRequest);
}
if (!tool?.params) throw new Error('No candidate exposed a current city parameter contract');
// 3. Use samples only as a template; apply this request's actual value
const missing = tool.params.filter((parameter) => parameter.required && params[parameter.name] === undefined);
if (missing.length) throw new Error(`Missing inputs: ${missing.map((parameter) => parameter.name)}`);
const result = await qveris.call(tool.tool_id, {
parameters: params,
searchId: discovered.search_id,
maxResponseSize: 20480,
});
console.log(result.success, result.result);
// 4. Audit the final charge outcome
const usage = await qveris.usage({ execution_id: result.execution_id, summary: true });
const ledger = await qveris.ledger({ summary: true, limit: 5 });
console.log(usage.total, ledger.total);
There is no connection to close — the client is stateless over fetch.
Stateless also means no hidden semantic route, schema, price, or result cache. Preserve the real search_id in the active application flow. Any host-managed reuse must isolate account/API endpoint/authorization/session, rebuild business values from the current request, and expire metadata explicitly.
An explicit empty parameter list means the tool takes no parameters; an omitted parameter list means the projection did not provide the contract. Use inspect when details needed for selection or a valid request are missing/stale, or when candidates require comparison. Use probe only when parameters need validation, a current quote is needed for a budget decision, or a preflight was explicitly requested. A quote is not a reserved price or a substitute for user authorization:
const inspected = await qveris.inspect(tool.tool_id, { searchId: discovered.search_id });
const quote = await qveris.probe(tool.tool_id, {
parameters: params,
checks: ['schema', 'quote'],
});
new Qveris(config) accepts:
| Field | Env var | Default | Description |
|---|---|---|---|
apiKey | QVERIS_API_KEY | — (required without credentialProvider) | API key, sent as Authorization: Bearer ... |
credentialProvider | — | — | Async bearer provider; mutually exclusive with apiKey |
credentialAudience | — | — | Audience forwarded to the credential provider |
credentialScopes | — | [] | OAuth scopes forwarded to the credential provider |
baseUrl | QVERIS_BASE_URL | https://qveris.ai/api/v1 | API base URL; constructor option has highest priority |
timeoutMs | — | 30000 | Default request timeout (call defaults to 120000) |
Qveris.fromEnv(overrides?) builds the client from QVERIS_API_KEY and accepts the same non-key options.
Registered confidential Agent Runtimes can use AgentDelegationCredentialProvider
to exchange a user access token at https://qveris.ai/api/v1/oauth/token.
Configure the client with the same credentialAudience and a subset of
credentialScopes. Delegation tokens stay in memory, are never refreshed, and
fail closed on audience or scope widening. Keep the confidential client secret
on a trusted server, never in browser or mobile code.
The source-generated symbol reference lists every public class, method, option, response type, and AI SDK integration exported by the current package. It is regenerated from TypeScript source and checked for drift in CI.
Qveris| Method | REST endpoint | Purpose |
|---|---|---|
discover(query, options?) | POST /search | Find capabilities; view: 'routing' returns compact routing cards (free) |
inspect(toolIds, options?) | POST /tools/by-ids | Fetch full capability metadata (free) |
probe(toolId, options?) | POST /tools/probe | Validate parameters and request a zero-cost quote |
call(toolId, options) | POST /tools/execute | Execute a capability; model records attribution and respondWith selects full, summary, or JSONPath fields |
credits() | GET /auth/credits | Current credit balance and buckets |
usage(filters?) | GET /auth/usage/history/v2 | Audit request status and charge outcome |
ledger(filters?) | GET /auth/credits/ledger | Inspect final credit balance movements |
Option shapes:
discover(query, { limit?, sessionId?, view?, lang?, timeoutMs? })inspect(toolIds, { searchId?, sessionId?, timeoutMs? }) — toolIds accepts a single string or an array; an empty array short-circuits and returns an empty response without a network request.probe(toolId, { parameters?, checks?, liveBudget?, subUserId?, timeoutMs? })call(toolId, { parameters, searchId?, sessionId?, subUserId?, model?, maxResponseSize?, respondWith?, timeoutMs?, compatibilityMode? })Use the same non-empty subUserId for Probe and Call when provider OAuth is scoped to an end user. Omit it otherwise; it is an identity, not a token.
For framework tools, bind the authenticated identity in host code: getQverisTools(qveris, { subUserId: authenticatedUser.id }). Create a tool set per end user and use the same identity for any host-side Probe. The identity is not exposed in the model tool schema, and model-generated arguments cannot override it.
Projection options are opt-in. Omitting respondWith keeps compatibility auto-delivery: maxResponseSize defaults to 20KB and oversized results use the overflow envelope. Explicit respondWith: 'full' forces complete inline result.data and takes precedence over a finite maxResponseSize; a platform hard-limit failure is reported as response_too_large instead of truncation. Summary mode preserves at least one usable payload: a summary object, lossless data, or truncated_content together with full_content_file_url. These fields may coexist. Neither statistics nor a URL is guaranteed by the mode alone. Check success first, then field availability; failed summary calls retain an empty data object.
Paid calls are strict single-submit: HTTP redirects are not followed, and 429/503 and projection errors are returned without replay. The deprecated compatibilityMode: 'legacyOptionalFields' opt-in permits exactly one replay without an optional field rejected by an older service; invalid projections remain errors.
usage(...) and ledger(...) take filter objects such as start_date, end_date, summary, bucket, charge_outcome, execution_id, search_id, direction, entry_type, min_credits, max_credits, limit, page, page_size.
All methods return typed results that track the public OpenAPI contract. Unknown backend fields pass through, so newer API metadata will not break older SDK clients.
SearchResponse → results: ToolInfo[]; ToolInfo has tool_id, name, description, categories (objects or strings), capabilities, params, examples, stats, billing_rule, expected_cost, and (discover only) why_recommended.ExecuteResponse with execution_id, success, result, error_message, billing (CompactBillingStatement), cost, remaining_credits.UsageEventsResponse → items: UsageEventItem[], total, summary.CreditsLedgerResponse → items: CreditsLedgerItem[], total, summary.import type { ExecuteResponse } from '@qverisai/sdk';
function explain(result: ExecuteResponse): string {
if (!result.success) return `failed: ${result.error_message}`;
const charged = result.billing?.summary ?? 'no billing info';
return `ok (${charged}); remaining=${result.remaining_credits}`;
}
The installation page's copied v1 JSON is a short-lived public selection hint, not an SDK request object. Use the canonical CLI consumer when accepting it from a user:
qveris call --context @context.json --params @params.json
That boundary rejects credentials, PII, prompts, payloads, executable parameters, duplicate/prototype keys, and unsupported required capabilities. It ignores ordinary future fields with structured warnings and refreshes expired availability/price/permission snapshots through Discover. Inspect and Probe are conditional; quotes gate only explicit budget/quote policy or detected paid risk. Do not pass the JSON directly to qveris.call or trust an old search_id.
An application that deliberately implements the same flow with the SDK must keep parameters separate, use public IDs only as discovery hints, return candidates rather than guess for service-only context, require an exact current tool match, call inspect or probe only when current validation requires it, and pass the fresh discovery search_id to call. Reconcile final settlement with usage and ledger; absent final audit data is unknown, not charged or free.
The typed client is a natural tool backend for any LLM agent framework. Tell the model to use discover then call by default and to invoke inspect only when it needs missing or refreshed detail. Because discover returns why_recommended, parameter guidance, and expected_cost when available, the model should not inspect every candidate by habit.
Expose the QVeris workflow as Vercel AI SDK tools. ai and zod are peer dependencies (import from the @qverisai/sdk/ai subpath):
npm install @qverisai/sdk ai zod
import { generateText, stepCountIs } from 'ai';
import { openai } from '@ai-sdk/openai';
import { Qveris } from '@qverisai/sdk';
import { getQverisTools } from '@qverisai/sdk/ai';
const qveris = new Qveris({ apiKey: process.env.QVERIS_API_KEY! });
const { text } = await generateText({
model: openai('gpt-4o'),
tools: getQverisTools(qveris), // qveris_discover / qveris_inspect / qveris_call
stopWhen: stepCountIs(6),
prompt: 'Find a stock quote capability and quote AAPL.',
});
The adapter descriptions encode the same shortest-safe-path policy: qveris_inspect is optional, and a model may call directly from a sufficiently detailed discovery result.
The Python SDK ships adapters for LangChain/LangGraph, OpenAI Agents SDK, CrewAI, AutoGen, LlamaIndex, and Pydantic AI as well.
Every failed request throws QverisApiError — an Error subclass carrying:
| Property | Description |
|---|---|
status | HTTP status (0 network error, 408 timeout, 402 insufficient credits, …) |
details | The server-returned error body, when available |
observability | Request context (operation, endpoint, request id) for diagnostics |
cause | Lower-level transport/runtime cause, when available |
import { Qveris, QverisApiError } from '@qverisai/sdk';
const qveris = Qveris.fromEnv();
try {
await qveris.call('some.tool.v1', { parameters: {} });
} catch (err) {
if (err instanceof QverisApiError && err.status === 402) {
// insufficient credits — err.message includes the purchase link
}
}
result.success reflects the capability call only. Do not treat it as the final billing outcome — confirm charges with usage(...) / ledger(...).
>=18 (native fetch). ESM-only.Versions
0.1.xof the@qverisai/sdknpm package were an early MCP-focused SDK, since superseded by@qverisai/mcp. The typed REST client documented here starts at0.2.0.
Capability Detail reads a published CAP contract. Capability Query executes a CAP and may consume credits. max_credits is a spending ceiling, not a reserved quote. Query submits once, including after HTTP errors, timeouts, redirects, or an invalid success response. For an uncertain outcome, review usage and settlement before submitting another Query. Resolve and selection-token APIs are not exposed until their public contracts are available.
The adapter returns Discover, Inspect, and Call by default. Enable Probe when the agent needs parameter validation or a current schema/quote; Probe does not execute the capability or reserve its price. Probe uses the same host-controlled end-user identity as Call. The adapter example uses @qverisai/sdk/ai. Inspect the CAP's parameters and restrictions and construct valid current parameters before executing it; the example assumes the inspected contract supports the symbol below.
import { getQverisTools } from '@qverisai/sdk/ai';
const contract = await qveris.capabilityDetail('MKT.BARS.EOD');
const outcome = await qveris.capabilityQuery({
capability_id: contract.capability_id,
parameters: { symbol: 'AAPL' },
max_credits: 10,
});
const tools = getQverisTools(qveris, { includeProbe: true });
The optional AI adapter supports AI SDK 5–7 and Zod 3.25.76 or 4. AI SDK 4 uses a different tool schema interface.
@qverisai/sdk on npmpackages/js-sdkWas this page helpful?