Skip to main content
POST

Authorizations

Authorization
string
header
required

Bearer token used by every /v1/* endpoint. Two kinds of key work here:

  • Long-lived partner key (cxh_pk_live_*) — issued by CollectiveX Health (contact partners@collectivex.health). Keep it server-side only — never expose it in client bundles or mobile app code. This rule is absolute and does not change for any endpoint.
  • Short-lived session key — minted server-side via POST /v1/session-tokens from a long-lived key. Safe to hand to a native mobile client only — not a browser or other JavaScript context, see "API keys" in the description above. It's scoped to /v1/query and /v1/chat only, expires in at most 60 minutes, and can't mint further session keys. POST /v1/session-tokens itself only ever accepts the long-lived key.

Body

application/json

Request body for POST /v1/query. Uses additionalProperties: false (mirrors Zod .strict() on the server, matching ChatRequest's convention). Exactly one of question or messages is required — not both. Retrieval tuning knobs are intentionally not accepted here either, for the same reason as /v1/chat: we curate retrieval, partners don't tune.

question
string
required

A single question, plain string. The preferred shape for /v1/query callers — no message envelope needed. Internally wrapped into a single-element UIMessage before being passed to the same pipeline that /v1/chat uses, so behavior is identical to sending that text as the sole message on /v1/chat.

Minimum string length: 1
messages
object[]

Single-element AI SDK v6 UIMessage array, provided for continuity with callers already building /v1/chat request bodies who want to switch endpoints with a minimal diff. Unlike /v1/chat, this array MUST contain exactly one message with role "user" — /v1/query has no multi-turn concept. Sending more than one message, or a message with a different role, is a 400 invalid_request (use /v1/chat with stream:false instead if you need conversation history).

Required array length: 1 element
response_format
enum<string>
default:text

BETA. When omitted or "text", the response is byte-for-byte the SyncResponse this endpoint has always returned — no behavior change. When "structured", the response ADDS a structured_answer field (machine-readable sections/claims/citations) alongside the unchanged answer/citations fields; nothing is removed or replaced. This field, and the shape it produces, may change in a future minor version while in beta.

Available options:
text,
structured

Response

Accepted. The job exists and is running in the background. Poll poll_url (a path relative to the API base URL you called) until status is terminal. Nothing about the answer is known yet — this response deliberately carries no result.

202 body from POST /v1/jobs. A receipt, not a result: it tells you where to poll and how long the job will be readable.

request_id
string<uuid>
required

UUID minted for this submission. The job's background execution reuses it for tracing, so quote it to support.

id
string<uuid>
required

The job's id. Use it with GET /v1/jobs/{id}.

job_type
string
required

Always query today — see JobResponse.job_type.

Example:

"query"

status
enum<string>
required

Always queued on the 202 — execution begins in the background immediately after this response is sent.

Available options:
queued
poll_url
string
required

Path to poll, relative to the API base URL you called (e.g. /v1/jobs/8f14e45f-…). Deliberately not an absolute URL: the host you called is the host to poll.

Example:

"/v1/jobs/8f14e45f-ceea-467e-adc0-7a1a6b5f6b28"

expires_at
string<date-time>
required

When the job and its result stop being readable — one hour after submission. Fetch your result before then.

created_at
string<date-time>
required

When the job was created.