{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/riveterhq-com/json-schema/riveterhq-com-run-schema.json",
  "title": "Run",
  "description": "The uniform shape for every run, returned by kickoff endpoints and all /runs endpoints.\nRelated resource ids (enrichment_id, dataset_id, extraction_id, monitor_id) appear when they\napply to the run; kickoff responses may add a few endpoint-specific fields.\n",
  "x-generated": "2026-10-31",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/riveterhq-com-openapi.json#/components/schemas/Run",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "The run id (run_...)"
    },
    "type": {
      "type": "string",
      "enum": [
        "enrichment",
        "dataset_build",
        "extraction",
        "scrape",
        "quick_search",
        "search_agent"
      ],
      "description": "What kind of run this is"
    },
    "status": {
      "type": "string",
      "enum": [
        "pending",
        "enqueued",
        "processing",
        "success",
        "stopped"
      ]
    },
    "progress": {
      "$ref": "#/$defs/RunProgress"
    },
    "credits_used": {
      "type": "number",
      "description": "Credits consumed so far"
    },
    "credit_detail": {
      "$ref": "#/$defs/CreditDetail"
    },
    "app_url": {
      "type": "string",
      "format": "uri",
      "description": "Link to view this run in the Riveter app"
    },
    "result_url": {
      "type": "string",
      "format": "uri",
      "description": "Where to fetch the run's output"
    },
    "started_at": {
      "type": [
        "string",
        "null"
      ],
      "format": "date-time"
    },
    "finished_at": {
      "type": [
        "string",
        "null"
      ],
      "format": "date-time"
    },
    "error": {
      "type": [
        "object",
        "null"
      ],
      "description": "Null unless the run hit an error",
      "properties": {
        "type": {
          "type": "string"
        },
        "message": {
          "type": "string"
        }
      }
    },
    "stopped_reason": {
      "$ref": "#/$defs/StoppedReason"
    },
    "enrichment_id": {
      "type": "string",
      "description": "Present when the run belongs to an enrichment"
    },
    "enrichment_name": {
      "type": "string"
    },
    "dataset_id": {
      "type": "string",
      "description": "Present on dataset-build runs"
    },
    "extraction_id": {
      "type": "string",
      "description": "Present on extraction runs"
    },
    "monitor_id": {
      "type": "string",
      "description": "Present on monitor-scheduled runs"
    },
    "webhook_url": {
      "type": "string",
      "format": "uri",
      "description": "Present when the run has a webhook configured"
    },
    "legacy": {
      "$ref": "#/$defs/LegacyNotice"
    }
  },
  "required": [
    "id",
    "type",
    "status",
    "progress",
    "credit_detail",
    "result_url"
  ],
  "$defs": {
    "CreditDetail": {
      "type": "object",
      "description": "The estimate made at kickoff next to what has been charged so far. `estimate` is null for runs\nstarted before estimates existed. Estimates and credit errors add `credits_remaining` and `sufficient_credits`.\n",
      "properties": {
        "estimate": {
          "oneOf": [
            {
              "$ref": "#/$defs/CreditEstimate"
            },
            {
              "type": "null"
            }
          ]
        },
        "credits_used": {
          "type": "number",
          "description": "Credits charged so far (same value as the top-level credits_used)"
        },
        "credits_remaining": {
          "type": "number",
          "description": "Account balance. Only on estimates and credit errors."
        },
        "sufficient_credits": {
          "type": "boolean",
          "description": "Whether the balance covers `estimate.maximum`. Only on estimates and credit errors."
        }
      },
      "required": [
        "estimate",
        "credits_used"
      ]
    },
    "CreditEstimate": {
      "type": "object",
      "description": "Kickoff-time credit estimate. `maximum` is the contract — the run never charges more.\n`minimum` is 0 when the run can charge less (cells that short-circuit, a dataset build settling below its cap).\n`upfront` is the deposit taken at kickoff when `charged_upfront` is true (a dataset build's expected spend; equal to `maximum` for a fixed-price product; 0 for a fill).\n`expected` is the likely charge when history exists (a dataset fill: rows × the enrichment's average charge per row; a dataset build: equal to `upfront`).\n`typical` is `{ low, high }` — the recent p25–p75 settled range for builds of that size (absent elsewhere).\n",
      "properties": {
        "minimum": {
          "type": "number",
          "description": "Least the run can cost"
        },
        "expected": {
          "type": "number",
          "description": "Likely cost from past runs of the same config; absent without history"
        },
        "typical": {
          "type": "object",
          "description": "Recent p25–p75 settled range for builds of this size; absent without a dataset build estimate",
          "properties": {
            "low": {
              "type": "number"
            },
            "high": {
              "type": "number"
            }
          },
          "required": [
            "low",
            "high"
          ]
        },
        "maximum": {
          "type": "number",
          "description": "Most the run can cost"
        },
        "upfront": {
          "type": "number",
          "description": "Credits taken at kickoff when charged_upfront is true; 0 when the charge accrues as work completes"
        },
        "charged_upfront": {
          "type": "boolean",
          "description": "true when a deposit is taken at kickoff (dataset builds, extractions); false when credits accrue as work completes"
        }
      },
      "required": [
        "minimum",
        "maximum",
        "charged_upfront"
      ]
    },
    "LegacyNotice": {
      "type": "object",
      "description": "Present on a response when the request took a legacy mode — a legacy enrichment's id on `/enrich`,\n`/enrichments/{id}`, `/monitors`, or `GET /runs`; a monitor on a legacy enrichment; an `output` column\nwith legacy-pipeline fields on `/enrich`; the list-build body on `POST /datasets`. The response also\ncarries `Deprecation: true` and a `Link` header (`rel=\"successor-version\"`). The legacy generation is\ndocumented in [the legacy API docs](?spec=legacy).\n",
      "properties": {
        "notice": {
          "type": "string",
          "description": "One or two sentences — what was legacy about the request and what to send instead"
        },
        "successor": {
          "type": "string",
          "description": "`METHOD /v1/path` of the current operation to use"
        },
        "docs": {
          "type": "string",
          "format": "uri",
          "description": "The successor's section of this reference"
        }
      },
      "required": [
        "notice",
        "successor",
        "docs"
      ]
    },
    "RunProgress": {
      "type": "object",
      "description": "Completion estimate. Cell-based runs (enrichment, quick_search) also report cell counts; dataset fills report row counts; builds on a dataset report what landed.",
      "properties": {
        "percent_complete": {
          "type": [
            "number",
            "null"
          ]
        },
        "estimated_seconds_remaining": {
          "type": [
            "number",
            "null"
          ]
        },
        "elapsed_seconds": {
          "type": [
            "number",
            "null"
          ]
        },
        "completed_cells": {
          "type": "integer",
          "description": "Cell-based runs only"
        },
        "total_cells_expected": {
          "type": "integer",
          "description": "Cell-based runs only"
        },
        "not_found_cells": {
          "type": [
            "integer",
            "null"
          ],
          "description": "Cell-based runs only. Null while a run over 5,000 rows is in progress; set when it finishes."
        },
        "total_rows": {
          "type": "integer",
          "description": "Dataset fills only. Rows in the fill's scope"
        },
        "completed_rows": {
          "type": "integer",
          "description": "Dataset fills only. Rows finished (ok, not found, or failed)"
        },
        "running_rows": {
          "type": "integer",
          "description": "Dataset fills only. Rows an agent is working on right now"
        },
        "requested_rows": {
          "type": "integer",
          "description": "Builds on a dataset only. The `count` asked for"
        },
        "generated_rows": {
          "type": "integer",
          "description": "Builds on a dataset only. Rows the generator found; set when the run finishes"
        },
        "added_rows": {
          "type": "integer",
          "description": "Builds on a dataset only. Rows that landed in the dataset; set when the run finishes"
        },
        "skipped_duplicate_rows": {
          "type": "integer",
          "description": "Builds on a dataset only. Generated rows dropped as duplicates on the index column; set when the run finishes"
        }
      }
    },
    "StoppedReason": {
      "type": "string",
      "enum": [
        "user_request",
        "credit_limit",
        "error"
      ],
      "description": "Why the run has status `stopped`. Only present on stopped runs.\n`user_request`: stopped through the API or the app. `credit_limit`: the account ran out of credits.\n`error`: the run failed (internal error, or every enrichment cell failed); `error.message` has the detail.\n"
    }
  }
}