Bearer token

Include your API key as a Bearer token in every request's Authorization header.

Authorization: Bearer YOUR_API_KEY

Unauthenticated requests are served as free tier (25 queries/month, 2-provider panel). Paid tiers require a bearer token. Get an API key →

TierQueries/monthPanelAPI access
Free (no key)252 providers
Personal ($8.99/mo)2003 providers
Plus ($17.99/mo)1,000Every available provider + export
Business ($149/mo)5,000Every available provider + provenance reports

Your first call

A minimal request with three providers and the default synthesizer:

# Ask three models, get a synthesized answer with consensus annotation
curl -X POST https://askarei.com/api/ask \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "question": "What are the key risks of deploying LLMs in production?",
    "providers": ["gemini", "openrouter", "cohere"]
  }'

Plus and Business plans can use every available provider at once — no fixed panel size:

-d '{
  "question": "...",
  "providers": ["gemini", "groq", "openrouter", "cohere", "cerebras", "huggingface", "anthropic", "deepseek"]
}'

Available routes

POST /api/ask Multi-provider Q&A with synthesis

Request body

FieldTypeDescription
questionrequired string The question to send to all providers.
providersrequired string[] Provider keys to query. See Providers below. At least one required.
synthesizeroptional string Provider key to use as synthesizer. Defaults to a provider not in the panel. Must differ from all queried providers.
modeloptional string Override the default model for all providers.
optimize_promptoptional boolean Rewrite the question before fan-out for clarity and specificity. Default: false.
optimizer_modeloptional string Provider key to use for prompt optimization when optimize_prompt is true.
fast_modeoptional boolean Use only the 2 lowest-latency providers from recent history instead of the full requested panel. Default: false. Overridden by panel_size if both are set.
panel_sizeoptional integer Explicit cap on how many of the requested providers actually run (must be ≥ 1). Your plan's own provider-count limit still applies on top of this.

Response

FieldTypeDescription
question string Original question as submitted.
optimized_question string | null Rewritten question, if optimize_prompt was true and succeeded.
answers object[] One entry per provider. Each has label, model, text (the raw answer), error (null on success), and cost_usd (real per-call cost in USD, or null when the provider doesn't expose token-usage data).
consensus_available boolean True if two or more providers responded successfully.
provider_count integer Number of providers that returned a successful answer.
final_answer string Synthesized answer combining the strongest, most corroborated content from all providers.
synthesizer string Provider label that performed the synthesis step.
source_count integer Number of provider answers the synthesizer used as sources.
notes string Synthesizer commentary on agreement level and notable divergences.
init_errors object Map of provider key → error message for any providers that failed to initialize.
conversation_id integer | null Persisted conversation ID for history and rating. An integer for authenticated requests like the ones documented here. null when no history row was recorded — anonymous, unauthenticated requests are answered normally but are never persisted, so they have no conversation to rate or retrieve.
consensus_sentences object[] Per-sentence breakdown of the final_answer. Each entry: text (sentence) and corroborated_by (count of raw answers that contain similar content).

Example response

{
  "question": "What are the key risks of deploying LLMs in production?",
  "optimized_question": null,
  "answers": [
    { "label": "gemini", "model": "gemini-2.5-flash", "text": "...", "error": null },
    { "label": "openrouter", "model": "openai/gpt-oss-120b:free", "text": "...", "error": null },
    { "label": "cohere", "model": "command-a-03-2025", "text": "...", "error": null }
  ],
  "consensus_available": true,
  "provider_count": 3,
  "final_answer": "Deploying LLMs in production carries several key risks...",
  "synthesizer": "gemini",
  "source_count": 3,
  "notes": "All three providers agreed on the core risk categories...",
  "init_errors": {},
  "conversation_id": 42,
  "consensus_sentences": [
    { "text": "Deploying LLMs in production carries several key risks.", "corroborated_by": 3 },
    { "text": "Hallucination is the most cited failure mode.", "corroborated_by": 2 }
  ]
}
POST /api/ask/stream Same request, progressive SSE response

Identical request body, auth, tier limits, and rate limiting to /api/ask above — the only difference is the response shape: a text/event-stream of Server-Sent Events instead of one blocking JSON payload, so a client can render each provider's answer as it arrives instead of waiting for the full panel plus synthesis. Event types (each a JSON payload under data:): provider_result (one per provider, as it completes), synthesis_result (the final combined answer, same shape as /api/ask's response body), error, and done (stream end).

POST /api/conversations/{id}/rating Rate a past answer

Thumbs up or down on a past call. Use the conversation_id from any /api/ask response.

curl -X POST https://askarei.com/api/conversations/42/rating \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"rating": 1}'  # 1 = thumbs up, -1 = thumbs down
GET /api/conversations/{id}/report Full audit report

Returns a structured, provenance-complete report for a single past call. Includes: original question, every per-provider raw answer with lexical overlap scores, the synthesized answer, and per-sentence corroboration rates computed at report-generation time.

curl https://askarei.com/api/conversations/42/report \
  -H "Authorization: Bearer YOUR_API_KEY"

Requires either the caller to be the conversation's own owner (the key/session that asked it), or a valid share_token query parameter from POST .../share below. Returns 404 for unknown IDs and for a real ID that isn't yours — the id itself is not a capability token; a paying-tier key or free-tier session only ever sees its own conversations.

POST /api/conversations/{id}/share Create a shareable report link (B2B)

Owner-only. Mints a single active, unguessable share_token for this conversation and returns a ready-to-send report URL — the explicit, revocable way to hand a report to someone else (a client, an auditor) without giving them your key. Calling it again replaces the previous link.

curl -X POST https://askarei.com/api/conversations/42/share \
  -H "Authorization: Bearer YOUR_API_KEY"
POST /api/conversations/{id}/unshare Revoke a shared report link

Owner-only. Immediately invalidates any previously-issued share_token for this conversation — the link stops working right away.

curl -X POST https://askarei.com/api/conversations/42/unshare \
  -H "Authorization: Bearer YOUR_API_KEY"
DELETE /api/conversations/{id} Permanently delete a past question

Owner-only. Permanently removes one of your own past questions and its answers from your history — cannot be undone. Same 404-for-unauthorized reasoning as .../report above: a real id that isn't yours 404s, it never reveals whether the id exists.

curl -X DELETE https://askarei.com/api/conversations/42 \
  -H "Authorization: Bearer YOUR_API_KEY"
GET /api/conversations/{id}/export Downloadable provenance report (Plus/Business)

Owner-only. Returns a downloadable JSON file with the full per-provider raw answers, synthesis, and metadata for one past call — Business tier additionally includes a human-readable provenance_text field suitable for pasting directly into a client report. Requires Plus or Business tier; a Free or Personal key gets 403 export_requires_professional. Same 404-for-unauthorized reasoning as .../report above, but with no share_token variant — export is a "get my own data" feature, not a sharing mechanism.

curl https://askarei.com/api/conversations/42/export \
  -H "Authorization: Bearer YOUR_API_KEY"
GET /api/conversations Your own conversation history

Returns up to 50 of your own past questions and their synthesis summaries, plus aggregate stats — scoped to the caller's identity, never another user's.

curl https://askarei.com/api/conversations \
  -H "Authorization: Bearer YOUR_API_KEY"
GET /api/health Health check (no auth required)
curl https://askarei.com/api/health
# → {"status": "ok"}

Available provider keys

Pass any combination of these keys in the providers array. Each runs independently against its default model.

gemini gemini-2.5-flash
groq openai/gpt-oss-120b
openrouter nvidia/nemotron-3-super-120b-a12b:free
cohere command-a-03-2025
cerebras gpt-oss-120b
huggingface gpt-oss-120b
anthropic claude-haiku-4-5 Paid plans only
deepseek deepseek-v4-flash Paid plans only
Synthesizer selection: The synthesizer must be a different provider than those in your panel. If you don't specify one, Arei picks the best available option automatically. Free-tier requests for anthropic or deepseek return a clear per-provider error rather than a real answer — see pricing for paid plans. Live per-provider success rates are public at reliability.html.

How corroboration scores work

Each sentence in final_answer appears in consensus_sentences with a corroborated_by count. A count of 3 means three independent raw provider answers contained semantically similar content — the higher the count, the more confident you can be that sentence reflects genuine model consensus rather than a single model's opinion.

Sentences with corroborated_by: 1 are worth extra scrutiny — only one model said it, and it may reflect that model's individual bias or a hallucination the others didn't share.

Transparency guarantee: Raw per-provider answers are always returned in answers[], even when synthesis fails. You can always read exactly what each model said, independent of Arei's synthesis layer.

HTTP status codes

CodeMeaningDetails
200OK Successful call. Check init_errors for any providers that failed to initialize within a successful overall request.
400Bad request No providers could be initialized, or invalid request body.
401Unauthorized Missing or invalid Authorization header.
403Forbidden The endpoint you're calling requires a higher tier than your account has — e.g. conversation export requires Plus or Business.
404Not found The resource id in the URL doesn't exist, or exists but belongs to a different account (returned identically either way, so a request can't be used to probe which conversation ids are real).
429Too many requests You've hit your plan's monthly query limit, or a short-term rate limit. See pricing for plan limits.
502Bad gateway The synthesizer call failed or returned a malformed response. Raw per-provider answers are still included in the response body.
503Service unavailable A downstream integration (e.g. the billing portal) is temporarily unreachable. Safe to retry; not a sign anything else on your account is broken.