{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/inkseal-net/json-schema/inkseal-net-detection-run-schema.json",
  "title": "DetectionRun",
  "description": "A detection run in full. `fields`, `formatting`, and `warning` appear only on a completed run; `error` only on a failed one.",
  "x-generated": "2026-11-12",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/inkseal-net-openapi.json#/components/schemas/DetectionRun",
  "type": "object",
  "required": [
    "detectionRunId",
    "status",
    "forced",
    "agentVersion",
    "pagesProcessed",
    "totalPages",
    "modelRequested",
    "modelUsed",
    "primaryModelUsed",
    "fallbackModelsTried",
    "tokenUsage",
    "reservedCostUsd",
    "costUsd",
    "costSource",
    "estimatedCostUsd",
    "createdAt",
    "startedAt",
    "completedAt"
  ],
  "properties": {
    "detectionRunId": {
      "type": "integer",
      "minimum": 1
    },
    "status": {
      "$ref": "#/$defs/DetectionStatus"
    },
    "forced": {
      "type": "boolean",
      "description": "Whether this run was explicitly asked for instead of a cached one."
    },
    "agentVersion": {
      "type": [
        "string",
        "null"
      ]
    },
    "pagesProcessed": {
      "type": [
        "integer",
        "null"
      ],
      "description": "How many pages the run has finished. Progress while it is running."
    },
    "totalPages": {
      "type": [
        "integer",
        "null"
      ],
      "description": "How many pages the run was reserved for."
    },
    "modelRequested": {
      "type": "string",
      "description": "The model the deployment asked for."
    },
    "modelUsed": {
      "type": [
        "string",
        "null"
      ],
      "description": "The model recorded for the run overall."
    },
    "primaryModelUsed": {
      "type": [
        "string",
        "null"
      ],
      "description": "The model that answered the primary classify and detect pass."
    },
    "fallbackModelsTried": {
      "type": "array",
      "description": "Models the cascade fell through to. Empty when the primary handled the whole run.",
      "items": {
        "type": "string"
      }
    },
    "tokenUsage": {
      "$ref": "#/$defs/DetectionTokenUsage"
    },
    "reservedCostUsd": {
      "type": "number",
      "description": "What is being held against the workspace's daily cap for this run, in USD. Reported alongside `costUsd` rather than merged into it, because one is a reservation and the other is spend."
    },
    "costUsd": {
      "type": [
        "number",
        "null"
      ],
      "description": "What the run actually spent, in USD. Null until it finishes. A failed run can still have spent money, so this is reported there too."
    },
    "costSource": {
      "$ref": "#/$defs/DetectionCostSource"
    },
    "estimatedCostUsd": {
      "type": [
        "number",
        "null"
      ],
      "description": "The estimate made before the run, in USD."
    },
    "createdAt": {
      "type": "string",
      "format": "date-time"
    },
    "startedAt": {
      "type": [
        "string",
        "null"
      ],
      "format": "date-time"
    },
    "completedAt": {
      "type": [
        "string",
        "null"
      ],
      "format": "date-time"
    },
    "fields": {
      "type": "array",
      "description": "The detected fields. Present only when `status` is `completed`.",
      "items": {
        "$ref": "#/$defs/DetectedField"
      }
    },
    "formatting": {
      "type": [
        "object",
        "null"
      ],
      "description": "The agent's own assessment of the document, as the visual editor sees it. Its shape differs by pipeline, so it is passed through rather than narrowed: the agent path records strategy and budget outcome, the single-shot path records document type and placement quality. Present only when `status` is `completed`.",
      "additionalProperties": true
    },
    "warning": {
      "type": [
        "string",
        "null"
      ],
      "description": "Set when more fields were detected than an envelope may hold and the lowest-confidence ones were dropped. Present only when `status` is `completed`."
    },
    "error": {
      "type": "string",
      "description": "Why detection failed. Present only when `status` is `failed`. The envelope is untouched: the caller can force another run or place fields by hand."
    }
  },
  "$defs": {
    "DetectedField": {
      "type": "object",
      "description": "One field the agent placed, with its own confidence and the reason it was placed there.",
      "required": [
        "type",
        "pageIndex",
        "bounds",
        "label",
        "detectionConfidence",
        "detectionReason",
        "detectionSource",
        "party",
        "fillHint",
        "fillHintConfidence",
        "suggestedName"
      ],
      "properties": {
        "type": {
          "$ref": "#/$defs/DetectedFieldType"
        },
        "pageIndex": {
          "type": "integer",
          "description": "0-based page index, matching the page image endpoints.",
          "minimum": 0
        },
        "bounds": {
          "$ref": "#/$defs/DetectedFieldBounds"
        },
        "label": {
          "type": "string",
          "description": "The label derived from the surrounding text, or a default for the field type."
        },
        "detectionConfidence": {
          "type": [
            "number",
            "null"
          ],
          "description": "Confidence in this placement, 0 to 1. Null when the run recorded none.",
          "minimum": 0,
          "maximum": 1
        },
        "detectionReason": {
          "type": [
            "string",
            "null"
          ],
          "description": "A one-line, human-readable reason for the placement."
        },
        "detectionSource": {
          "$ref": "#/$defs/DetectedFieldSource"
        },
        "party": {
          "oneOf": [
            {
              "type": "object",
              "required": [
                "key",
                "label",
                "confidence"
              ],
              "properties": {
                "key": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "confidence": {
                  "type": "number",
                  "minimum": 0,
                  "maximum": 1
                }
              }
            },
            {
              "type": "null"
            }
          ]
        },
        "fillHint": {
          "type": "string",
          "enum": [
            "signer",
            "sender"
          ]
        },
        "fillHintConfidence": {
          "type": "number",
          "minimum": 0,
          "maximum": 1
        },
        "suggestedName": {
          "type": "string",
          "pattern": "^[a-z][a-z0-9_]{0,63}$"
        }
      }
    },
    "DetectedFieldBounds": {
      "type": "object",
      "description": "Where the field sits on its page, as ratios of the page box in the range 0 to 1 with the origin at the top-left corner. `xRatio` and `yRatio` locate the field's top-left corner; `widthRatio` and `heightRatio` size it. No pixels and no points, so the numbers hold at any render scale.",
      "required": [
        "xRatio",
        "yRatio",
        "widthRatio",
        "heightRatio"
      ],
      "properties": {
        "xRatio": {
          "type": "number",
          "minimum": 0,
          "maximum": 1
        },
        "yRatio": {
          "type": "number",
          "minimum": 0,
          "maximum": 1
        },
        "widthRatio": {
          "type": "number",
          "minimum": 0,
          "maximum": 1
        },
        "heightRatio": {
          "type": "number",
          "minimum": 0,
          "maximum": 1
        }
      }
    },
    "DetectedFieldSource": {
      "type": "string",
      "description": "Who placed the field. Detection output is `agent`; the other values appear once a person has edited a placement.",
      "enum": [
        "agent",
        "manual",
        "agent-then-manual"
      ]
    },
    "DetectedFieldType": {
      "type": "string",
      "description": "The kind of field detected. The same vocabulary envelope fields use.",
      "enum": [
        "signature",
        "initials",
        "text",
        "date",
        "checkbox"
      ]
    },
    "DetectionCostSource": {
      "type": [
        "string",
        "null"
      ],
      "description": "Where `costUsd` came from: `actual` when the provider reported it, `estimated` when a conservative estimate was required, `mixed` when the run used both. Null until the run finishes.",
      "enum": [
        "actual",
        "estimated",
        "mixed",
        null
      ]
    },
    "DetectionStatus": {
      "type": "string",
      "description": "A detection run's lifecycle. `processing` while it is queued or running, then `completed` or `failed`.",
      "enum": [
        "processing",
        "completed",
        "failed"
      ]
    },
    "DetectionTokenUsage": {
      "type": "object",
      "description": "Model token usage for the run. Each value is null until the provider reports it.",
      "required": [
        "promptTokens",
        "completionTokens",
        "totalTokens"
      ],
      "properties": {
        "promptTokens": {
          "type": [
            "integer",
            "null"
          ]
        },
        "completionTokens": {
          "type": [
            "integer",
            "null"
          ]
        },
        "totalTokens": {
          "type": [
            "integer",
            "null"
          ]
        }
      }
    }
  }
}