API
Kolmo is a topic-conditioned classifier. Send text chunks and a topic (or a freeform question); the API returns only the chunks that are actually about that topic.
/v1/vslm/predictModels
Section titled “Models”Kolmo v1.0.0 has three models. Choose one by setting the agent field in your request.
| Model | Set agent to |
Behavior | Use when |
|---|---|---|---|
| General | general_context_agent |
Balanced precision/recall. Filters more aggressively. | Most workloads. |
| Highest recall | highest_recall_context_agent |
Recall-first. Keeps softer signals that the general model may drop. | Misses are expensive and you can’t afford to drop a relevant chunk. |
| SEC | sec_context_agent |
Built for SEC filings and regulatory disclosures. | Your chunks come from 10-Ks, 10-Qs, 8-Ks, S-1s, or similar filings. |
All models use the same endpoint and the same request shape. Only the agent value changes.
Request an API key from ZettaQuant, then set:
export ZQ_BASE_URL="https://api.zettaquant.ai"export ZQ_API_KEY="<your API key>"Auth is a single header: x-api-key: $ZQ_API_KEY.
Quickstart
Section titled “Quickstart”curl -X POST "$ZQ_BASE_URL/v1/vslm/predict" \ -H "x-api-key: $ZQ_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "agent": "general_context_agent", "query": "tariffs and trade policy", "sentences": [ "We expect tariffs on imported steel to increase COGS by $50M in 2026.", "Trade-policy shifts hit our China-sourced product lines.", "Our company picnic was wonderful this summer.", "Same-store sales grew 4% year over year." ] }'import os, requests
BASE_URL = os.environ["ZQ_BASE_URL"]API_KEY = os.environ["ZQ_API_KEY"]
def filter_relevant(chunks, query, agent="general_context_agent"): r = requests.post( f"{BASE_URL}/v1/vslm/predict", headers={"x-api-key": API_KEY}, json={"agent": agent, "query": query, "sentences": chunks}, timeout=120, ) r.raise_for_status() return r.json()["relevant_sentences"]async function filterRelevant(chunks, query, agent = "general_context_agent") { const res = await fetch(`${process.env.ZQ_BASE_URL}/v1/vslm/predict`, { method: "POST", headers: { "x-api-key": process.env.ZQ_API_KEY, "Content-Type": "application/json", }, body: JSON.stringify({ agent, query, sentences: chunks }), }); if (!res.ok) throw new Error(`${res.status} ${await res.text()}`); return (await res.json()).relevant_sentences;}Response:
{ "agent": "general_context_agent", "model_id": "vslm_general_relevancy", "topic_used": "Government policies, regulations, and duties imposed on international trade, including tariffs and import/export restrictions.", "topic_source": "zettaquant", "relevant_sentences": [ "We expect tariffs on imported steel to increase COGS by $50M in 2026.", "Trade-policy shifts hit our China-sourced product lines." ], "total_sentences": 4, "relevant_count": 2, "scores": [ {"sentence": "We expect tariffs on imported steel to increase COGS by $50M in 2026.", "relevant": true, "relevant_prob": 1.0}, {"sentence": "Trade-policy shifts hit our China-sourced product lines.", "relevant": true, "relevant_prob": 0.9996}, {"sentence": "Our company picnic was wonderful this summer.", "relevant": false, "relevant_prob": 0.0}, {"sentence": "Same-store sales grew 4% year over year.", "relevant": false, "relevant_prob": 0.0} ], "tokens_saved": 19, "input_tokens": 50, "kept_tokens": 31}relevant_sentences: kept chunks, verbatim, in input order.scores[]: one row per input chunk (kept and dropped), withrelevant_probin[0, 1]. Apply your own threshold client-side if needed.tokens_saved/input_tokens/kept_tokens: token accounting per call.
Specifying the topic
Section titled “Specifying the topic”Provide exactly one of:
| Mode | Field | Use when |
|---|---|---|
| Explicit | topic (string) |
You know the exact topic string. No LLM step. |
| Variants | descriptions (array) |
You have multiple phrasings you’ve tested. v1 uses index 0. |
| Freeform | query (string) |
You only have the question. ZettaQuant writes the topic. |
Chunks
Section titled “Chunks”The sentences field accepts any string chunks: individual sentences, whole paragraphs, log lines, bullet points. Put one chunk per array element for each unit of text you want a keep/drop decision on.
Chunks longer than the tokenizer cap (max_length, default 512 tokens) are truncated, so paragraphs are fine.
Batching past 512
Section titled “Batching past 512”def filter_relevant_batched(chunks, query, agent="general_context_agent", batch_size=512): kept = [] for i in range(0, len(chunks), batch_size): kept.extend(filter_relevant(chunks[i:i + batch_size], query, agent)) return keptHighest-recall model
Section titled “Highest-recall model”Same code, different agent:
kept = filter_relevant(chunks, "M&A activity and strategic alternatives", agent="highest_recall_context_agent")Request reference
Section titled “Request reference”| Field | Type | Required | Notes |
|---|---|---|---|
agent |
string | yes | Model: general_context_agent, highest_recall_context_agent, or sec_context_agent |
sentences |
string[] | yes | 1–512 chunks per call (sentences, paragraphs, anything) |
topic |
string | one of | Explicit topic |
descriptions |
string[] | one of | Pre-written variants; v1 uses index 0 |
query |
string | one of | Freeform question; topic auto-generated |
max_length |
int | no | Per-chunk tokenizer cap, 64–512, default 512 |
Response reference
Section titled “Response reference”| Field | Type | Notes |
|---|---|---|
agent, model_id |
string | Echoes what ran. |
topic_used |
string | Topic string actually filtered on: topic, descriptions[0], or the ZettaQuant-generated one. |
topic_source |
string | provided, descriptions, or zettaquant. |
relevant_sentences |
string[] | Kept chunks, verbatim, in input order. |
total_sentences, relevant_count |
int | Counts. |
scores |
{sentence, relevant, relevant_prob}[] |
One row per input chunk (kept and dropped). relevant_prob is in the range [0, 1]. |
tokens_saved, input_tokens, kept_tokens |
int | Per-call token accounting. |
Errors
Section titled “Errors”| Status | Meaning | Action |
|---|---|---|
200 |
Success | — |
400 |
Bad agent value or missing topic field |
Fix the request |
401 |
Bad or missing x-api-key |
Check the header |
402 / 403 |
Plan inactive / account paused | Contact support |
429 |
Over monthly quota | Contact support for an increase |
502 |
Upstream inference or topic generation failed | Retry with backoff |
503 |
Transient capacity blip | Retry in a few seconds |
4xx errors are deterministic, so don’t retry them. 5xx errors are retryable: use exponential backoff, 3 attempts.
Usage & rate limits
Section titled “Usage & rate limits”Full usage
Section titled “Full usage”/v1/usage/mecurl -H "x-api-key: $ZQ_API_KEY" "$ZQ_BASE_URL/v1/usage/me"{ "plan": "pro", "current_period_start": "2026-09-01T00:00:00+00:00", "current_period_end": "2026-10-01T00:00:00+00:00", "usage": { "vslm": { "used": 3, "limit": 10000000, "remaining": 9999997, "percent_used": 0 } }}Counters reset at current_period_end.
Quick check
Section titled “Quick check”/v1/usage/quotaA smaller payload for dashboards or pre-call guards. Pass ?product=vslm to get the Kolmo counter.
curl -H "x-api-key: $ZQ_API_KEY" "$ZQ_BASE_URL/v1/usage/quota?product=vslm"{ "product": "vslm", "plan": "pro", "plan_status": "active", "period_id": "2026-09-01", "resets_at": "2026-10-01T00:00:00+00:00", "limit": 10000000, "used": 2380, "remaining": 9997620, "percent_used": 0.02}Rate-limit headers
Section titled “Rate-limit headers”Every successful /v1/vslm/predict response carries these headers, so you don’t have to poll /v1/usage/* on every call.
| Header | Value |
|---|---|
x-ratelimit-limit |
Your Kolmo monthly cap |
x-ratelimit-remaining |
Calls left this period |
x-ratelimit-reset |
ISO-8601 timestamp of the next period boundary |
Data handling
Section titled “Data handling”Chunks are not stored. Request bodies are discarded after the response returns. Only call-level metadata (timestamp, chunk count, model, latency) is retained for billing and rate-limit accounting.
Support
Section titled “Support”Support, quota increases, and feature requests: support@zettaquant.ai.