{
  "openapi": "3.1.0",
  "info": {
    "title": "CronHub Orchestration Protocol",
    "version": "1.0.0",
    "description": "Authenticated CronHub COP endpoints used by service SDKs."
  },
  "servers": [
    {
      "url": "https://cronhub.wejoona.com"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/api/v1/register": {
      "post": {
        "operationId": "registerService",
        "summary": "Register a service and its jobs",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RegisterManifest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Service and jobs registered",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegisterResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/jobs/{id}/pause": {
      "post": {
        "operationId": "pauseJob",
        "summary": "Pause a job",
        "parameters": [
          {
            "$ref": "#/components/parameters/JobId"
          }
        ],
        "responses": {
          "200": {
            "description": "Job paused",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobPauseResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/jobs/{id}/resume": {
      "post": {
        "operationId": "resumeJob",
        "summary": "Resume a job",
        "parameters": [
          {
            "$ref": "#/components/parameters/JobId"
          }
        ],
        "responses": {
          "200": {
            "description": "Job resumed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobPauseResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/jobs/{id}/trigger": {
      "post": {
        "operationId": "triggerJob",
        "summary": "Trigger a job manually",
        "parameters": [
          {
            "$ref": "#/components/parameters/JobId"
          }
        ],
        "responses": {
          "200": {
            "description": "Job trigger accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TriggerResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/jobs/{id}/reset": {
      "post": {
        "operationId": "resetCircuitBreaker",
        "summary": "Reset a job circuit breaker",
        "parameters": [
          {
            "$ref": "#/components/parameters/JobId"
          }
        ],
        "responses": {
          "200": {
            "description": "Circuit breaker reset",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CircuitBreakerResetResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/jobs/{id}/runs": {
      "get": {
        "operationId": "listRuns",
        "summary": "List runs for a job",
        "parameters": [
          {
            "$ref": "#/components/parameters/JobId"
          },
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated run history",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunHistoryResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/jobs/{id}": {
      "delete": {
        "operationId": "deleteJob",
        "summary": "Delete a registered job",
        "parameters": [
          {
            "$ref": "#/components/parameters/JobId"
          }
        ],
        "responses": {
          "200": {
            "description": "Job deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteJobResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/runs/{run_id}/complete": {
      "post": {
        "operationId": "completeRun",
        "summary": "Complete a run",
        "parameters": [
          {
            "$ref": "#/components/parameters/RunId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RunCompletePayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Run completed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunCompleteResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/services": {
      "get": {
        "operationId": "listServices",
        "summary": "List registered services",
        "responses": {
          "200": {
            "description": "Registered services",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceListResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer"
      }
    },
    "parameters": {
      "JobId": {
        "name": "id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "RunId": {
        "name": "run_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "Page": {
        "name": "page",
        "in": "query",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        }
      },
      "PerPage": {
        "name": "per_page",
        "in": "query",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 20
        }
      }
    },
    "schemas": {
      "RegisterManifest": {
        "type": "object",
        "required": ["service", "version", "base_url", "jobs"],
        "properties": {
          "service": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "base_url": {
            "type": "string",
            "format": "uri"
          },
          "environment": {
            "type": "string"
          },
          "jobs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/JobDefinition"
            }
          }
        }
      },
      "JobDefinition": {
        "type": "object",
        "required": ["name", "endpoint", "schedule"],
        "properties": {
          "name": {
            "type": "string"
          },
          "endpoint": {
            "type": "string"
          },
          "method": {
            "type": "string",
            "default": "POST"
          },
          "schedule": {
            "type": "string"
          },
          "timeout_ms": {
            "type": "integer"
          },
          "grace_period_s": {
            "type": "integer"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "severity": {
            "type": "string",
            "enum": ["low", "medium", "high", "critical"]
          },
          "retries": {
            "type": "integer"
          },
          "depends_on": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "RegisterResponse": {
        "type": "object",
        "required": ["status", "service_id", "jobs", "orphaned"],
        "properties": {
          "status": {
            "type": "string"
          },
          "service_id": {
            "type": "string"
          },
          "jobs": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["id", "name", "schedule"],
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "schedule": {
                  "type": "string"
                }
              }
            }
          },
          "orphaned": {
            "type": "integer"
          }
        }
      },
      "RunCompletePayload": {
        "type": "object",
        "required": ["status"],
        "properties": {
          "status": {
            "type": "string",
            "enum": ["ok", "error"]
          },
          "duration_ms": {
            "type": "integer"
          },
          "output": {
            "type": "string"
          }
        }
      },
      "RunCompleteResponse": {
        "type": "object",
        "required": ["status", "run_id", "final_status"],
        "properties": {
          "status": {
            "type": "string"
          },
          "run_id": {
            "type": "string"
          },
          "final_status": {
            "type": "string"
          }
        }
      },
      "TriggerResponse": {
        "type": "object",
        "required": ["status"],
        "properties": {
          "status": {
            "type": "string"
          },
          "message": {
            "type": "string"
          }
        }
      },
      "JobPauseResponse": {
        "type": "object",
        "required": ["status", "id", "paused"],
        "properties": {
          "status": {
            "type": "string"
          },
          "id": {
            "type": "string"
          },
          "paused": {
            "type": "boolean"
          }
        }
      },
      "CircuitBreakerResetResponse": {
        "type": "object",
        "required": ["status", "id", "consecutive_failures", "paused"],
        "properties": {
          "status": {
            "type": "string"
          },
          "id": {
            "type": "string"
          },
          "consecutive_failures": {
            "type": "integer"
          },
          "paused": {
            "type": "boolean"
          }
        }
      },
      "DeleteJobResponse": {
        "type": "object",
        "required": ["status"],
        "properties": {
          "status": {
            "type": "string"
          }
        }
      },
      "RunHistoryResponse": {
        "type": "object",
        "required": ["data", "meta"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RunHistoryItem"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/PaginationMeta"
          }
        }
      },
      "RunHistoryItem": {
        "type": "object",
        "required": ["id", "run_id", "trigger_type", "started_at", "status"],
        "properties": {
          "id": {
            "type": "string"
          },
          "run_id": {
            "type": "string"
          },
          "trigger_type": {
            "type": "string"
          },
          "started_at": {
            "type": "string",
            "format": "date-time"
          },
          "completed_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "status": {
            "type": "string"
          },
          "response_code": {
            "type": ["integer", "null"]
          },
          "duration_ms": {
            "type": ["integer", "null"]
          },
          "retry_count": {
            "type": ["integer", "null"]
          },
          "error": {
            "type": ["string", "null"]
          }
        }
      },
      "PaginationMeta": {
        "type": "object",
        "required": ["page", "total", "total_pages", "per_page"],
        "properties": {
          "page": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          },
          "total_pages": {
            "type": "integer"
          },
          "per_page": {
            "type": "integer"
          }
        }
      },
      "ServiceListResponse": {
        "type": "object",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServiceSummary"
            }
          }
        }
      },
      "ServiceSummary": {
        "type": "object",
        "required": ["id", "name", "version", "base_url", "environment", "job_count"],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "base_url": {
            "type": "string",
            "format": "uri"
          },
          "environment": {
            "type": "string"
          },
          "health_status": {
            "type": ["string", "null"]
          },
          "last_registered_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "job_count": {
            "type": "integer"
          }
        }
      }
    }
  }
}
