{
  "components": {
    "schemas": {
      "HTTPValidationError": {
        "properties": {
          "detail": {
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "title": "Detail",
            "type": "array"
          }
        },
        "title": "HTTPValidationError",
        "type": "object"
      },
      "JobCancelled": {
        "description": "A job cancelled, now or before.",
        "properties": {
          "job_id": {
            "title": "Job Id",
            "type": "string"
          },
          "status": {
            "const": "cancelled",
            "default": "cancelled",
            "title": "Status",
            "type": "string"
          }
        },
        "required": [
          "job_id"
        ],
        "title": "JobCancelled",
        "type": "object"
      },
      "JobError": {
        "description": "The body of the job routes' errors.",
        "properties": {
          "detail": {
            "title": "Detail",
            "type": "string"
          }
        },
        "required": [
          "detail"
        ],
        "title": "JobError",
        "type": "object"
      },
      "ValidationError": {
        "properties": {
          "ctx": {
            "title": "Context",
            "type": "object"
          },
          "input": {
            "title": "Input"
          },
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "title": "Location",
            "type": "array"
          },
          "msg": {
            "title": "Message",
            "type": "string"
          },
          "type": {
            "title": "Error Type",
            "type": "string"
          }
        },
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError",
        "type": "object"
      },
      "WorkflowError": {
        "description": "The body of every error of the workflow routes.",
        "properties": {
          "detail": {
            "description": "What went wrong, naming the stage or the field when a rule is broken",
            "title": "Detail",
            "type": "string"
          }
        },
        "required": [
          "detail"
        ],
        "title": "WorkflowError",
        "type": "object"
      }
    },
    "securitySchemes": {
      "MetricsToken": {
        "description": "The metrics token (METRICS_TOKEN)",
        "scheme": "bearer",
        "type": "http"
      }
    }
  },
  "info": {
    "title": "SPOT Orchestrator",
    "version": "2.1.0"
  },
  "openapi": "3.1.0",
  "paths": {
    "/capabilities": {
      "get": {
        "description": "Get orchestrator capabilities.",
        "operationId": "get_capabilities_capabilities_get",
        "parameters": [
          {
            "in": "header",
            "name": "X-Internal-API-Key",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Internal-Api-Key"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "title": "Response Get Capabilities Capabilities Get",
                  "type": "object"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get Capabilities",
        "tags": [
          "Status"
        ]
      }
    },
    "/health": {
      "get": {
        "description": "Health check endpoint, open to every service that can reach the orchestrator.\n\nReports whether each dependency is connected and required. Failure\ndetails are logged, not returned: workflows and analyzers are behind the\ninternal key (``/readiness``, ``/workflows``, ``/capabilities``), and the\nmetrics behind the metrics token (``/metrics``).",
        "operationId": "health_check_health_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "503": {
            "description": "Service degraded"
          }
        },
        "summary": "Health Check",
        "tags": [
          "Health"
        ]
      },
      "head": {
        "description": "Health check endpoint, open to every service that can reach the orchestrator.\n\nReports whether each dependency is connected and required. Failure\ndetails are logged, not returned: workflows and analyzers are behind the\ninternal key (``/readiness``, ``/workflows``, ``/capabilities``), and the\nmetrics behind the metrics token (``/metrics``).",
        "operationId": "health_check_health_head",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          }
        },
        "summary": "Health Check",
        "tags": [
          "Health"
        ]
      }
    },
    "/jobs": {
      "get": {
        "description": "List analysis jobs with filtering.",
        "operationId": "list_jobs_jobs_get",
        "parameters": [
          {
            "in": "query",
            "name": "status",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Status"
            }
          },
          {
            "in": "query",
            "name": "workflow_id",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Workflow Id"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "default": 0,
              "title": "Offset",
              "type": "integer"
            }
          },
          {
            "in": "header",
            "name": "X-Internal-API-Key",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Internal-Api-Key"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "title": "Response List Jobs Jobs Get",
                  "type": "object"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "List Jobs",
        "tags": [
          "Jobs"
        ]
      }
    },
    "/jobs/{job_id}/cancel": {
      "post": {
        "description": "Cancel a job queued or running: its analysis stops, or never starts.\n\nA cancelled job is recorded ``cancelled`` and published to nobody.\nCancelling it again answers the same.",
        "operationId": "cancel_job_jobs__job_id__cancel_post",
        "parameters": [
          {
            "in": "path",
            "name": "job_id",
            "required": true,
            "schema": {
              "title": "Job Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "X-Internal-API-Key",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Internal-Api-Key"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobCancelled"
                }
              }
            },
            "description": "Successful Response"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobError"
                }
              }
            },
            "description": "No job has this id"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobError"
                }
              }
            },
            "description": "The job is finished: completed or failed"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobError"
                }
              }
            },
            "description": "The job processor is not running, or the cancel could not be recorded: it stays pending, so the job does not run again, and a retry records it"
          }
        },
        "summary": "Cancel Job",
        "tags": [
          "Jobs"
        ]
      }
    },
    "/metrics": {
      "get": {
        "operationId": "metrics_metrics_get",
        "responses": {
          "200": {
            "content": {
              "text/plain": {}
            },
            "description": "Prometheus text format"
          },
          "401": {
            "description": "Without the metrics token"
          },
          "503": {
            "description": "Metrics are off: METRICS_TOKEN is not set"
          }
        },
        "security": [
          {
            "MetricsToken": []
          }
        ],
        "summary": "Metrics",
        "tags": [
          "Metrics"
        ]
      }
    },
    "/plugins/status": {
      "get": {
        "description": "Every plugin's own state: each plugin of spot.yaml that has a URL, enabled or not.\n\nA plugin is listed under its section, and its ``/health`` read once, at\nonce with the others'. With ``plugin_id``, only that plugin is read and\nlisted.",
        "operationId": "get_plugin_status_plugins_status_get",
        "parameters": [
          {
            "description": "Read this plugin only",
            "in": "query",
            "name": "plugin_id",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Read this plugin only",
              "title": "Plugin Id"
            }
          },
          {
            "in": "header",
            "name": "X-Internal-API-Key",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Internal-Api-Key"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "title": "Response Get Plugin Status Plugins Status Get",
                  "type": "object"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get Plugin Status",
        "tags": [
          "Status"
        ]
      }
    },
    "/readiness": {
      "get": {
        "description": "Whether each workflow can run now, from the state of its analyzers.\n\n``broken``: an analyzer has no URL, so analyses fail; ``degraded``: an\nanalyzer is configured but does not pass its health check; ``ready``:\nevery analyzer passes it.",
        "operationId": "get_workflow_readiness_readiness_get",
        "parameters": [
          {
            "in": "header",
            "name": "X-Internal-API-Key",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Internal-Api-Key"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "title": "Response Get Workflow Readiness Readiness Get",
                  "type": "object"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get Workflow Readiness",
        "tags": [
          "Status"
        ]
      }
    },
    "/version": {
      "get": {
        "description": "Get service version and build information.",
        "operationId": "get_version_version_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "title": "Response Get Version Version Get",
                  "type": "object"
                }
              }
            },
            "description": "Successful Response"
          }
        },
        "summary": "Get Version",
        "tags": [
          "Health"
        ]
      }
    },
    "/workflows": {
      "get": {
        "description": "List available workflows.",
        "operationId": "list_workflows_workflows_get",
        "parameters": [
          {
            "in": "header",
            "name": "X-Internal-API-Key",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Internal-Api-Key"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "title": "Response List Workflows Workflows Get",
                  "type": "object"
                }
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "List Workflows",
        "tags": [
          "Workflows"
        ]
      }
    },
    "/workflows/{workflow_id}": {
      "get": {
        "description": "Get detailed workflow configuration; 409 with the reason for one left out at load.",
        "operationId": "get_workflow_workflows__workflow_id__get",
        "parameters": [
          {
            "in": "path",
            "name": "workflow_id",
            "required": true,
            "schema": {
              "title": "Workflow Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "X-Internal-API-Key",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Internal-Api-Key"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "title": "Response Get Workflow Workflows  Workflow Id  Get",
                  "type": "object"
                }
              }
            },
            "description": "Successful Response"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowError"
                }
              }
            },
            "description": "No workflow has this id"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowError"
                }
              }
            },
            "description": "The workflow was left out at load: the detail gives the rule it breaks"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Get Workflow",
        "tags": [
          "Workflows"
        ]
      }
    },
    "/workflows/{workflow_id}/test": {
      "post": {
        "description": "Dry-run a saved workflow on an email's view.\n\nThe gateway parses the submitted message and sends its view as\n``email``. The run uses the same engine as an analysis job but stores\nand publishes nothing: no job, no analysis result, no metrics, no\nmessage. Body fields other than ``email`` (such as\n``wait_for_completion``) are ignored. A workflow left out at load\nanswers 409, with the rule it breaks. Each analyzer is called with its\nown token; without the plugin token store (no database) the dry run\nanswers 503.\n\nThe analyzers are not told the run is a dry run: one with side effects\nof its own (sender history, MISP sightings) records the test email\nlike any other.",
        "operationId": "test_workflow_workflows__workflow_id__test_post",
        "parameters": [
          {
            "in": "path",
            "name": "workflow_id",
            "required": true,
            "schema": {
              "title": "Workflow Id",
              "type": "string"
            }
          },
          {
            "in": "header",
            "name": "X-Internal-API-Key",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Internal-Api-Key"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "additionalProperties": true,
                "title": "Test Data",
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "title": "Response Test Workflow Workflows  Workflow Id  Test Post",
                  "type": "object"
                }
              }
            },
            "description": "Successful Response"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowError"
                }
              }
            },
            "description": "No workflow has this id"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowError"
                }
              }
            },
            "description": "The workflow was left out at load: the detail gives the rule it breaks"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowError"
                }
              }
            },
            "description": "The email is not a valid view; the detail quotes nothing of it"
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowError"
                }
              }
            },
            "description": "The run failed: the detail says why, never the content of the message"
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowError"
                }
              }
            },
            "description": "The plugin tokens are unavailable"
          }
        },
        "summary": "Test Workflow",
        "tags": [
          "Workflows"
        ]
      }
    }
  }
}
