> ## Documentation Index
> Fetch the complete documentation index at: https://api.globalwebindex.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Stream responses with Agent Spark (beta)

Agent Spark is a beta Spark API endpoint that streams a chat response as [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) (SSE). Instead of waiting for one JSON response, you receive the answer in stages: provisional thinking text, the sources Spark used, cited insights, and a finished Markdown answer.

Use Agent Spark when end users or agents ask **open-ended questions** and you need progress, citations, and a finished Markdown answer in one stream. The v1 **`/v1/spark-api/generic`** endpoint is a separate, narrower tool: it returns one JSON payload, but only tends to produce **meaningful insights when the prompt is deliberately structured** (audience, question, and often dataset or timeframe). See [Structuring a Query](https://api.globalwebindex.com/docs/spark-api/getting-started/structuring-query.md) and the [Quickstart](https://api.globalwebindex.com/docs/spark-api/getting-started/insight.md) for that pattern.

> [!NOTE]
>
> Agent Spark is in beta. The request and event formats can change.

## Agent Spark and `/v1/spark-api/generic`

Both endpoints accept the same core chat payload: a required **`prompt`**, plus optional **`chat_id`**, **`dataset_code`**, **`dataset_codes`**, and **`docked_audiences`**. They share authentication and the same insight engine, but they solve different product problems.

| | **`POST /v1/spark-api/generic`** | **`POST /beta/spark-api/agents/spark`** (Agent Spark) |
| - | - | - |
| **Who writes the prompt** | **Your integration** (templates, forms, or generated text you control) | **Your users or agent** (free text, follow-ups, vague wording) |
| **Prompt quality bar** | High. Broad or chatty prompts often miss the mark. Plan audience + question (+ scope) as in [Structuring a Query](https://api.globalwebindex.com/docs/spark-api/getting-started/structuring-query.md). | Lower for integrators. Spark does more interpretation inside the agent workflow. |
| **Response shape** | One JSON document when the request completes | Named SSE events until `end` or `error` |
| **Latency UX** | Wait for the full answer | `loading` events with provisional thinking text, then the final Markdown answer |
| **Insights** | JSON **`insights`** array with **`id`** and **`text`** | **`insights`** event with **`id`**, **`text`**, and audience **`origins`** |
| **Sources** | **`sources`** with **`topics`**, **`audiences`**, **`datasets`**, **`locations`**, **`waves`** | **`sources`** event with **`location_groups`**, **`timeframe_groups`**, **`attribute_codes`**, **`questions`**, **`namespaces`**, and richer audience metadata |
| **Natural language** | Introductory **`message`** plus insight bullets | **`natural_language_response`** (Markdown) and **`sources_available`** |
| **Extra request fields** | Optional **`limit`** (1–20) | No **`limit`** |
| **Errors** | Standard Spark API JSON errors | JSON before the stream, or in-band **`error`** with **`code`**, **`message`**, **`retryable`** |

Choose **generic** for repeatable, backend-driven lookups where you invest in prompt design once. Choose **Agent Spark** for chat surfaces, copilots, and agents where you cannot enforce that prompt shape on every request.

## Send a request

Send a `POST` request to `/beta/spark-api/agents/spark` with the same `Authorization` header you use for other Spark API requests. Keep the connection open to read the stream.

```bash theme={null}
curl -N -X POST "https://api.globalwebindex.com/beta/spark-api/agents/spark" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{ "prompt": "What is Gen Z car ownership in the UK?", "dataset_code": "ds-core" }'
```

### Request body

| Field | Type | Required | Description |
| - | - | - | - |
| `prompt` | string | Yes | The chat prompt. |
| `chat_id` | string | No | An existing chat ID. Use it to ask a follow-up question in the same conversation. |
| `dataset_code` | string | No | A root dataset code that scopes the chat, for example `ds-core`. |
| `dataset_codes` | array of strings | No | Dataset codes from the same dataset tree. A non-empty `dataset_codes` list takes precedence over `dataset_code`. |
| `docked_audiences` | array of strings | No | Audience UUIDs to dock to the chat. |

For more on dataset scoping, see [Working with multiple data sets](https://api.globalwebindex.com/docs/spark-api/getting-started/working-with-multiple-data-sets.md).

## Read the stream

A successful request returns `200` with `Content-Type: text/event-stream`. Each frame has an `event` name and a JSON `data` payload that includes the `chat_id`. Events arrive in this order:

| Event | Fires | Description |
| - | - | - |
| `chat_init` | Once, first | Confirms the stream opened and returns the `chat_id`. |
| `loading` | Up to three times | Provisional Markdown thinking text in `natural_language_response`. This text can differ from the final answer. |
| `sources` | Once | The scope of the response: `topics`, `audiences`, `location_groups`, `timeframe_groups`, `datasets`, `attribute_codes`, `questions`, and `namespaces`. |
| `insights` | Once | The cited insights. Each insight has an `id`, `text`, and `origins` with the audience `id` and `name`. |
| `natural_language` | Once | The finished Markdown answer in `natural_language_response`, plus a `sources_available` boolean. |
| `end` | Once, last | Marks a successful end of the stream. |

```text Response theme={null}
event: chat_init
data: {"chat_id":"e1a593b8-3cf0-40c3-a7a8-a3b7dc0a2bd7","message":"ChatSSE opened successfully. Let's chat!"}

event: loading
data: {"chat_id":"e1a593b8-3cf0-40c3-a7a8-a3b7dc0a2bd7","natural_language_response":"#### Thinking..."}

event: sources
data: {"chat_id":"e1a593b8-3cf0-40c3-a7a8-a3b7dc0a2bd7","topics":["car ownership"],"audiences":[],"location_groups":[],"timeframe_groups":[],"datasets":[],"attribute_codes":[],"questions":[],"namespaces":[]}

event: insights
data: {"chat_id":"e1a593b8-3cf0-40c3-a7a8-a3b7dc0a2bd7","insights":[{"id":"32c56b1d-3b42-4b68-a356-ab71360f6a0e","text":"11% of Gen Z car or van owners own an electric car or van.","origins":{"audiences":[{"id":"259f6394-436c-4801-b83b-bbc926e8b4b9","name":"Generation: Gen Z"}]}}]}

event: natural_language
data: {"chat_id":"e1a593b8-3cf0-40c3-a7a8-a3b7dc0a2bd7","natural_language_response":"Answer","sources_available":true}

event: end
data: {"chat_id":"e1a593b8-3cf0-40c3-a7a8-a3b7dc0a2bd7"}
```

To ask a follow-up question, send a new request with the `chat_id` from the stream.

## Handle errors

Agent Spark reports errors in two ways, depending on whether the stream has started.

**Before the stream starts**, the API returns a JSON error response with an HTTP status code:

| Status | Meaning |
| - | - |
| `400` | Bad request. |
| `401` | Missing or invalid API key. |
| `422` | The request could not be processed, for example `invalid_request` or `audience_not_resolved`. |
| `429` | Rate limited (`rate_limited`). |
| `502` | Upstream error (`upstream_error`). |
| `504` | Upstream timeout (`upstream_timeout`). |
| `500` | Internal server error. |

Agent Spark-specific errors include `code`, `message`, and `retryable` fields, and `chat_id` when you provided one:

```json theme={null}
{
  "chat_id": "e1a593b8-3cf0-40c3-a7a8-a3b7dc0a2bd7",
  "code": "upstream_timeout",
  "message": "upstream timeout",
  "retryable": true
}
```

**After the stream starts**, a terminal failure arrives as an `error` event with the same `code`, `message`, and `retryable` fields. No `end` event follows an `error` event, so treat `error` as the end of the stream.

```text theme={null}
event: error
data: {"chat_id":"e1a593b8-3cf0-40c3-a7a8-a3b7dc0a2bd7","code":"upstream_timeout","message":"upstream timeout","retryable":true}
```

If `retryable` is `true`, you can retry the request.
