Every scan uses the same status, input, extraction, coverage, usage, and jobs envelope. A completed anonymous request contains its jobs directly; those inline jobs have no status_url and cannot be polled. An authenticated URL or file request normally returns 202 accepted with job references and uses GET /api/v1/scan/{job_id} for completed jobs. A URL has one job per extracted segment; a file has one job per file. Top-level metadata describes the submission, while categories, decision, and safety_status describe each completed job. Completed inline responses also include those fields at the top level for existing clients.
ark_version is the version of the internal Ark result contract that the Control Plane interpreted to produce the response. It is currently "1" and is present on accepted, completed, and polled scan responses. This is distinct from the public /api/v1 route version, extraction.version, and usage.unit_version.
URL responses include segments: each item has a stable id, a kind describing the extracted surface, its graphemes, and, once complete, its category results and evidence. The canonical text sent to Ark starts with a short source label for the segment kind; chunk offsets refer to that labeled text. Static URL extraction reports partial on both access paths because dynamic page content is not scanned. This coverage metadata does not change an otherwise complete final classification.
The job status is only lifecycle state: running, completed, or failed. The decision summarizes how an application should handle the result:
Decision
Meaning
allow
Final classifications for the requested categories are benign.
block
At least one requested category reported a finding.
review
A final classification is missing or inconclusive.
safety_status is attack for a final attack. With a benign final result it is review only when the category result has level: "L3", decision_evidence.stage is union, and a decisive attack chunk from source: "l3" differs from the final class with confidence strictly greater than 0.1; otherwise it is benign. With a benign final result, decision stays allow. Extraction coverage is reported separately; clients can apply their own policy to partial coverage.
For PDFs, coverage.input_tokens counts the extracted text sent to analysis, not the binary file size. Images, fonts, layout data, and compression increase PDF bytes without becoming text tokens. pages_scanned / pages_total shows how many pages supplied a readable text layer; pages without one produce partial coverage because OCR is not currently performed.
The requested analysis finished without a reported failure.
Apply your policy; a scan cannot guarantee the absence of risk.
Completed, complete analysis, detection reported
Analysis finished and found a signal.
Use category results and evidence to choose an action.
Completed, degraded analysis
Some analysis failed or was unavailable.
Review or use a fallback; do not silently treat it as clean.
Failed job or failed completion
Analysis did not complete successfully.
Handle the failure explicitly.
Missing completion or requested category
Insufficient information for a complete result.
Use your fallback policy.
These are handling examples, not fixed classifications. class_name, decision, model identifiers, and evidence labels are open strings. Do not infer an allow decision from HTTP 200, accepted, or confidence alone.
The two evidence fields answer different questions:
decision_evidence locates the analyzed chunk associated with a decision candidate. For injection and other document-level classifiers, use decisive_chunks[].span to locate it in the canonical scan text. These offsets are character offsets.
evidence_spans contains detected entities with a label, score, text, and optional byte or character offsets. This is the primary evidence shape for PII and DLP. It can legitimately be empty for an injection result even when decision_evidence identifies a decisive chunk.
Confidence of the final category classification that contributes to decision. If final_result is absent, use jobs[i].categories.<category>.confidence, which is the category verdict exposed by older or simpler Ark results.
Confidence of that chunk-level candidate. Read class_name, source, chunk_id, and optional span from the same item.
For synchronous compatibility fields, the same category object can also appear at top-level as categories.<category>. Prefer jobs[i].categories.<category> when jobs is present so the confidence stays associated with the correct input segment or file. A decisive chunk can disagree with the final result, so never treat its confidence as the final decision confidence.
detectors lists every model that reported a result for each category. The category’s model is the final model selected for the verdict; an earlier detector such as native:dlp can therefore appear in detectors.dlp even when a later DLP model determines the final classification. Both synchronous and asynchronous account jobs include this field.
decision_evidence can also describe a rejected risk candidate. A chunk may have class_name: "attack" while the final injection category has class_name: "benign", accepted: false, and final_result.class_name: "benign". With category level: "L3", evidence stage: "union", chunk source: "l3", and attack confidence above 0.1, the response is decision: "allow" and safety_status: "review". At 0.1 or below, at another stage or level, or from another chunk source, it is allow and benign. A final attack yields decision: "block" and safety_status: "attack".
Public responses include only decisive chunks. Per-chunk contributor diagnostics are internal because they do not explain the final verdict and can make document responses very large.
Preserve the original input when using offsets to highlight text; changing whitespace or Unicode normalization can move the corresponding positions. For extracted documents, offsets refer to the canonical text produced by extraction, not necessarily the original binary file layout.
final_result, when present, provides the final category classification. timings.total_ms is the end-to-end scan latency reported by the scan backend; the other timing keys break down processing stages. Timing fields are diagnostic data, not an additional safety decision.
Optional fields may be absent. Clients should tolerate additional response fields in future versions and avoid depending on specific model names or timing keys for enforcement.
Required. Version of the internal Ark result contract interpreted by the Control Plane.
job_id
string
Required.
source
string
Required.
status
running | completed | failed
Required.
input
InputMetadata
Required.
extraction
ExtractionMetadata
Required.
coverage
CoverageMetadata
Required.
progress
Map<string, Progress>
Required.
categories
Map<string, CategoryResult>
Required. Results keyed by requested category: injection, dlp, pii, or threat. Check every requested category; missing results do not establish clean input.
jobs
SubmissionJob[]
Optional.
segments
UrlSegment[]
Optional.
detectors
object
Optional. Model identifiers that reported results, keyed by category, including detectors superseded by a later category result.
completion
Completion
Optional.
decision
string
Optional. Scan decision, when present. The client remains responsible for enforcing its policy.
safety_status
SafetyStatus
Optional.
timings
Timings
Optional.
usage
ScanUsage
Required. Usage for the submission; supplied on successful POST responses.
Optional. Confidence of this decisive chunk candidate, not of the final decision. Read the final confidence from the category's final_result.confidence.