Talkory API Documentation
One API key, one call: your prompt runs on up to 5 LLMs (GPT, Claude, Gemini, Grok, Perplexity) and comes back with an AI consensus. Base URL: https://api.talkory.ai.
curl -X POST https://api.talkory.ai/v1/query/sync \
-H "Authorization: Bearer tk_live_xxxxxxxx" \
-H "Content-Type: application/json" \
--max-time 600 \
-d '{ "prompt": "Best commuter motorcycles under $5000?" }'
# → one JSON: every model's answer + consensus
# + common answer (can take a few minutes)Endpoints at a glance
Everything the API can do, in one look. Free endpoints never touch your wallet; Paid endpoints are charged from it. Click any row for full details.
| Endpoint | Cost | What it does |
|---|---|---|
POST /v1/query/sync | Paid | Simplest way to query. One request → one JSON with all model answers + consensus. Waits until done (can take a few minutes). |
POST /v1/query | Paid | Same run, but answers stream live over SSE as each model responds. |
POST /v1/queries/:id/consensus | Paid | Generate consensus later for a query run with consensus: false. |
GET /v1/queries/:id | Free | Fetch a query's full result by id (also used for polling). |
GET /v1/queries | Free | List your past queries, newest first. |
GET /v1/health/llm | Free | Live health of all 5 LLM providers. |
GET /v1/models | Free | Models available for queries. |
GET /v1/wallet | Free | Your wallet balance. |
GET /v1/usage | Free | Requests, errors and spend for your key. |
Running a query: pick your style
| You want | Use | How it behaves |
|---|---|---|
| Simple request → response | POST /v1/query/sync | Connection stays open until the full answer is ready. May take a few minutes, so set a generous client timeout. |
| Live tokens as they arrive | POST /v1/query | SSE stream: every model's text chunks live, final done event with consensus. |
| Fire & forget + poll | POST /v1/query with stream: false | Returns 202 { id } instantly; poll GET /v1/queries/:id until done. |
Getting started
API access is available on paid plans. Recharge your wallet once in app.talkory.ai and you can create keys.
- Sign in to app.talkory.ai → Settings → API Keys.
- Click Create key, give it a name, and (optionally) set a monthly spend cap.
- Copy the key that starts with
tk_live_. It is shown only once, so store it somewhere safe. If you lose it, revoke it and create a new one. - Send it as a Bearer token on every request (see below).
Authentication
Every request must include an Authorization header with your secret key:
Authorization: Bearer tk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxScopes
Every key carries a set of scopes (permissions) that you choose when creating it. An endpoint called without the required scope returns 403 insufficient_scope.
| Scope | Grants | Cost |
|---|---|---|
health:read | GET /v1/health/llm | Free |
models:read | GET /v1/models | Free |
wallet:read | GET /v1/wallet | Free |
usage:read | GET /v1/usage | Free |
query:read | GET /v1/queries, GET /v1/queries/:id | Free |
query:write | POST /v1/query, POST /v1/query/sync, POST /v1/queries/:id/consensus | Charged from wallet |
Rate limits
Each key is limited to 30 requests per minute by default. Requests that exceed the limit receive a 429 response with a Retry-After header (seconds to wait). Responses also include X-RateLimit-Limit and X-RateLimit-Remaining.
POST /v1/query and POST /v1/query/sync share an additional limit of 10 query runs per minute and at most 2 queries in flight per key at a time (409 query_in_progress otherwise).
Errors
All errors return a consistent JSON shape:
{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded. Slow down and retry.",
"status": 429,
"requestId": "req_a1b2c3d4"
}
}Include the requestId when contacting support. Possible codes:
| HTTP | code | When it happens | What to do |
|---|---|---|---|
| 400 | invalid_request | Malformed request or failed validation | Fix the request format |
| 401 | missing_api_key | No Authorization header | Send the Bearer key |
| 401 | invalid_api_key | Key is wrong, revoked, or expired | Create a new key in settings |
| 402 | insufficient_balance | Wallet has no balance (paid endpoints) | Top up your wallet |
| 402 | paid_plan_required | Account is on the free plan (API access is a paid feature) | Recharge your wallet in app.talkory.ai |
| 402 | spend_cap_reached | Monthly spend cap hit for the key | Raise the cap or wait for next month |
| 403 | insufficient_scope | Key lacks the required scope | Use a key with the right scope |
| 400 | invalid_model | Unknown model id, or model not on your plan | Check GET /v1/models |
| 404 | not_found | Endpoint or resource does not exist | Check the URL |
| 409 | query_in_progress | Too many queries in flight for this key | Wait for a running query to finish |
| 413 | payload_too_large | Request body too large | Send a smaller payload |
| 429 | rate_limited | Too many requests | Retry after Retry-After seconds |
| 500 | internal_error | Unexpected server error | Retry; contact support with requestId |
| 503 | service_unavailable | Temporary outage / maintenance | Retry shortly |
Endpoint reference
GET/v1/health/llmFree · no wallet charge
Returns the current health of every LLM provider Talkory uses: GPT, Claude, Gemini, Grok and Perplexity. Requires a valid key with the health:read scope (the default scope on every new key). Results are cached for up to 5 minutes.
curl https://api.talkory.ai/v1/health/llm \
-H "Authorization: Bearer tk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"const res = await fetch("https://api.talkory.ai/v1/health/llm", {
headers: { Authorization: `Bearer ${process.env.TALKORY_API_KEY}` },
});
const data = await res.json();
console.log(data.status, data.providers);import os, requests
res = requests.get(
"https://api.talkory.ai/v1/health/llm",
headers={"Authorization": f"Bearer {os.environ['TALKORY_API_KEY']}"},
)
print(res.json()){
"status": "ok",
"checkedAt": "2026-06-27T10:00:00.000Z",
"providers": {
"gpt": { "status": "ok" },
"claude": { "status": "ok" },
"gemini": { "status": "ok" },
"grok": { "status": "error" },
"perplexity": { "status": "ok" }
}
}| Field | Type | Description |
|---|---|---|
status | string | ok if all providers are healthy, otherwise degraded |
checkedAt | string (ISO 8601) | When the health snapshot was taken |
providers | object | Per-provider status: each is ok or error |
GET/v1/modelsFree · no wallet charge
Lists the models available on the API. Use the returned id values in POST /v1/query. Requires the models:read scope.
{
"models": [
{ "id": "gpt", "name": "GPT-5.5", "provider": "OpenAI", "vision": true },
{ "id": "claude", "name": "Claude Sonnet 4.6", "provider": "Anthropic", "vision": true },
{ "id": "gemini", "name": "Gemini 3.1 Pro", "provider": "Google", "vision": true },
{ "id": "perplexity", "name": "Sonar Reasoning Pro", "provider": "Perplexity AI", "vision": false },
{ "id": "grok", "name": "Grok 4.3", "provider": "xAI", "vision": false }
]
}GET/v1/walletFree · no wallet charge
Your current wallet balance. Requires the wallet:read scope.
{ "balance": 12.4831, "currency": "USD", "plan": "payg" }GET/v1/usageFree · no wallet charge
Aggregated usage for the calling key. Optional ?from= and ?to= ISO timestamps (default: last 30 days). Requires the usage:read scope.
{
"period": { "from": "2026-06-04T00:00:00.000Z", "to": "2026-07-04T00:00:00.000Z" },
"requests": { "total": 218, "errors": 3, "byRoute": { "/v1/query": { "requests": 42, "errors": 1 } } },
"queries": { "total": 42, "charged": 3.1272, "totalTokens": 913202 }
}POST/v1/query/syncPaid · charged from wallet
The simplest way to use Talkory: a normal request → response API call. Send your prompt; the connection stays open while every model answers, and you get back one JSON body with all model results, the AI consensus, the common answer and confidence. No SSE to parse, no polling. Requires the query:write scope.
curl --max-time 600). If your connection drops mid-run, the run still completes and is charged. Find it via GET /v1/queries and fetch it with GET /v1/queries/:id.Error handling: if the run itself fails after it has started, the response body contains an error object (with the query id) instead of results, so always check for data.error before reading fields.
| Field | Type | Default | Description |
|---|---|---|---|
prompt | string | (required) | Your question. Input size follows your account's token limits. |
models | string[] | all plan models | Model ids from GET /v1/models (max 10). Omit to run all models on your plan. |
country | string | "global" | ISO country code (e.g. "IN") to localise answers. |
recursive | boolean | false | Round-2 self-review before consensus (slower, higher quality). |
consensus | boolean | true | false skips consensus; generate later via POST /v1/queries/:id/consensus. |
Same fields as POST /v1/query, just no stream option.
curl -X POST https://api.talkory.ai/v1/query/sync \
-H "Authorization: Bearer tk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
--max-time 600 \
-d '{ "prompt": "Best commuter motorcycles under $5000 in 2026?" }'const res = await fetch("https://api.talkory.ai/v1/query/sync", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TALKORY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ prompt: "Best commuter motorcycles under $5000?" }),
});
const data = await res.json(); // waits until the full answer is ready
console.log(data.consensus, data.commonAnswer, data.confidence, data.charged);import os, requests
res = requests.post(
"https://api.talkory.ai/v1/query/sync",
headers={"Authorization": f"Bearer {os.environ['TALKORY_API_KEY']}"},
json={"prompt": "Best commuter motorcycles under $5000?"},
timeout=600, # the run can take a few minutes
)
data = res.json()
print(data["consensus"], data["confidence"], data["charged"]){
"id": "7f9e4c2a-1b8f-4a21-9d3c-e77aa53b6c10",
"status": "success",
"models": ["gpt", "claude", "gemini", "grok", "perplexity"],
"results": [
{ "modelId": "gpt", "name": "GPT-5.5", "provider": "OpenAI", "score": 91,
"tokens": 2841, "latency": "9.4s", "text": "## Best commuter motorcycles…" }
],
"consensus": "## Consensus answer…",
"commonAnswer": "- Honda CB300R, named by every model…",
"confidence": 87,
"charged": 0.0742,
"totalTokens": 14203,
"createdAt": "2026-07-04T09:12:33.000Z"
}Same shape as GET /v1/queries/:id. status is success, or partial if some models failed (you are only charged for models that succeed).
POST/v1/queryPaid · charged from wallet
Talkory's core endpoint. Runs your prompt across up to five models in parallel, optionally refines every answer with a recursive-correction round, then produces an AI consensus and a common answer (points all models agree on). Results stream live over Server-Sent Events. Requires the query:write scope. The total cost of the run is charged from your wallet at the end and returned as charged in the final event: one number, no surprises.
| Field | Type | Default | Description |
|---|---|---|---|
prompt | string | (required) | Your question. Input size follows your account's token limits. |
models | string[] | all plan models | Model ids from GET /v1/models. If provided, must contain at least one valid model id (max 10); an empty array is rejected. Omit the field entirely to run all models active on your plan. |
country | string | "global" | ISO country code (e.g. "IN") to localise answers. If omitted, defaults to "global". |
recursive | boolean | false | Round-2 self-review: each model critiques and improves its own answer before consensus. Defaults to false if omitted. |
consensus | boolean | true | Defaults to true if omitted. false skips consensus; generate it later with POST /v1/queries/:id/consensus. |
stream | boolean | true | Defaults to true (SSE) if omitted. false returns 202 { "id" } immediately; poll GET /v1/queries/:id. |
There is no system-prompt field; output length and input limits come from your account settings in app.talkory.ai. Maximum output tokens apply per model.
curl -N https://api.talkory.ai/v1/query \
-H "Authorization: Bearer tk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Best commuter motorcycles under $5000 in 2026?",
"models": ["gpt", "claude", "gemini", "grok", "perplexity"],
"recursive": false,
"consensus": true
}'const res = await fetch("https://api.talkory.ai/v1/query", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TALKORY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ prompt: "Best commuter motorcycles under $5000?" }),
});
const reader = res.body.getReader();
const dec = new TextDecoder();
let buf = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
buf += dec.decode(value, { stream: true });
const parts = buf.split("\n\n"); // SSE events are separated by a blank line
buf = parts.pop(); // keep the (possibly incomplete) tail
for (const part of parts) {
const line = part.trim();
if (!line.startsWith("data: ")) continue; // skips ": ping" heartbeats
const raw = line.slice(6);
if (raw === "[DONE]") continue; // end-of-stream marker
const ev = JSON.parse(raw);
switch (ev.type) {
case "query_created": console.log("id:", ev.id); break; // save it
case "model_chunk": process.stdout.write(ev.chunk); break; // live text
case "done": // final payload lives on this event:
console.log(ev.consensus, ev.commonAnswer, ev.confidence,
ev.charged, ev.balance);
break;
}
}
}Every event is a data: {...} JSON line with a type field. Switch on type; the done event carries the final fields (consensus, commonAnswer, confidence, charged, balance).
The response is text/event-stream; each line is data: {...} JSON with a type field, ending with data: [DONE]. Heartbeat comments (: ping) arrive every 15 seconds.
| type | Meaning |
|---|---|
query_created | First event. Contains the query id (a UUID). Save it: if the connection drops, the run still finishes and you can fetch the result by id. |
model_stream_start | A model produced its first token. |
model_chunk | Live text chunk from one model (modelId, chunk). |
model_result | One model finished: full text, score, latency, tokens. |
model_error | One model failed or timed out. The run continues with the rest; you are only charged for models that succeed. |
round1_done / round2_start / round2_done | Round boundaries (round 2 only when recursive: true; round-1 chunks are suppressed in that mode). |
consensus_start | Consensus synthesis began. |
done | Final payload: all results, consensus, commonAnswer, confidence, charged, balance. |
error | Fatal error for the whole run. |
{
"type": "done",
"id": "7f9e4c2a-1b8f-4a21-9d3c-e77aa53b6c10",
"status": "success",
"models": ["gpt", "claude", "gemini", "grok", "perplexity"],
"results": [
{ "modelId": "gpt", "name": "GPT-5.5", "provider": "OpenAI", "score": 91,
"tokens": 2841, "latency": "9.4s", "text": "## Best commuter motorcycles…", "tags": ["Motorcycles", "Commuter", "Budget"] }
],
"consensus": "## Consensus answer…",
"commonAnswer": "- Honda CB300R, named by every model…",
"confidence": 87,
"charged": 0.0742,
"balance": 12.4089,
"totalTokens": 14203,
"avgLatency": "11.2s",
"createdAt": "2026-07-04T09:12:33.000Z"
}stream: falseSend "stream": false and the call returns instantly, with no SSE to parse. You get an id, then poll for the result:
# 1. Start the run (returns immediately)
curl -sS -X POST https://api.talkory.ai/v1/query \
-H "Authorization: Bearer tk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{ "prompt": "Best commuter bikes under $5000?", "stream": false }'
# → 202 { "id": "7f9e4c2a-1b8f-4a21-9d3c-e77aa53b6c10", "status": "running" }
# 2. Poll every 1–2s until status is no longer "running"
curl -sS https://api.talkory.ai/v1/queries/7f9e4c2a-1b8f-4a21-9d3c-e77aa53b6c10 \
-H "Authorization: Bearer tk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# → status "running" → keep polling; "success" / "partial" → full result is readyThe POST answers right away, but the final answer (consensus, results, confidence) only appears once status flips from running to success/partial. Polling with GET /v1/queries/:id is free; only the query itself is charged.
GET /v1/queries/:id using its id.POST/v1/queries/:id/consensusPaid · idempotent
Generate the consensus + common answer for a query that was run with consensus: false. If the consensus already exists it is returned as-is with charged: 0, so calling this twice never double-charges. Requires query:write.
{
"id": "7f9e4c2a-1b8f-4a21-9d3c-e77aa53b6c10",
"consensus": "## Consensus answer…",
"commonAnswer": "- Honda CB300R…",
"confidence": 87,
"charged": 0.0031,
"balance": 12.4058,
"cached": false
}GET/v1/queries/:idFree · no wallet charge
Fetch a query and its full results by id, in the same shape as the done event. Use it to poll when running with stream: false, or to recover after a dropped stream (status is "running" until the run finishes). Requires query:read.
GET/v1/queriesFree · no wallet charge
Paginated list of your API queries, newest first. ?limit= (max 100, default 20) and ?cursor= from the previous page's nextCursor. Requires query:read.
{
"queries": [
{ "id": "7f9e4c2a-1b8f-4a21-9d3c-e77aa53b6c10", "prompt": "Best commuter motorcycles…",
"status": "success", "models": ["gpt","claude","gemini"], "recursive": false,
"confidence": 87, "charged": 0.0742, "createdAt": "2026-07-04T09:12:33.000Z" }
],
"nextCursor": "d2c8a611-4b0f-4e9a-9f75-3c1b6e0a2d58"
}FAQ
How do I authenticate with the Talkory API?
Create an API key at app.talkory.ai under Settings, then send it as a Bearer token in the Authorization header on every request. Keys are shown only once and should only be used from server-side code.
What is the base URL for the Talkory API?
All Talkory API endpoints are served from https://api.talkory.ai.
What are the Talkory API rate limits?
Each API key is limited to 30 requests per minute by default. Requests over the limit receive a 429 response with a Retry-After header.
Is the GET /v1/health/llm endpoint free?
Yes. It never touches your wallet or records a charge. It requires the health:read scope, included by default on every new key, and results are cached for up to 5 minutes.
Can I get the full multi-LLM answer in a single request?
Yes. POST /v1/query/sync is a normal request → response call: it waits for all LLM responses, builds the consensus and common answer, and returns everything as one JSON body. It can take a few minutes, so set a generous client timeout (10 minutes is safe).
How do I run a multi-LLM query through the Talkory API?
POST /v1/query with a prompt runs your question across up to five models in parallel and streams every answer plus an AI consensus and common answer over Server-Sent Events. It requires the query:write scope and is charged from your wallet; the total appears as charged in the final event.
What scopes do Talkory API keys support?
health:read, models:read, wallet:read, usage:read, query:read and query:write. Pick them when creating a key in settings; only query:write endpoints are charged.
What does the Talkory health check endpoint return?
A status field (ok or degraded), a checkedAt ISO 8601 timestamp, and a providers object with a per-provider ok/error status for GPT, Claude, Gemini, Grok, and Perplexity.
Need a key? Head to your API settings.