> ## Documentation Index
> Fetch the complete documentation index at: https://jesse-7a8b4a1d.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Events

> The JSON events a search emits. One catalogue, whether you stream them or read the result.

Every event is a JSON object with a `type` string. Ignore types you do not use. They reach you as the `data:` payload of an SSE frame from [the event stream](/streaming), and the `final` event is also what `result` on [the run](/run) returns.

A run that gets to write its own ending emits four events in this order: `final`, `cost`, `usage`, `done`. A run whose process went away can emit none of them, so do not make `done` the only thing that ends your loop.

## `final`

The table to store. It is sent once, just before `cost`, `usage` and `done`.

| Field | Type | Meaning |
| - | - | - |
| `type` | string | `"final"` |
| `table` | Result\[] | Rows that passed every filter. May be shorter than `target`. See [Result row](/result). |
| `target` | integer | The target you asked for. |
| `met` | boolean | `true` when `table.length >= target`. |
| `filters` | object\[] | The original filters, in funnel order. Each item is `{index, title, criterion}`. `index` is 1-based and matches `by_filter[].index` on a row. |
| `stopped` | boolean | Present and `true` whenever the run ended early, for any reason: you called stop, the run hit its spend ceiling, your balance ran out mid-run, the deadline passed, or the process it was running in went away. It says the table is partial. It does not say why; the run's `status` does. See [The run](/run). |
| `stopped_at` | string | Present whenever `stopped` is. Short name of the stage that was in progress, such as `round 2, filter 1 (…)`. |

## `done`

```json theme={null}
{ "type": "done" }
```

On any early end: `{ "type": "done", "stopped": true }`. It is the last event of a run that got to write one. An interrupted run can end without it, so treat a terminal `status` as the end of the run and `done` as a convenience.

## `error`

```json theme={null}
{ "type": "error", "message": "Human-readable reason" }
```

A search that failed. The server also sends `cost`, `usage` and `done` after it, and the run lands as `error`. A search that was never started does not produce this event at all: a refused `POST /v1/searches` answers an HTTP status instead, and [Errors](/errors) lists them.

## `cost`

```json theme={null}
{ "type": "cost", "stage": "Finished", "usd": 1.234 }
```

`usd` is the running dollar total to show a user. Replace the displayed number with the latest `usd`. It is not a delta. The last value before `done` is the final cost. On a run that ended early the last `stage` is `Stopped` rather than `Finished`. See [Cost](/cost).

## `usage`

Provider call and token counts: `gemini`, `jev` and `parallel`, plus `page_fetch` when pages were fetched outside the search provider. Sent once, between `cost` and `done`. It is diagnostic. Do not show it as a cost, and do not add anything in it to the figure from `cost`.

## `plan`

How the query was split. Safe to ignore if you only render `final`.

| Field | Type | Meaning |
| - | - | - |
| `analysis` | string | Short reading of the query. |
| `entity_kind` | string | What the rows are: `company`, `professional`, `researcher`, `product`, `clinician`, `lawyer`, `book`, `paper`, `music_video`, `exhibition`, `conference`, `freelancer`, `news`, or `both`. People found at organizations are still `company` rows, with the person named by the last filter. `entity_label` is the readable name. |
| `target` | integer | Requested result count. |
| `today` | string | `YYYY-MM-DD` used to resolve relative dates. |
| `recency_after_date` | string | Start of the query’s time window, or `""`. |
| `recency_before_date` | string | End of a closed range, or `""` when the window runs through today. |
| `discovery` | object | `title`, `objective`, `search_queries` (string\[]), `ordering_rationale`, `entity_kind`, `after_date`, `before_date`. |
| `filters` | object\[] | Ordered filters. See below. |

Each filter:

| Field | Type | Meaning |
| - | - | - |
| `title` | string | Column name. |
| `criterion` | string | Yes/no test applied to one entity. Dates inside it are absolute. |
| `search_hints` | string\[] | Two short suffixes appended to the entity name for that filter’s web search. |
| `expected_pass_rate` | string | `high`, `medium`, or `low`. Wider filters run first. |
| `after_date` | string | `YYYY-MM-DD` publish-date floor sent to web search for this filter, or `""`. |
| `before_date` | string | `YYYY-MM-DD` last day of a closed range, or `""`. Not sent to web search. The event date must fall on or before it. |
| `ordering_rationale` | string | Why this filter sits where it does. |

## `progress`

```json theme={null}
{ "type": "progress", "have": 4, "target": 50, "round": 0, "leads": [] }
```

`round` is 0-based. `leads` uses the same row shape as `final.table`, for rows finished so far. `have` is `leads.length`.

## Live table events

These drive a results grid while the run is in progress. `round` is 0-based. Filter `index` is 1-based. Discovery is index 0.

| type | Fields |
| - | - |
| `funnel_open` | `round`, `filters: [{index, title, criterion}]` |
| `funnel_init` | `round`, `rows: [{name, details}]`. The starting set for this round. |
| `funnel_filter_start` | `round`, `index`, `title`, `criterion` |
| `funnel_criterion` | Same fields, sent when a filter is rewritten by relaxation. |
| `funnel_filter_done` | `round`, `index`, `title`, `criterion`, `kept` (names), `strict_kept` (count that passed the original wording), `cells`. `cells` maps a name to `{rationale, urls}`. `urls` are the pages that rationale was written from. |
| `filter_relaxed` | `round`, `index`, `attempt`, `stopped`, `why`, `title`, `criterion`, `search_hints`. When `stopped` is false, also `filter_index` (0-based), `previous_criterion`, `kept`, `checked`. |
| `status` | `stage`, `message`, and sometimes `round` and `index`. `stage` is a short label such as `plan`, `search`, `filter`, `relax`, or `pre_discovery`. |

## Other events

You can ignore these. They are the background trail.

* `round_start` — `{round, needed, message}`
* `stage_start` — `{round, index, mode, title, detail}`. `mode` is `discovery` or `filter`.
* `stage_done` — `{round, index, table, note}`. `table` is the survivors of that stage.
* `search_done` — `{round, index, result_count, queries}`
* `source_screen` — `{round, index, kept, dropped, message}`. Sent only when pages were dropped before extraction.
* `candidates` — `{round, index, leads}` names extracted for the universe.
* `pre_discovery` — remembered sources before web search: `filters`, `fan_out_queries`, `source_types`, `sources`, `rows`.
* `discovery_brief` — `source_types`, `company_types`, `people_types`, `roles`, `companies`, `people`, `counterparties`, `search_queries`, `broaden_queries`, `pivot_queries`, `angles`, `why`.
* `discovery_policy` — later-round source choice: `where_to_start`, `why`, `queries`, `exploit`, `types`, `avoid`, `bottleneck`.
* `entity_checks`, `entity_search`, `verification`, `verify_searches` — per-entity progress.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.