{
  "components": {
    "schemas": {
      "ApiKeyCreateResponse.c5eb086": {
        "description": "Response model for POST /v2/api-keys and POST /v2/api-keys/{id}/rotate.",
        "properties": {
          "contexts": {
            "description": "Allowed contexts",
            "items": {
              "type": "string"
            },
            "title": "Contexts",
            "type": "array"
          },
          "expires_at": {
            "description": "ISO 8601 expiration timestamp",
            "title": "Expires At",
            "type": "string"
          },
          "key_id": {
            "description": "Key identifier",
            "title": "Key Id",
            "type": "string"
          },
          "role": {
            "description": "Assigned role",
            "title": "Role",
            "type": "string"
          },
          "token": {
            "description": "JWT token (shown once)",
            "title": "Token",
            "type": "string"
          }
        },
        "required": [
          "key_id",
          "token",
          "role",
          "expires_at"
        ],
        "title": "ApiKeyCreateResponse",
        "type": "object"
      },
      "ApiKeyListResponse.c5eb086": {
        "description": "Response model for GET /v2/api-keys.",
        "properties": {
          "keys": {
            "description": "Active API keys",
            "items": {
              "$ref": "#/components/schemas/ApiKeyListResponse.c5eb086.ApiKeyListItem"
            },
            "title": "Keys",
            "type": "array"
          }
        },
        "required": [
          "keys"
        ],
        "title": "ApiKeyListResponse",
        "type": "object"
      },
      "ApiKeyListResponse.c5eb086.ApiKeyListItem": {
        "description": "API key metadata (no token).",
        "properties": {
          "contexts": {
            "description": "Allowed contexts",
            "items": {
              "type": "string"
            },
            "title": "Contexts",
            "type": "array"
          },
          "created_at": {
            "description": "ISO 8601 creation timestamp",
            "title": "Created At",
            "type": "string"
          },
          "created_by": {
            "description": "Creator identity",
            "title": "Created By",
            "type": "string"
          },
          "expires_at": {
            "description": "ISO 8601 expiration timestamp",
            "title": "Expires At",
            "type": "string"
          },
          "key_id": {
            "description": "Key identifier",
            "title": "Key Id",
            "type": "string"
          },
          "role": {
            "description": "Assigned role",
            "title": "Role",
            "type": "string"
          }
        },
        "required": [
          "key_id",
          "role",
          "created_at",
          "expires_at",
          "created_by"
        ],
        "title": "ApiKeyListItem",
        "type": "object"
      },
      "ContextsResponse.c5eb086": {
        "description": "Response model for GET /v1/contexts.",
        "properties": {
          "contexts": {
            "description": "Active contexts",
            "items": {
              "$ref": "#/components/schemas/ContextsResponse.c5eb086.ContextInfo"
            },
            "title": "Contexts",
            "type": "array"
          }
        },
        "required": [
          "contexts"
        ],
        "title": "ContextsResponse",
        "type": "object"
      },
      "ContextsResponse.c5eb086.ContextInfo": {
        "description": "Status of a single routing context.",
        "properties": {
          "name": {
            "description": "Context name",
            "title": "Name",
            "type": "string"
          },
          "queue_depth": {
            "description": "Number of jobs currently queued",
            "title": "Queue Depth",
            "type": "integer"
          },
          "workers": {
            "description": "Number of active workers serving this context",
            "title": "Workers",
            "type": "integer"
          }
        },
        "required": [
          "name",
          "workers",
          "queue_depth"
        ],
        "title": "ContextInfo",
        "type": "object"
      },
      "FailedJobsResponse.c5eb086": {
        "description": "Response model for GET /v2/jobs/failed.",
        "properties": {
          "jobs": {
            "description": "List of failed jobs",
            "items": {
              "$ref": "#/components/schemas/FailedJobsResponse.c5eb086.FailedJobSummary"
            },
            "title": "Jobs",
            "type": "array"
          },
          "total": {
            "description": "Total number of failed jobs",
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "jobs",
          "total"
        ],
        "title": "FailedJobsResponse",
        "type": "object"
      },
      "FailedJobsResponse.c5eb086.FailedJobSummary": {
        "description": "Summary of a single failed job.",
        "properties": {
          "error": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Sanitized error message",
            "title": "Error"
          },
          "error_code": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Machine-parseable error code",
            "title": "Error Code"
          },
          "error_retryable": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Whether the caller can retry",
            "title": "Error Retryable"
          },
          "failed_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "ISO 8601 failure timestamp",
            "title": "Failed At"
          },
          "func": {
            "default": "",
            "description": "Worker function name",
            "title": "Func",
            "type": "string"
          },
          "host": {
            "default": "",
            "description": "Target device host",
            "title": "Host",
            "type": "string"
          },
          "job_id": {
            "description": "Unique job identifier",
            "title": "Job Id",
            "type": "string"
          },
          "platform": {
            "default": "",
            "description": "Netmiko platform",
            "title": "Platform",
            "type": "string"
          },
          "port": {
            "default": 22,
            "description": "SSH port",
            "title": "Port",
            "type": "integer"
          }
        },
        "required": [
          "job_id"
        ],
        "title": "FailedJobSummary",
        "type": "object"
      },
      "HealthCheckResponse.c5eb086": {
        "description": "Response model for GET /healthcheck.",
        "properties": {
          "components": {
            "$ref": "#/components/schemas/HealthCheckResponse.c5eb086.HealthComponents",
            "description": "Component health details"
          },
          "status": {
            "description": "Overall status: healthy, degraded, or no_workers",
            "title": "Status",
            "type": "string"
          },
          "uptime_seconds": {
            "description": "Seconds since API start",
            "title": "Uptime Seconds",
            "type": "integer"
          },
          "version": {
            "description": "NAAS version",
            "title": "Version",
            "type": "string"
          }
        },
        "required": [
          "status",
          "version",
          "uptime_seconds",
          "components"
        ],
        "title": "HealthCheckResponse",
        "type": "object"
      },
      "HealthCheckResponse.c5eb086.HealthComponentStatus": {
        "description": "Status of a single health component.",
        "properties": {
          "status": {
            "description": "Component status (healthy, unhealthy, no_workers)",
            "title": "Status",
            "type": "string"
          }
        },
        "required": [
          "status"
        ],
        "title": "HealthComponentStatus",
        "type": "object"
      },
      "HealthCheckResponse.c5eb086.HealthComponents": {
        "description": "Health check component statuses.",
        "properties": {
          "failed_jobs": {
            "default": 0,
            "description": "Number of failed jobs",
            "title": "Failed Jobs",
            "type": "integer"
          },
          "queue": {
            "$ref": "#/components/schemas/HealthCheckResponse.c5eb086.QueueHealth",
            "description": "Job queue status"
          },
          "redis": {
            "$ref": "#/components/schemas/HealthCheckResponse.c5eb086.HealthComponentStatus",
            "description": "Redis connectivity"
          },
          "workers": {
            "$ref": "#/components/schemas/HealthCheckResponse.c5eb086.WorkersHealth",
            "description": "Worker pool status"
          }
        },
        "required": [
          "redis",
          "queue",
          "workers"
        ],
        "title": "HealthComponents",
        "type": "object"
      },
      "HealthCheckResponse.c5eb086.QueueHealth": {
        "description": "Queue health with depth.",
        "properties": {
          "depth": {
            "default": 0,
            "description": "Number of jobs in queue",
            "title": "Depth",
            "type": "integer"
          },
          "status": {
            "description": "Component status (healthy, unhealthy, no_workers)",
            "title": "Status",
            "type": "string"
          }
        },
        "required": [
          "status"
        ],
        "title": "QueueHealth",
        "type": "object"
      },
      "HealthCheckResponse.c5eb086.WorkersHealth": {
        "description": "Worker health with count and active jobs.",
        "properties": {
          "active_jobs": {
            "default": 0,
            "description": "Jobs currently processing",
            "title": "Active Jobs",
            "type": "integer"
          },
          "count": {
            "default": 0,
            "description": "Number of worker pods/hosts",
            "title": "Count",
            "type": "integer"
          },
          "status": {
            "description": "Component status (healthy, unhealthy, no_workers)",
            "title": "Status",
            "type": "string"
          }
        },
        "required": [
          "status"
        ],
        "title": "WorkersHealth",
        "type": "object"
      },
      "JobResponse.c5eb086": {
        "description": "Response model for job submission.",
        "properties": {
          "deduplicated": {
            "default": false,
            "description": "True if this response reuses an in-flight duplicate job",
            "title": "Deduplicated",
            "type": "boolean"
          },
          "enqueued_at": {
            "description": "ISO 8601 timestamp when job was enqueued",
            "title": "Enqueued At",
            "type": "string"
          },
          "idempotent": {
            "default": false,
            "description": "True if this response reuses an existing job",
            "title": "Idempotent",
            "type": "boolean"
          },
          "job_id": {
            "description": "Unique job identifier",
            "title": "Job Id",
            "type": "string"
          },
          "message": {
            "description": "Status message",
            "title": "Message",
            "type": "string"
          },
          "queue_position": {
            "description": "Approximate position in queue (1 = next to run)",
            "title": "Queue Position",
            "type": "integer"
          },
          "timeout": {
            "description": "Job timeout in seconds",
            "title": "Timeout",
            "type": "integer"
          }
        },
        "required": [
          "job_id",
          "message",
          "queue_position",
          "enqueued_at",
          "timeout"
        ],
        "title": "JobResponse",
        "type": "object"
      },
      "JobResultResponse.c5eb086": {
        "description": "Response model for job results.",
        "properties": {
          "detected_platform": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "title": "Detected Platform"
          },
          "error": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "title": "Error"
          },
          "error_code": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "title": "Error Code"
          },
          "error_retryable": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "title": "Error Retryable"
          },
          "job_id": {
            "title": "Job Id",
            "type": "string"
          },
          "results": {
            "anyOf": [
              {},
              {
                "type": "null"
              }
            ],
            "default": null,
            "title": "Results"
          },
          "status": {
            "title": "Status",
            "type": "string"
          },
          "tags": {
            "anyOf": [
              {
                "additionalProperties": {
                  "type": "string"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "title": "Tags"
          }
        },
        "required": [
          "job_id",
          "status"
        ],
        "title": "JobResultResponse",
        "type": "object"
      },
      "ListJobsQuery.c5eb086": {
        "description": "Query parameters for the list jobs endpoint.\n\nNOTE: No strict=True here \u2014 query params arrive as strings from werkzeug.\nPydantic's default lax mode coerces '2' -> 2 for int fields, which is required\nfor query parameter models. See SendCommandRequest for the full rationale.",
        "properties": {
          "page": {
            "default": 1,
            "minimum": 1,
            "title": "Page",
            "type": "integer"
          },
          "per_page": {
            "default": 20,
            "maximum": 100,
            "minimum": 1,
            "title": "Per Page",
            "type": "integer"
          },
          "status": {
            "anyOf": [
              {
                "enum": [
                  "finished",
                  "failed",
                  "started",
                  "queued"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "title": "Status"
          },
          "tag": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Filter by tag in 'key:value' format",
            "title": "Tag"
          }
        },
        "title": "ListJobsQuery",
        "type": "object"
      },
      "ListJobsResponse.c5eb086": {
        "description": "Response model for GET /v2/jobs.",
        "properties": {
          "jobs": {
            "description": "List of jobs",
            "items": {
              "$ref": "#/components/schemas/ListJobsResponse.c5eb086.JobSummary"
            },
            "title": "Jobs",
            "type": "array"
          },
          "pagination": {
            "$ref": "#/components/schemas/ListJobsResponse.c5eb086.PaginationInfo",
            "description": "Pagination metadata"
          }
        },
        "required": [
          "jobs",
          "pagination"
        ],
        "title": "ListJobsResponse",
        "type": "object"
      },
      "ListJobsResponse.c5eb086.JobSummary": {
        "description": "Summary of a single job in a list response.",
        "properties": {
          "created_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "ISO 8601 creation timestamp",
            "title": "Created At"
          },
          "ended_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "ISO 8601 completion timestamp",
            "title": "Ended At"
          },
          "job_id": {
            "description": "Unique job identifier",
            "title": "Job Id",
            "type": "string"
          },
          "status": {
            "description": "Job status",
            "title": "Status",
            "type": "string"
          },
          "tags": {
            "anyOf": [
              {
                "additionalProperties": {
                  "type": "string"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Job metadata tags",
            "title": "Tags"
          }
        },
        "required": [
          "job_id",
          "status"
        ],
        "title": "JobSummary",
        "type": "object"
      },
      "ListJobsResponse.c5eb086.PaginationInfo": {
        "description": "Pagination metadata.",
        "properties": {
          "page": {
            "description": "Current page number",
            "title": "Page",
            "type": "integer"
          },
          "pages": {
            "description": "Total number of pages",
            "title": "Pages",
            "type": "integer"
          },
          "per_page": {
            "description": "Results per page",
            "title": "Per Page",
            "type": "integer"
          },
          "total": {
            "description": "Total number of results",
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "page",
          "per_page",
          "total",
          "pages"
        ],
        "title": "PaginationInfo",
        "type": "object"
      },
      "SendCommandRequest.c5eb086": {
        "description": "Request model for send_command endpoint.\n\nUses strict=True because spectree passes Flask's parsed JSON body (native Python\ntypes) to model_validate(). Strict mode rejects type mismatches (e.g. port sent\nas a JSON string instead of a number) rather than silently coercing them.\n\nNOTE: Do NOT use strict=True on query parameter models (e.g. ListJobsQuery).\nQuery params always arrive as strings from werkzeug; strict mode would reject\nvalid integer params like ?page=2 because '2' is a str, not an int.",
        "properties": {
          "commands": {
            "description": "Commands to execute",
            "items": {
              "type": "string"
            },
            "minItems": 1,
            "title": "Commands",
            "type": "array"
          },
          "conn_timeout": {
            "default": 10.0,
            "description": "TCP connection timeout in seconds",
            "minimum": 1.0,
            "title": "Conn Timeout",
            "type": "number"
          },
          "context": {
            "default": "default",
            "description": "Routing context for multi-segment environments (e.g. 'corp', 'oob-dc1', 'hk-prod')",
            "title": "Context",
            "type": "string"
          },
          "device_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Deprecated: use platform instead (v1 compat)",
            "title": "Device Type"
          },
          "enable": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Enable password (optional, defaults to password)",
            "title": "Enable"
          },
          "expect_string": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Regex pattern to match in device output (overrides prompt detection)",
            "title": "Expect String"
          },
          "host": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Device IP address or hostname",
            "title": "Host"
          },
          "ip": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Deprecated: use host instead (v1 compat)",
            "title": "Ip"
          },
          "password": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Device password (required for API key auth)",
            "title": "Password"
          },
          "platform": {
            "default": "cisco_ios",
            "description": "Netmiko device type (use 'autodetect' for SSHDetect)",
            "title": "Platform",
            "type": "string"
          },
          "port": {
            "default": 22,
            "description": "SSH port",
            "maximum": 65535,
            "minimum": 1,
            "title": "Port",
            "type": "integer"
          },
          "read_timeout": {
            "default": 30.0,
            "description": "Read timeout in seconds for device responses",
            "minimum": 1.0,
            "title": "Read Timeout",
            "type": "number"
          },
          "tags": {
            "anyOf": [
              {
                "additionalProperties": {
                  "type": "string"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Optional key-value metadata tags (max 10, keys/values max 64 chars, alphanumeric + hyphens/underscores/colons)",
            "title": "Tags"
          },
          "username": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Device username (required for API key auth)",
            "title": "Username"
          },
          "webhook_secret": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Optional shared secret for HMAC-SHA256 webhook payload signing",
            "title": "Webhook Secret"
          },
          "webhook_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Optional HTTPS URL to POST a job completion notification to (never includes results)",
            "title": "Webhook Url"
          }
        },
        "required": [
          "commands"
        ],
        "title": "SendCommandRequest",
        "type": "object"
      },
      "SendCommandStructuredRequest.c5eb086": {
        "description": "Request model for structured send_command with TextFSM or TTP parsing.\n\nReturns parsed output as list[dict] per command. Falls back to raw string\nif no template is found.",
        "properties": {
          "commands": {
            "description": "Commands to execute",
            "items": {
              "type": "string"
            },
            "minItems": 1,
            "title": "Commands",
            "type": "array"
          },
          "conn_timeout": {
            "default": 10.0,
            "description": "TCP connection timeout in seconds",
            "minimum": 1.0,
            "title": "Conn Timeout",
            "type": "number"
          },
          "context": {
            "default": "default",
            "description": "Routing context for multi-segment environments (e.g. 'corp', 'oob-dc1', 'hk-prod')",
            "title": "Context",
            "type": "string"
          },
          "device_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Deprecated: use platform instead (v1 compat)",
            "title": "Device Type"
          },
          "enable": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Enable password (optional, defaults to password)",
            "title": "Enable"
          },
          "host": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Device IP address or hostname",
            "title": "Host"
          },
          "ip": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Deprecated: use host instead (v1 compat)",
            "title": "Ip"
          },
          "password": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Device password (required for API key auth)",
            "title": "Password"
          },
          "platform": {
            "default": "cisco_ios",
            "description": "Netmiko device type (use 'autodetect' for SSHDetect)",
            "title": "Platform",
            "type": "string"
          },
          "port": {
            "default": 22,
            "description": "SSH port",
            "maximum": 65535,
            "minimum": 1,
            "title": "Port",
            "type": "integer"
          },
          "read_timeout": {
            "default": 30.0,
            "description": "Read timeout in seconds for device responses",
            "minimum": 1.0,
            "title": "Read Timeout",
            "type": "number"
          },
          "tags": {
            "anyOf": [
              {
                "additionalProperties": {
                  "type": "string"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Optional key-value metadata tags (max 10, keys/values max 64 chars, alphanumeric + hyphens/underscores/colons)",
            "title": "Tags"
          },
          "textfsm_template": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Custom TextFSM template (uses ntc-templates if not provided)",
            "title": "Textfsm Template"
          },
          "ttp_template": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "TTP template string or ttp://<path> reference (mutually exclusive with textfsm_template)",
            "title": "Ttp Template"
          },
          "username": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Device username (required for API key auth)",
            "title": "Username"
          },
          "webhook_secret": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Optional shared secret for HMAC-SHA256 webhook payload signing",
            "title": "Webhook Secret"
          },
          "webhook_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Optional HTTPS URL to POST a job completion notification to (never includes results)",
            "title": "Webhook Url"
          }
        },
        "required": [
          "commands"
        ],
        "title": "SendCommandStructuredRequest",
        "type": "object"
      },
      "SendConfigRequest.c5eb086": {
        "description": "Request model for send_config endpoint.\n\nUses strict=True for the same reason as SendCommandRequest \u2014 see that class\nfor the strict vs. non-strict rationale.",
        "properties": {
          "commands": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "minItems": 1,
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Configuration commands (alias)",
            "title": "Commands"
          },
          "commit": {
            "default": false,
            "description": "Commit configuration (Juniper)",
            "title": "Commit",
            "type": "boolean"
          },
          "config": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "minItems": 1,
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Configuration commands",
            "title": "Config"
          },
          "conn_timeout": {
            "default": 10.0,
            "description": "TCP connection timeout in seconds",
            "minimum": 1.0,
            "title": "Conn Timeout",
            "type": "number"
          },
          "context": {
            "default": "default",
            "description": "Routing context for multi-segment environments",
            "title": "Context",
            "type": "string"
          },
          "device_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Deprecated: use platform instead (v1 compat)",
            "title": "Device Type"
          },
          "enable": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Enable password (optional, defaults to password)",
            "title": "Enable"
          },
          "host": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Device IP address or hostname",
            "title": "Host"
          },
          "ip": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Deprecated: use host instead (v1 compat)",
            "title": "Ip"
          },
          "password": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Device password (required for API key auth)",
            "title": "Password"
          },
          "platform": {
            "default": "cisco_ios",
            "description": "Netmiko device type (use 'autodetect' for SSHDetect)",
            "title": "Platform",
            "type": "string"
          },
          "port": {
            "default": 22,
            "description": "SSH port",
            "maximum": 65535,
            "minimum": 1,
            "title": "Port",
            "type": "integer"
          },
          "read_timeout": {
            "default": 30.0,
            "description": "Read timeout in seconds for device responses",
            "minimum": 1.0,
            "title": "Read Timeout",
            "type": "number"
          },
          "save_config": {
            "default": false,
            "description": "Save configuration after applying",
            "title": "Save Config",
            "type": "boolean"
          },
          "tags": {
            "anyOf": [
              {
                "additionalProperties": {
                  "type": "string"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Optional key-value metadata tags (max 10, keys/values max 64 chars)",
            "title": "Tags"
          },
          "username": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Device username (required for API key auth)",
            "title": "Username"
          },
          "webhook_secret": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Optional shared secret for HMAC-SHA256 webhook payload signing",
            "title": "Webhook Secret"
          },
          "webhook_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "description": "Optional HTTPS URL to POST a job completion notification to (never includes results)",
            "title": "Webhook Url"
          }
        },
        "title": "SendConfigRequest",
        "type": "object"
      },
      "ValidationError.6a07bef": {
        "description": "Model of a validation error response.",
        "items": {
          "$ref": "#/components/schemas/ValidationError.6a07bef.ValidationErrorElement"
        },
        "title": "ValidationError",
        "type": "array"
      },
      "ValidationError.6a07bef.ValidationErrorElement": {
        "description": "Model of a validation error response element.",
        "properties": {
          "ctx": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "default": null,
            "title": "Error context"
          },
          "loc": {
            "items": {
              "type": "string"
            },
            "title": "Missing field name",
            "type": "array"
          },
          "msg": {
            "title": "Error message",
            "type": "string"
          },
          "type": {
            "title": "Error type",
            "type": "string"
          }
        },
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationErrorElement",
        "type": "object"
      }
    },
    "securitySchemes": {
      "basicAuth": {
        "scheme": "basic",
        "type": "http"
      }
    }
  },
  "info": {
    "title": "NAAS - Netmiko As A Service",
    "version": "v1"
  },
  "openapi": "3.1.0",
  "paths": {
    "/": {
      "get": {
        "description": "Returns:     dict: Health status with the following structure:         {             \"status\": str,  # \"healthy\", \"degraded\", or \"no_workers\"             \"version\": str,  # NAAS version             \"uptime_seconds\": int,  # Seconds since API start             \"components\": {                 \"redis\": {\"status\": str},  # \"healthy\" or \"unhealthy\"                 \"queue\": {\"status\": str, \"depth\": int},  # Queue status and job count                 \"workers\": {                     \"status\": str,  # \"healthy\" or \"no_workers\"                     \"count\": int,  # Number of worker pods/hosts                     \"active_jobs\": int  # Jobs currently processing                 }             }         }",
        "operationId": "get__",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthCheckResponse.c5eb086"
                }
              }
            },
            "description": "OK"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Return detailed health status including component checks.",
        "tags": []
      }
    },
    "/healthcheck": {
      "get": {
        "description": "Returns:     dict: Health status with the following structure:         {             \"status\": str,  # \"healthy\", \"degraded\", or \"no_workers\"             \"version\": str,  # NAAS version             \"uptime_seconds\": int,  # Seconds since API start             \"components\": {                 \"redis\": {\"status\": str},  # \"healthy\" or \"unhealthy\"                 \"queue\": {\"status\": str, \"depth\": int},  # Queue status and job count                 \"workers\": {                     \"status\": str,  # \"healthy\" or \"no_workers\"                     \"count\": int,  # Number of worker pods/hosts                     \"active_jobs\": int  # Jobs currently processing                 }             }         }",
        "operationId": "get__healthcheck",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthCheckResponse.c5eb086"
                }
              }
            },
            "description": "OK"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Return detailed health status including component checks.",
        "tags": []
      }
    },
    "/metrics": {
      "get": {
        "description": "",
        "operationId": "get__metrics",
        "parameters": [],
        "responses": {},
        "summary": "prometheus_metrics <GET>",
        "tags": []
      }
    },
    "/send_command": {
      "get": {
        "description": "",
        "operationId": "get__send_command",
        "parameters": [],
        "responses": {},
        "summary": "get <GET>",
        "tags": []
      },
      "post": {
        "description": "Requires you submit the following in the payload:     ip: str     commands: Sequence[str] Optional:     port: int - Default 22     platform: str - Default cisco_ios     enable: Optional[str] - Default the password provided for basic auth\n\nSecured by Basic Auth, which is then passed to the network device. :return: A dict of the job ID, a 202 response code, and the job_id as the X-Request-ID header",
        "operationId": "post__send_command",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendCommandRequest.c5eb086"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobResponse.c5eb086"
                }
              }
            },
            "description": "Accepted"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Will enqueue an attempt to run commands on a device.",
        "tags": []
      }
    },
    "/send_command/{job_id}": {
      "get": {
        "description": "",
        "operationId": "get__send_command_{job_id}",
        "parameters": [
          {
            "description": "",
            "in": "path",
            "name": "job_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobResultResponse.c5eb086"
                }
              }
            },
            "description": "OK"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Given the requested job_id, return status and/or any results if finished. :param job_id: :return: A dict of job status and/or results if finished.",
        "tags": []
      }
    },
    "/send_config": {
      "get": {
        "description": "",
        "operationId": "get__send_config",
        "parameters": [],
        "responses": {},
        "summary": "get <GET>",
        "tags": []
      },
      "post": {
        "description": "Requires you submit the following in the payload:     ip: str     commands: Sequence[str] Optional:     port: int - Default 22     platform: str - Default cisco_ios     enable: Optional[str] - Default the password provided for basic auth     save_config: bool     commit: bool\n\nSecured by Basic Auth, which is then passed to the network device. :return: A dict of the job ID, a 202 response code, and the job_id as the X-Request-ID header",
        "operationId": "post__send_config",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendConfigRequest.c5eb086"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobResponse.c5eb086"
                }
              }
            },
            "description": "Accepted"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Will enqueue an attempt to use netmiko's send_config_set() method to run commands/put configuration on a device.",
        "tags": []
      }
    },
    "/send_config/{job_id}": {
      "get": {
        "description": "",
        "operationId": "get__send_config_{job_id}",
        "parameters": [
          {
            "description": "",
            "in": "path",
            "name": "job_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobResultResponse.c5eb086"
                }
              }
            },
            "description": "OK"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Given the requested job_id, return status and/or any results if finished. :param job_id: :return: A dict of job status and/or results if finished.",
        "tags": []
      }
    },
    "/v1/api-keys": {
      "get": {
        "description": "",
        "operationId": "get__v1_api-keys",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyListResponse.c5eb086"
                }
              }
            },
            "description": "OK"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "List all active API keys (metadata only, not tokens).",
        "tags": []
      },
      "post": {
        "description": "",
        "operationId": "post__v1_api-keys",
        "parameters": [],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyCreateResponse.c5eb086"
                }
              }
            },
            "description": "Created"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Create a new API key. Returns the JWT token once.",
        "tags": []
      }
    },
    "/v1/api-keys/{key_id}": {
      "delete": {
        "description": "",
        "operationId": "delete__v1_api-keys_{key_id}",
        "parameters": [
          {
            "description": "",
            "in": "path",
            "name": "key_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Revoke an API key.",
        "tags": []
      }
    },
    "/v1/api-keys/{key_id}/rotate": {
      "post": {
        "description": "",
        "operationId": "post__v1_api-keys_{key_id}_rotate",
        "parameters": [
          {
            "description": "",
            "in": "path",
            "name": "key_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyCreateResponse.c5eb086"
                }
              }
            },
            "description": "Created"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Rotate an API key. Returns a new token, revokes the old key.",
        "tags": []
      }
    },
    "/v1/contexts": {
      "get": {
        "description": ":return: ContextsResponse with per-context status",
        "operationId": "get__v1_contexts",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContextsResponse.c5eb086"
                }
              }
            },
            "description": "OK"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "List all configured contexts with active worker counts and queue depths.",
        "tags": []
      }
    },
    "/v1/healthcheck": {
      "get": {
        "description": "Returns:     dict: Health status with the following structure:         {             \"status\": str,  # \"healthy\", \"degraded\", or \"no_workers\"             \"version\": str,  # NAAS version             \"uptime_seconds\": int,  # Seconds since API start             \"components\": {                 \"redis\": {\"status\": str},  # \"healthy\" or \"unhealthy\"                 \"queue\": {\"status\": str, \"depth\": int},  # Queue status and job count                 \"workers\": {                     \"status\": str,  # \"healthy\" or \"no_workers\"                     \"count\": int,  # Number of worker pods/hosts                     \"active_jobs\": int  # Jobs currently processing                 }             }         }",
        "operationId": "get__v1_healthcheck",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthCheckResponse.c5eb086"
                }
              }
            },
            "description": "OK"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Return detailed health status including component checks.",
        "tags": []
      }
    },
    "/v1/jobs": {
      "get": {
        "description": "",
        "operationId": "get__v1_jobs",
        "parameters": [
          {
            "description": "",
            "in": "query",
            "name": "page",
            "required": false,
            "schema": {
              "default": 1,
              "minimum": 1,
              "title": "Page",
              "type": "integer"
            }
          },
          {
            "description": "",
            "in": "query",
            "name": "per_page",
            "required": false,
            "schema": {
              "default": 20,
              "maximum": 100,
              "minimum": 1,
              "title": "Per Page",
              "type": "integer"
            }
          },
          {
            "description": "",
            "in": "query",
            "name": "status",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "enum": [
                    "finished",
                    "failed",
                    "started",
                    "queued"
                  ],
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "default": null,
              "title": "Status"
            }
          },
          {
            "description": "Filter by tag in 'key:value' format",
            "in": "query",
            "name": "tag",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "default": null,
              "description": "Filter by tag in 'key:value' format",
              "title": "Tag"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListJobsResponse.c5eb086"
                }
              }
            },
            "description": "OK"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "List jobs with pagination and filtering. Query parameters: - page: Page number (default: 1) - per_page: Results per page (default: 20, max: 100) - status: Filter by status (finished, failed, started, queued) :return: Dict with jobs list and pagination info",
        "tags": []
      }
    },
    "/v1/jobs/failed": {
      "get": {
        "description": "Returns:     200: {\"jobs\": [...], \"total\": int}     401: Unauthorized",
        "operationId": "get__v1_jobs_failed",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FailedJobsResponse.c5eb086"
                }
              }
            },
            "description": "OK"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "List jobs in the failed (dead letter) registry.",
        "tags": []
      }
    },
    "/v1/jobs/{job_id}": {
      "delete": {
        "description": "Returns:     Empty response with 204 status on success.     400 if job_id is not a valid UUID.     403 if credentials do not match the job submitter.     404 if job not found.     409 if job already finished or failed.",
        "operationId": "delete__v1_jobs_{job_id}",
        "parameters": [
          {
            "description": "",
            "in": "path",
            "name": "job_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Args:     job_id: UUID of the job to cancel.",
        "tags": []
      }
    },
    "/v1/jobs/{job_id}/replay": {
      "post": {
        "description": "The stored credentials are never used \u2014 the caller's Basic Auth credentials are substituted instead.\n\nArgs:     job_id: UUID of the failed job to replay.\n\nReturns:     202: JobResponse (new job enqueued)     401: Unauthorized     403: Caller credentials don't match original job submitter     404: Job not found in failed registry     409: Job is not in failed state",
        "operationId": "post__v1_jobs_{job_id}_replay",
        "parameters": [
          {
            "description": "",
            "in": "path",
            "name": "job_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobResponse.c5eb086"
                }
              }
            },
            "description": "Accepted"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Re-enqueue a failed job using the caller's current credentials.",
        "tags": []
      }
    },
    "/v1/send_command": {
      "get": {
        "description": "",
        "operationId": "get__v1_send_command",
        "parameters": [],
        "responses": {},
        "summary": "get <GET>",
        "tags": []
      },
      "post": {
        "description": "Requires you submit the following in the payload:     ip: str     commands: Sequence[str] Optional:     port: int - Default 22     platform: str - Default cisco_ios     enable: Optional[str] - Default the password provided for basic auth\n\nSecured by Basic Auth, which is then passed to the network device. :return: A dict of the job ID, a 202 response code, and the job_id as the X-Request-ID header",
        "operationId": "post__v1_send_command",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendCommandRequest.c5eb086"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobResponse.c5eb086"
                }
              }
            },
            "description": "Accepted"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Will enqueue an attempt to run commands on a device.",
        "tags": []
      }
    },
    "/v1/send_command/{job_id}": {
      "get": {
        "description": "",
        "operationId": "get__v1_send_command_{job_id}",
        "parameters": [
          {
            "description": "",
            "in": "path",
            "name": "job_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobResultResponse.c5eb086"
                }
              }
            },
            "description": "OK"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Given the requested job_id, return status and/or any results if finished. :param job_id: :return: A dict of job status and/or results if finished.",
        "tags": []
      }
    },
    "/v1/send_command_structured": {
      "get": {
        "description": "",
        "operationId": "get__v1_send_command_structured",
        "parameters": [],
        "responses": {},
        "summary": "get <GET>",
        "tags": []
      },
      "post": {
        "description": "Returns parsed list[dict] per command (or raw string if no template found). Uses ntc-templates by default, or custom template if provided.\n\nRequires:     ip: str     commands: Sequence[str] Optional:     port: int - Default 22     platform: str - Default cisco_ios (use \"autodetect\" for SSHDetect)     read_timeout: float - Default 30.0 seconds     textfsm_template: str - Custom TextFSM template (uses ntc-templates if omitted)\n\nSecured by Basic Auth, which is then passed to the network device. :return: A dict of the job ID, a 202 response code, and the job_id as the X-Request-ID header",
        "operationId": "post__v1_send_command_structured",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendCommandStructuredRequest.c5eb086"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobResponse.c5eb086"
                }
              }
            },
            "description": "Accepted"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Enqueue a send_command job with TextFSM parsing for structured output.",
        "tags": []
      }
    },
    "/v1/send_command_structured/{job_id}": {
      "get": {
        "description": "",
        "operationId": "get__v1_send_command_structured_{job_id}",
        "parameters": [
          {
            "description": "",
            "in": "path",
            "name": "job_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobResultResponse.c5eb086"
                }
              }
            },
            "description": "OK"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Given the requested job_id, return status and/or any results if finished. :param job_id: :return: A dict of job status and/or results if finished.",
        "tags": []
      }
    },
    "/v1/send_config": {
      "get": {
        "description": "",
        "operationId": "get__v1_send_config",
        "parameters": [],
        "responses": {},
        "summary": "get <GET>",
        "tags": []
      },
      "post": {
        "description": "Requires you submit the following in the payload:     ip: str     commands: Sequence[str] Optional:     port: int - Default 22     platform: str - Default cisco_ios     enable: Optional[str] - Default the password provided for basic auth     save_config: bool     commit: bool\n\nSecured by Basic Auth, which is then passed to the network device. :return: A dict of the job ID, a 202 response code, and the job_id as the X-Request-ID header",
        "operationId": "post__v1_send_config",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendConfigRequest.c5eb086"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobResponse.c5eb086"
                }
              }
            },
            "description": "Accepted"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Will enqueue an attempt to use netmiko's send_config_set() method to run commands/put configuration on a device.",
        "tags": []
      }
    },
    "/v1/send_config/{job_id}": {
      "get": {
        "description": "",
        "operationId": "get__v1_send_config_{job_id}",
        "parameters": [
          {
            "description": "",
            "in": "path",
            "name": "job_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobResultResponse.c5eb086"
                }
              }
            },
            "description": "OK"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Given the requested job_id, return status and/or any results if finished. :param job_id: :return: A dict of job status and/or results if finished.",
        "tags": []
      }
    },
    "/v2/api-keys": {
      "get": {
        "description": "",
        "operationId": "get__v2_api-keys",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyListResponse.c5eb086"
                }
              }
            },
            "description": "OK"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "List all active API keys (metadata only, not tokens).",
        "tags": []
      },
      "post": {
        "description": "",
        "operationId": "post__v2_api-keys",
        "parameters": [],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyCreateResponse.c5eb086"
                }
              }
            },
            "description": "Created"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Create a new API key. Returns the JWT token once.",
        "tags": []
      }
    },
    "/v2/api-keys/{key_id}": {
      "delete": {
        "description": "",
        "operationId": "delete__v2_api-keys_{key_id}",
        "parameters": [
          {
            "description": "",
            "in": "path",
            "name": "key_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Revoke an API key.",
        "tags": []
      }
    },
    "/v2/api-keys/{key_id}/rotate": {
      "post": {
        "description": "",
        "operationId": "post__v2_api-keys_{key_id}_rotate",
        "parameters": [
          {
            "description": "",
            "in": "path",
            "name": "key_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyCreateResponse.c5eb086"
                }
              }
            },
            "description": "Created"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Rotate an API key. Returns a new token, revokes the old key.",
        "tags": []
      }
    },
    "/v2/contexts": {
      "get": {
        "description": ":return: ContextsResponse with per-context status",
        "operationId": "get__v2_contexts",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContextsResponse.c5eb086"
                }
              }
            },
            "description": "OK"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "List all configured contexts with active worker counts and queue depths.",
        "tags": []
      }
    },
    "/v2/healthcheck": {
      "get": {
        "description": "Returns:     dict: Health status with the following structure:         {             \"status\": str,  # \"healthy\", \"degraded\", or \"no_workers\"             \"version\": str,  # NAAS version             \"uptime_seconds\": int,  # Seconds since API start             \"components\": {                 \"redis\": {\"status\": str},  # \"healthy\" or \"unhealthy\"                 \"queue\": {\"status\": str, \"depth\": int},  # Queue status and job count                 \"workers\": {                     \"status\": str,  # \"healthy\" or \"no_workers\"                     \"count\": int,  # Number of worker pods/hosts                     \"active_jobs\": int  # Jobs currently processing                 }             }         }",
        "operationId": "get__v2_healthcheck",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthCheckResponse.c5eb086"
                }
              }
            },
            "description": "OK"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Return detailed health status including component checks.",
        "tags": []
      }
    },
    "/v2/jobs": {
      "get": {
        "description": "",
        "operationId": "get__v2_jobs",
        "parameters": [
          {
            "description": "",
            "in": "query",
            "name": "page",
            "required": false,
            "schema": {
              "default": 1,
              "minimum": 1,
              "title": "Page",
              "type": "integer"
            }
          },
          {
            "description": "",
            "in": "query",
            "name": "per_page",
            "required": false,
            "schema": {
              "default": 20,
              "maximum": 100,
              "minimum": 1,
              "title": "Per Page",
              "type": "integer"
            }
          },
          {
            "description": "",
            "in": "query",
            "name": "status",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "enum": [
                    "finished",
                    "failed",
                    "started",
                    "queued"
                  ],
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "default": null,
              "title": "Status"
            }
          },
          {
            "description": "Filter by tag in 'key:value' format",
            "in": "query",
            "name": "tag",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "default": null,
              "description": "Filter by tag in 'key:value' format",
              "title": "Tag"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListJobsResponse.c5eb086"
                }
              }
            },
            "description": "OK"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "List jobs with pagination and filtering. Query parameters: - page: Page number (default: 1) - per_page: Results per page (default: 20, max: 100) - status: Filter by status (finished, failed, started, queued) :return: Dict with jobs list and pagination info",
        "tags": []
      }
    },
    "/v2/jobs/failed": {
      "get": {
        "description": "Returns:     200: {\"jobs\": [...], \"total\": int}     401: Unauthorized",
        "operationId": "get__v2_jobs_failed",
        "parameters": [],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FailedJobsResponse.c5eb086"
                }
              }
            },
            "description": "OK"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "List jobs in the failed (dead letter) registry.",
        "tags": []
      }
    },
    "/v2/jobs/{job_id}": {
      "delete": {
        "description": "Returns:     Empty response with 204 status on success.     400 if job_id is not a valid UUID.     403 if credentials do not match the job submitter.     404 if job not found.     409 if job already finished or failed.",
        "operationId": "delete__v2_jobs_{job_id}",
        "parameters": [
          {
            "description": "",
            "in": "path",
            "name": "job_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Args:     job_id: UUID of the job to cancel.",
        "tags": []
      }
    },
    "/v2/jobs/{job_id}/replay": {
      "post": {
        "description": "The stored credentials are never used \u2014 the caller's Basic Auth credentials are substituted instead.\n\nArgs:     job_id: UUID of the failed job to replay.\n\nReturns:     202: JobResponse (new job enqueued)     401: Unauthorized     403: Caller credentials don't match original job submitter     404: Job not found in failed registry     409: Job is not in failed state",
        "operationId": "post__v2_jobs_{job_id}_replay",
        "parameters": [
          {
            "description": "",
            "in": "path",
            "name": "job_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobResponse.c5eb086"
                }
              }
            },
            "description": "Accepted"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Re-enqueue a failed job using the caller's current credentials.",
        "tags": []
      }
    },
    "/v2/jobs/{job_id}/stream": {
      "get": {
        "description": "Args:     job_id: The job UUID to stream.\n\nReturns:     A streaming ``text/event-stream`` response.",
        "operationId": "get__v2_jobs_{job_id}_stream",
        "parameters": [
          {
            "description": "",
            "in": "path",
            "name": "job_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {},
        "summary": "Open an SSE stream for the given job.",
        "tags": []
      }
    },
    "/v2/send-command": {
      "get": {
        "description": "",
        "operationId": "get__v2_send-command",
        "parameters": [],
        "responses": {},
        "summary": "get <GET>",
        "tags": []
      },
      "post": {
        "description": "Requires you submit the following in the payload:     ip: str     commands: Sequence[str] Optional:     port: int - Default 22     platform: str - Default cisco_ios     enable: Optional[str] - Default the password provided for basic auth\n\nSecured by Basic Auth, which is then passed to the network device. :return: A dict of the job ID, a 202 response code, and the job_id as the X-Request-ID header",
        "operationId": "post__v2_send-command",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendCommandRequest.c5eb086"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobResponse.c5eb086"
                }
              }
            },
            "description": "Accepted"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Will enqueue an attempt to run commands on a device.",
        "tags": []
      }
    },
    "/v2/send-command-structured": {
      "get": {
        "description": "",
        "operationId": "get__v2_send-command-structured",
        "parameters": [],
        "responses": {},
        "summary": "get <GET>",
        "tags": []
      },
      "post": {
        "description": "Returns parsed list[dict] per command (or raw string if no template found). Uses ntc-templates by default, or custom template if provided.\n\nRequires:     ip: str     commands: Sequence[str] Optional:     port: int - Default 22     platform: str - Default cisco_ios (use \"autodetect\" for SSHDetect)     read_timeout: float - Default 30.0 seconds     textfsm_template: str - Custom TextFSM template (uses ntc-templates if omitted)\n\nSecured by Basic Auth, which is then passed to the network device. :return: A dict of the job ID, a 202 response code, and the job_id as the X-Request-ID header",
        "operationId": "post__v2_send-command-structured",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendCommandStructuredRequest.c5eb086"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobResponse.c5eb086"
                }
              }
            },
            "description": "Accepted"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Enqueue a send_command job with TextFSM parsing for structured output.",
        "tags": []
      }
    },
    "/v2/send-command-structured/{job_id}": {
      "get": {
        "description": "",
        "operationId": "get__v2_send-command-structured_{job_id}",
        "parameters": [
          {
            "description": "",
            "in": "path",
            "name": "job_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobResultResponse.c5eb086"
                }
              }
            },
            "description": "OK"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Given the requested job_id, return status and/or any results if finished. :param job_id: :return: A dict of job status and/or results if finished.",
        "tags": []
      }
    },
    "/v2/send-command/{job_id}": {
      "get": {
        "description": "",
        "operationId": "get__v2_send-command_{job_id}",
        "parameters": [
          {
            "description": "",
            "in": "path",
            "name": "job_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobResultResponse.c5eb086"
                }
              }
            },
            "description": "OK"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Given the requested job_id, return status and/or any results if finished. :param job_id: :return: A dict of job status and/or results if finished.",
        "tags": []
      }
    },
    "/v2/send-config": {
      "get": {
        "description": "",
        "operationId": "get__v2_send-config",
        "parameters": [],
        "responses": {},
        "summary": "get <GET>",
        "tags": []
      },
      "post": {
        "description": "Requires you submit the following in the payload:     ip: str     commands: Sequence[str] Optional:     port: int - Default 22     platform: str - Default cisco_ios     enable: Optional[str] - Default the password provided for basic auth     save_config: bool     commit: bool\n\nSecured by Basic Auth, which is then passed to the network device. :return: A dict of the job ID, a 202 response code, and the job_id as the X-Request-ID header",
        "operationId": "post__v2_send-config",
        "parameters": [],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendConfigRequest.c5eb086"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobResponse.c5eb086"
                }
              }
            },
            "description": "Accepted"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Will enqueue an attempt to use netmiko's send_config_set() method to run commands/put configuration on a device.",
        "tags": []
      }
    },
    "/v2/send-config/{job_id}": {
      "get": {
        "description": "",
        "operationId": "get__v2_send-config_{job_id}",
        "parameters": [
          {
            "description": "",
            "in": "path",
            "name": "job_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobResultResponse.c5eb086"
                }
              }
            },
            "description": "OK"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError.6a07bef"
                }
              }
            },
            "description": "Unprocessable Content"
          }
        },
        "summary": "Given the requested job_id, return status and/or any results if finished. :param job_id: :return: A dict of job status and/or results if finished.",
        "tags": []
      }
    }
  },
  "security": [
    {
      "basicAuth": []
    }
  ],
  "tags": []
}
