Streaming AI Search

    Streaming AI Search

    Stream the AI Search summary over the same POST /desearch/ai/search as the first call, when you want progressive output instead of one JSON body.

    Who this page is for

    Humans

    You already got a 200 with "streaming": false on the Search API first-call page. Flip to "streaming": true on REST when a UI or agent should show the summary as it is written. Read cost from response headers, not the stream body.

    Agents / tool authors

    Prefer a non-stream first call for a single tool result (search plus optional completion in one JSON object). Use streaming only when the runtime can consume an HTTP stream (SSE) and you need progressive summary output. Official SDKs (ai_search / aiSearch) currently force non-stream. Call REST for "streaming": true.

    When to stream vs not

    GoalSettingWhere
    One JSON body for first success or tests"streaming": falseSearch API first call
    Progressive summary over the wire"streaming": trueThis page

    OpenAPI default for streaming is true. Always set the boolean explicitly so you do not accidentally stream into a client that expects one JSON object.

    REST request

    • Method / path: POST /desearch/ai/search
    • Base: https://api.desearch.ai
    • Auth: Authorization: $DESEARCH_API_KEY (raw key in examples). See Auth and API keys.
    • Accept: text/event-stream (live Content-Type on success is text/event-stream)
    • Body: same fields as the first call (prompt, tools, optional count, date filters, result_type) plus "streaming": true
    • For a streamed summary path, keep result_type at LINKS_WITH_FINAL_SUMMARY unless you have a verified reason to change it

    curl (buffering off)

    bash
    curl --no-buffer --request POST 'https://api.desearch.ai/desearch/ai/search' \ --header "Authorization: $DESEARCH_API_KEY" \ --header 'Content-Type: application/json' \ --header 'Accept: text/event-stream' \ --data '{ "prompt": "summarize recent AI search benchmarks", "tools": ["web"], "result_type": "LINKS_WITH_FINAL_SUMMARY", "count": 10, "streaming": true }'

    Capture response headers (-D - or -i) so billing headers are visible. Do not commit the key.

    SSE wire format (live)

    Verified against a live streaming: true response (2026-09-24):

    FactObserved
    HTTP status200
    Content-Typetext/event-stream
    Frame shapedata: <json> lines, blank line between frames
    event: / id: fieldsNot present
    Cost / usage in bodyNot present (headers only)

    Event type order

    1. One search event: {"type":"search","content":[ ... result objects ... ]}. Result objects include title, link, snippet, and highlights (a list). Other fields may appear. Do not require fields you have not verified.
    2. Many text events: {"type":"text","role":"summary","content":"<token chunk>"} (incremental summary tokens).
    3. One final completion event: {"type":"completion","content":"<full summary string>"}.

    Parse only data: lines. Read JSON type to decide how to handle each frame. Do not invent named SSE event: channels.

    Sample frames (redacted / shortened)

    text
    data: {"type": "search", "content": [{"title": "…", "link": "https://…", "snippet": "…", "highlights": ["…"]}]} data: {"type": "text", "role": "summary", "content": "Recent AI"} data: {"type": "text", "role": "summary", "content": " search"} data: {"type": "completion", "content": "Recent AI search …"}

    Concatenate successive text chunks where role is summary for a progressive UI. Prefer the final completion.content as the full summary string when the stream ends cleanly.

    SDKs: use REST for streaming

    PackageVersion checkedStream support
    desearch-py1.2.1ai_search hardcodes "streaming": false. No stream iterator. Use REST.
    desearch-js1.5.0aiSearch always sends streaming: false (even if the caller adds the field). Use REST.

    Do not document SDK stream helpers, async generators, or streaming=True as a working SDK path until a published package ships them and they are re-verified.

    Non-stream first call with SDK tabs stays on the Search API guide.

    Billing on stream

    Successful billable responses expose cost only through headers:

    HeaderMeaning
    X-Desearch-Cost-UsdCost in USD for the request
    X-Desearch-Usage-CountBillable usage units
    X-Desearch-ServicePricing service / endpoint key
    X-Desearch-CurrencyCurrency (for example USD)

    Related headers often seen with the stream: cache-control: no-cache, x-proxy-buffering: no.

    Streaming responses keep their body shape as the SSE frames above. Do not claim the stream JSON includes cost_usd. This page does not list product dollar rates.

    Failures

    Before the stream body, or instead of one

    Align with Rate limits and errors:

    StatusMeaningWhat to do
    401Missing or invalid keyFix auth
    402Out of creditsTop up in Console
    422Invalid parametersFix the body against the API reference
    429Rate limitedExponential backoff. Do not tight-loop
    5xxServer failureShort delay and retry. Check status

    Mid-stream disconnect

    If the connection drops mid-stream, treat the result as incomplete. Retry with the same policy as other failed requests (rate-limit guide). A retry is a new request and may be billable again. Do not invent SSE error type values or status codes inside the stream channel. None were verified in the live smoke for this page.

    Verify

    • Non-stream first call already works (streaming: false)
    • Stream request uses curl --no-buffer (or equivalent) and "streaming": true
    • Response Content-Type is text/event-stream
    • Frames are data: {json} only. Order is search, then text repeated, then completion
    • Billing is read from X-Desearch-* headers, not the body
    • No SDK stream helper is assumed

    Next