Questions

Choice, score and probability questions — structured instructions and criteria, what the API returns for each, weighted levels, the reserved other option and minimum confidence.

Questions are what a decision answers about the state. A decision has 1 to 64 questions, all answered in one engine call: Jev evaluates each of them independently and in parallel against the same state. Each question becomes a key in the response's result and confidence objects, in the order you define them.

TypeUse it forresult[key]Example
choicePicking one option: a team, a category, a toolOne of your option values (string)"sales"
scorePlacing the state on an ordered scaleThe label of the most likely level (string)"high"
probabilityA yes/no questionProbability of yes, from 0 to 10.9412

Common properties

PropertyTypeRequiredDescription
keystringYessnake_case, unique in the decision. Becomes the JSON key in the response.
typestringYeschoice, score or probability.
instructionsstring, object or arrayYesThe question the engine answers: text, or structured JSON. Up to 8,000 characters (JSON counts its serialized length).
minConfidencenumberNo0 to 1. Below it, the decision applies the fallback action — see below.

Choice

{
  "key": "route",
  "type": "choice",
  "instructions": "Which team should receive this lead?",
  "options": [
    { "value": "sales", "description": "high intent, ready to talk to sales" },
    { "value": "sdr", "description": "some intent, needs qualification" },
    { "value": "nurture", "description": "early stage, send content" }
  ]
}
  • options needs at least 2 and at most 254 options, plus other — 255 in total, Jev's maximum.
  • value follows the key rules and must be unique within the question.
  • description tells the engine when the option applies: text or JSON, up to 2,000 characters. It is optional — omit it, or set it to null, when the value says it all ("yes_refund"). Descriptions decide accuracy: contrast similar options and add exclusions such as "not for existing customers".
  • Order matters. Jev can lean toward the option listed first. Test important questions with the options reordered in the Playground and check that the answer stays the same.

The reserved other option

Every choice question has an other option. Dcision adds it automatically as the last option, with the description none of the options above. It can't be removed, but you can describe it yourself by including it in options — wherever you put it, it is moved to the end:

{ "value": "other", "description": "not about our product, or a language we don't support" }

Without other, an engine is forced to pick the least wrong option. With it, "none of these" becomes an explicit answer: when a choice question answers other and no policy matched first, the decision applies its fallback action with action_reason.type = "other_option". See Policies and actions.

What the API returns

  • result.route — the chosen option, for example "sales" (or "other").
  • confidence.route — how far the chosen option stands above an even split between all the options, from 0 to 1 — see Confidence.
  • With ?include=probabilities, probabilities.route holds one probability per option, other included.

Policies on a choice answer can only use eq and neq. The comparison ignores case and surrounding spaces.

Score

{
  "key": "priority",
  "type": "score",
  "instructions": "How urgent is it to answer this lead?",
  "scale": ["low", "medium", "high", "critical"]
}
  • scale lists 2 to 10 levels from lowest to highest. A level is a label (up to 2,000 characters) or a structured rubric with a label. Labels must be unique.
  • result.priority is the label of the most likely level — not an average — and confidence.priority says how concentrated the distribution is around it.
  • scores.priority is the weighted level: the probability-weighted average of the levels, counted from 1. In the scale above, 2.81 sits between medium (2) and high (3), closer to high. Use it to act between levels.
  • With ?include=probabilities, probabilities.priority holds one probability per label, in scale order.

Policies compare levels, numbered from 1: in the scale above low is 1 and critical is 4.

  • On the answer ("on": "output"), a rule uses the level number ("value": 3) or the label ("value": "high"), with any operator: { "field": "priority", "operator": "gte", "value": "high", "action": "escalate" } matches high and critical. A label that isn't in the scale never matches.
  • On the weighted level ("on": "score"), a rule compares scores.priority with a number: { "field": "priority", "on": "score", "operator": "gte", "value": 3.5, "action": "escalate" } fires when the weight leans toward critical, even if high is the most likely level.

Probability

{
  "key": "purchase_intent",
  "type": "probability",
  "instructions": "Does this lead have real intent to buy in the next 30 days?",
  "criteria": {
    "yes": "asks for pricing, a demo, a quote or a start date",
    "no": "just browsing, student, vendor or spam"
  }
}
  • criteria.yes and criteria.no are optional — text or JSON, up to 2,000 characters each — and say what counts as yes and as no. Keep them aligned with the instructions: yes should describe the yes case.
  • result.purchase_intent is the probability of yes, between 0 and 1, rounded to 4 decimals.
  • confidence.purchase_intent is |2p − 1|: the distance from a coin flip. 0.03 (a confident no) and 0.97 (a confident yes) both have confidence 0.94; 0.5 has confidence 0.
  • With ?include=probabilities, probabilities.purchase_intent is { "yes": p, "no": 1 − p }.

Policies compare the probability with a number, for example { "field": "purchase_intent", "operator": "gte", "value": 0.8, "action": "continue" }.

Structured instructions and criteria

Jev reads structure natively. Wherever a question has text — instructions, option description, score levels, criteria.yes and criteria.no — you can send a JSON object or array instead. Structure helps when a question has several parts, or when it needs supporting data such as a taxonomy, a schema or a database row: the keys label each part.

{
  "key": "duplicate_candidate",
  "type": "probability",
  "instructions": {
    "potential_duplicate": { "name": "John Smith", "location": "Oakland, California", "last_employer": "Google" },
    "question": "Is the resume in `resume` for the same person as `potential_duplicate`?"
  }
}
  • Point at data with backticks. Name state fields and keys of the instruction between backticks — `resume`, `ticket.messages[0].text` — to tell the engine exactly what to look at.
  • Give options a rubric. An option description such as { "what": "Charges, invoices, refunds", "not_for": "Order tracking", "examples": ["I was charged twice"] } sharpens the boundary between neighbors.
  • Limits are the same as for text, measured on the serialized JSON: 8,000 characters for instructions, 2,000 for an option description, a score level or a criterion. Objects and arrays can't be empty.
  • In the editor, paste a JSON object or array into the field: it is stored as structure and marked structured. Anything that isn't valid JSON stays text.

Structured score levels

A score level can be an object with a label — the label is what result returns and what policies compare; the whole object is what the engine reads:

{
  "key": "bug_severity",
  "type": "score",
  "instructions": "If this describes a bug, how severe is it for the customer?",
  "scale": ["cosmetic", "minor", "major", { "label": "critical", "rubric": "outage, data loss, security issue or money at risk" }]
}

The label is 1 to 255 characters; the whole level, serialized, up to 2,000. Plain and structured levels can be mixed in one scale. The editor adds levels as plain labels and shows structured ones with a braces icon — the Support Ticket Triage template starts with one.

Minimum confidence

Any question can set minConfidence between 0 and 1. When the answer's confidence is below it and no policy matched first, the decision applies its fallback action with action_reason.type = "low_confidence":

{ "type": "low_confidence", "question": "route", "confidence": 0.52, "minConfidence": 0.8 }

In the editor, the Minimum confidence toggle starts at 80%. Without it, low-confidence answers still continue.

For a probability question, confidence is |2p − 1|, so a minimum confidence flags a band of probabilities around 0.5: 0.8 flags every p between 0.1 and 0.9, 0.6 every p between 0.2 and 0.8. The editor shows the band next to the slider. See Confidence and probabilities and Handling low confidence and other.

Tips

  • Ask one thing per question. Split "is this urgent spam?" into a probability (spam) and a score (urgency) — they cost one call either way.
  • Phrase instructions as a literal question about the state: "Which team should receive this lead?".
  • Prefer probability for yes/no — the number is easier to threshold than a two-option choice.
  • Prefer score for ordered levels — policies can then use gte/lte on the level and thresholds on the weighted level.
  • Write option descriptions as criteria, not labels, and make neighbors mutually exclusive. If the Playground flags a near tie, the descriptions overlap.
  • Put business facts in context, not in every instruction.
  • Keep math, counts and dates in code and send the results in the state.
  • Order matters: when several questions answer other or fall below their minimum confidence, the first one in question order is reported in action_reason.

More in Writing good questions.

On this page