GET /analyses/:analysisId returns more than 30 fields. This page is not about field definitions — it is about the order to read them in and how to interpret them. For the field list and types, see the API reference; for terminology, see core concepts.
The order to read in
Check status
completed. On failed, record error.code and error.message and check the item statuses.Check outputFormatting.status
extractedData follows the output-schema structure only when systemMetadata.outputFormatting.status is formatted or validation_failed. On skipped or fallback_raw there is no envelope (see below).Branch on verificationStatus
verified → approve automatically, pending_review → review queue, rejected → reject. The detailed verdicts come after that.Read extractedData and details[]
value, the reason is in reasoning, and the cause of an empty field is the reasonCode in details[].Go to agentAuditLog if you need to
The extractedData envelope
Every leaf field of the output schema carries an object with three keys instead of a bare value. Intermediate objects and array structures follow your schema exactly.
- A field that got no value still holds its place, as
value: null. The field list inextractedDataalways matches the output schema. - When a parent object itself was not produced, the paths beneath it are not created. In that case
details[]carries one entry for the parent withreasonCode: "PARENT_MISSING". reasoningis stored at the moment the analysis completes. Reading the analysis again never changes it.sourceStepis an execution order number, so it can differ from the next analysis onward if you edit the workflow. To point at a step reliably, useagentAuditLog.steps[].work_id.0andfalseare valid values. Emptiness meansnull/""/[]/{}.
When there is no envelope
fallback_raw is the most common reason for “every field in the output schema looks empty”. Branch on status before you look for values by schema key. validation_failed means assembly succeeded but some entries do not validate against the schema — the envelope is normal, and the mismatches are listed in ajvErrors[].
outputFormatting. For those, decide whether there is an envelope by checking whether outputSchema is null.Why a field is empty
A field that received no value stays in the envelope asvalue: null, and a category: "JSON_OUTPUT" entry is added to details[], lowering outputCompleteness in the Analysis Score.
reasonCodeis an extensible enum. Handle a value outside the table without erroring. It is a separate axis fromtype(a fixed set of six, such asOUTPUT_MISSINGandOUTPUT_EMPTY).reasonCode,message, andstepIdappear only onJSON_OUTPUTentries, never onSTEPorTOOLentries.messageis the grounds the responsible step recorded, while the envelope’sreasoninggives the reason at the field level. The two sentences can differ, so readreasoningfirst for field-level context.targetis a real instance path. Arrays are expanded by index, one per element (ubo_register[0].name). An empty array, or a missing array key, counts as a singleubo_registerentry.- Omni does not re-examine the original document. It never claims “the value was not in the document”; the strongest statement it makes is “it was not included in the extraction result” (
NOT_IN_FINAL_OUTPUT).
When no reason can be supplied
reasoning: null does not mean “there were no grounds” — it means “no reason could be supplied”. Reasons are not generated retroactively for past analyses.
Do not use extractionStatus
extractionStatus is a deprecated field kept for backward compatibility. It works at the level of top-level schema keys (extracted / missing), so it cannot distinguish nested fields or array elements. New integrations should use the envelope’s value together with details[]. Its emptiness rule matches the envelope (0 and false count as extracted). For an analysis with no output schema, it returns a map keyed by the top-level keys of extractedData.
Reading the verdict values
The response holds three levels of similarly named verdicts, each with a different value set.failed makes it rejected, all passed makes it verified, and anything else is pending_review. summary.overall_decision is the same aggregate, so passed → verified, needs_review → pending_review, and failed → rejected. findings[].result is that same action result mapped for the UI (needs_review → warning).
confidence vs confidenceScore
confidenceScore can accompany a low confidence.score. The classic case is every step passing while the output schema comes back empty. Put confidence.score and details[] alongside verificationStatus in your auto-approval conditions. The weights and level bands are in core concepts.
Which playbook produced this verdict
An analysis freezes the playbook as it was at run time and returns it asplaybookSnapshot. Editing the workflow afterwards leaves the grounds of past analyses untouched.
playbookSnapshot from analyses marked frozen. outputSchema is frozen at run time in the same way.
Reading the audit log
agentAuditLog is the step-by-step execution record. Unlike the top-level fields, it uses snake_case (work_id, executed_at, duration_ms).
- Identifying a step:
stepis the execution order andwork_idis the fixed ID of the playbook action. It corresponds toworkflowActions[].workIdfromGET /workflows/:workflowId. - Step verdicts:
status(passed/needs_review/failed) andreasoningare what the Summary tab shows as the reasoning line in the dashboard.ruleis the instruction that step carried out. - External engine calls: judge failure from
successanderror_codeinmcpcalls[]. There is no HTTP status code.fallback_to_rag: truemeans it fell back to document search after the engine failed. - To see the same calls organized by action, use
rawActionResults.{action}.mcpResults[]. That side uses camelCase (durationMs,errorCode,fallbackToRag). - A step that never ran does not appear in
systemMetadata.workflowHistory[]either. The full step definitions are inworkflowActionson the workflow response, and an unexecuted step is recorded indetails[]asSTEP_NOT_EXECUTED.
A pattern for downstream handling
- Showing a reviewer the
target,reasonCode, andmessagefromdetails[]alongside the envelope’sreasoningmakes the cause much faster to find. - Re-analyzing the same profile after improving the items issues a new
analysisId. The earlier result is kept, and you can compare them with the run selector in the dashboard. - When you need a report a person can read, get the PDF from
GET /analyses/:analysisId/report.