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

# Emit Tool

> Return schema-validated structured data beside the model's prose.

An emit tool is a tool whose arguments **are** the result. The model calls it when it has structured data to hand back — a list of ids, a set of options, a chart spec — and PromptJuggler runs nothing external: it validates the payload against the tool's schema and delivers it, both on the run and on the live [stream](/concepts/streaming).

It exists for chat experiences that need to stream prose *and* return structure at once. A support agent can stream "Let me pull those up…", call an emit tool with the matching record ids, and keep streaming its answer — the ids arrive as typed data your frontend renders as cards, while the prose stays plain readable text.

## Configuration

* **Name** and **description** — as with any tool; the description tells the model when to emit.
* **Payload schema** — a JSON Schema for the arguments. This is the contract: the model's payload is validated against it, and consumers can rely on the shape.

The model may call an emit tool multiple times in one run — emit three cards, keep writing, emit two more.

## What you get back

* **On the run** — `emitted` on the [run response](/api/overview): an ordered list of `{ tool, payload }` for every accepted emit. This is the authoritative record. The completion webhook carries only the run id and status, so fetch the run to read `emitted`.
* **On the stream** — a `data` event per emit as it happens, carrying the same `{ tool, payload }`. The [browser SDK](/sdks/browser/overview) maintains these as `runs[runId].data`, so a chat renders cards the moment the model produces them.

The payload is the tool's arguments verbatim — no wrapping, no transformation.

## Validation

PromptJuggler validates every payload against the schema before accepting it, and caps it at 64 KB. A payload that doesn't conform (or is too large) is rejected back to the model as a tool error it can correct on the next turn — so the data your callers receive is always valid and bounded. Only accepted emits appear in `emitted` and on the stream; a rejected-then-retried call surfaces only the accepted retry.

<Note>
  Emit tools need API access, so they are available on all paid plans. See the [chatbot guide](/guides/building-a-chatbot) for an end-to-end example.
</Note>
