The Lens
The Lens is the ordered list of output columns of a prism. It decides what answers holds in the default json format, the answer columns of a CSV, TSV or JSON Lines row, and the Lens columns the app shows on a result page, on the Integrate tab and in downloads. A prism has one Lens, and you edit it on the prism's Lens tab.
The automatic Lens
Section titled “The automatic Lens”Until you save a custom one, a prism uses the automatic Lens, with one column per question named by the question key.
| Question type | Output | support-routing column |
|---|---|---|
| Choice | top |
team |
| Yes / No | label |
urgent, Yes from 0.5 |
| Scale | level |
tone |
The automatic Lens follows the prism, so a question added in a new version adds its column. Saving a custom Lens freezes the columns, so a new question adds nothing until you add a column for it. Reset to automatic goes back.
Outputs
Section titled “Outputs”Each column reads one question and returns one output. The values below come from this stored answer, which format=raw returns:
{ "id": "0192f5c1-7c1a-7b3e-9f55-3c1d2e4a5b6c", "ref": "TCK-8812", "prism": "support-routing", "version": 3, "status": "ok", "error": null, "took_ms": 640, "created_at": "2026-09-23T09:14:02.187Z", "answers": { "team": { "type": "choice", "value": "billing", "probabilities": { "billing": 0.91, "technical": 0.05, "other": 0.03, "insufficient_information": 0.01 }, "confidence": 0.88 }, "urgent": { "type": "yes_no", "probability": 0.83 }, "tone": { "type": "scale", "level": "annoyed", "probabilities": { "calm": 0.12, "annoyed": 0.71, "angry": 0.17 } } }}| Type | Output | Returns | json and jsonl |
|---|---|---|---|
| Choice | top |
The chosen option | "billing" |
| Choice | probability |
The chosen option's probability | 0.91 |
| Choice | all |
Every option's probability | {"billing": 0.91, ...} |
| Yes / No | label |
Yes, No or Unsure, from the column's cutoffs | "yes" |
| Yes / No | probability |
The probability of yes | 0.83 |
| Scale | level |
The most probable level | "annoyed" |
| Scale | number |
That level's position, 1 for the lowest | 2 |
| Scale | average |
The expected level number, to two decimals | 2.05 |
| Scale | probability |
The most probable level's probability | 0.71 |
| Scale | all |
Every level's probability | {"calm": 0.12, ...} |
CSV and TSV carry labels instead of keys, such as Billing, Yes and Annoyed, and an all cell reads Billing 0.91; Technical support 0.05; Other 0.03; Not enough information 0.01. Formats has the details. Probabilities are decimals from 0 to 1 in every format.
average is 1 × P(lowest) + 2 × P(next) and so on, so 0.12 × 1 + 0.71 × 2 + 0.17 × 3 = 2.05 here. It tells you where between the ends of the scale the answer sits, which level alone hides.
A Choice top whose stored value is null returns null, and so does its probability.
Column names
Section titled “Column names”A column's name is the key in answers and the header in a CSV row. The default name is the question key, with _probability, _all, _number or _average added for extra outputs, such as team_probability.
Names are snake_case and unique. A column can't take a field key or one of the row names result_id, ref, version, status, error and created_at.
Yes / No cutoffs
Section titled “Yes / No cutoffs”A label column turns the probability of yes into a word with two cutoffs:
no_below: below it, the answer is No.yes_from: at it or above, the answer is Yes.
Between the two, the answer is Unsure. Without yes_from, Yes starts at no_below and there is no Unsure band. The automatic Lens uses no_below 0.5. no_below is strictly between 0 and 1. yes_from is at most 1 and above no_below, or above 0.5 when no_below is absent. The app's sliders set whole percents from 5% to 95%.
With no_below 0.4 and yes_from 0.6:
| Probability of yes | json |
csv |
|---|---|---|
| 0.35 | "no" |
No |
| 0.4 | "unsure" |
Unsure |
| 0.59 | "unsure" |
Unsure |
| 0.6 | "yes" |
Yes |
| 0.83 | "yes" |
Yes |
An Unsure band is how you send the doubtful cases to a person instead of guessing.
Lens edits relabel old results
Section titled “Lens edits relabel old results”Changing the Lens is not a new version and never asks the model again. Every read applies the current Lens to the stored answers, so a new cutoff relabels old results. If you raise yes_from to 0.9, the result above reads "urgent": "unsure" the next time you fetch it, from the API, the app or a download.
That is useful when you tune cutoffs against real results. It also means answers in json is not frozen. When a Lens edit must not change what your code reads, request format=raw, which returns the stored answers, and apply your own cutoffs. See Formats.
When columns go away
Section titled “When columns go away”- A result made by a version that lacks a column's question gets
nullfor that column, or an empty cell. - Saving a prism version that removes a question drops the custom Lens columns that read it, in the same save. The app names those columns and warns first.
- If a save drops every custom column, the prism falls back to the automatic Lens.
- Renaming or removing a column carries the same warning.
Code that reads answers should expect a column to be missing or null rather than fail on it.
A custom Lens
Section titled “A custom Lens”The support-routing examples in these docs use this Lens, which the app stores as JSON:
{ "columns": [ { "name": "team", "question": "team", "output": "top" }, { "name": "team_probability", "question": "team", "output": "probability" }, { "name": "urgent", "question": "urgent", "output": "label", "no_below": 0.4, "yes_from": 0.6 }, { "name": "tone", "question": "tone", "output": "level" }, { "name": "tone_average", "question": "tone", "output": "average" } ]}