{
  "openapi": "3.0.0",
  "info": {
    "title": "Cron API",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://api.cron.cool"
    }
  ],
  "components": {
    "schemas": {
      "Entity": {
        "type": "object",
        "description": "A Croncool resource. Fields vary by endpoint and requested projection.",
        "additionalProperties": true
      },
      "Page": {
        "type": "object",
        "required": [
          "data",
          "hasMore"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Entity"
            }
          },
          "cursor": {
            "type": "string",
            "nullable": true
          },
          "hasMore": {
            "type": "boolean"
          }
        }
      },
      "Error": {
        "type": "object",
        "description": "Structured JSON API error.",
        "required": [
          "name",
          "message",
          "status"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "details": {
            "type": "object",
            "additionalProperties": true
          }
        }
      }
    },
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "basic",
        "description": "HTTP Basic auth carrying only the API key secret: Authorization: Basic base64(<key secret>)."
      },
      "accessToken": {
        "type": "apiKey",
        "in": "header",
        "name": "Authorization",
        "description": "Operator session token issued by the Cron dashboard: Authorization: Token <access token>."
      }
    }
  },
  "paths": {
    "/api/jobs": {
      "get": {
        "tags": [
          "Jobs"
        ],
        "summary": "List cron jobs",
        "description": "Lists the cron jobs of your project, newest first. Requires the `jobs:read` scope.\n",
        "security": [
          {
            "apiKey": []
          },
          {
            "accessToken": []
          }
        ],
        "parameters": [
          {
            "in": "query",
            "name": "projectId",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "description": "Opt into pagination; returns a { data, cursor, hasMore } envelope.\n",
            "schema": {
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "cursor",
            "description": "Page forward by resending the cursor from the last page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "fields",
            "description": "Comma-separated projection of fields to return",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Array of jobs (or a paginated envelope)",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Entity"
                      }
                    },
                    {
                      "$ref": "#/components/schemas/Page"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid credentials",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "API key is missing the `jobs:read` scope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "API key rate limit exceeded",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the request may be retried.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "getApiJobs"
      },
      "post": {
        "tags": [
          "Jobs"
        ],
        "summary": "Create a cron job",
        "description": "Requires the `jobs:write` scope.",
        "security": [
          {
            "apiKey": []
          },
          {
            "accessToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "expression"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "expression": {
                    "type": "string",
                    "description": "EventBridge Scheduler schedule expression",
                    "example": "rate(1 day)"
                  },
                  "type": {
                    "type": "string",
                    "example": "webhook"
                  },
                  "url": {
                    "type": "string",
                    "example": "https://example.com/task"
                  },
                  "httpMethod": {
                    "type": "string",
                    "example": "POST"
                  },
                  "contentType": {
                    "type": "string",
                    "example": "application/json"
                  },
                  "input": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created job",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Entity"
                }
              }
            }
          },
          "403": {
            "description": "API key is missing the `jobs:write` scope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "postApiJobs"
      }
    },
    "/api/jobs/{jobId}": {
      "get": {
        "tags": [
          "Jobs"
        ],
        "summary": "Get a cron job",
        "description": "Requires the `jobs:read` scope.",
        "security": [
          {
            "apiKey": []
          },
          {
            "accessToken": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "jobId",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The job",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Entity"
                }
              }
            }
          },
          "404": {
            "description": "No such job in your project",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "getApiJobsJobId"
      },
      "put": {
        "tags": [
          "Jobs"
        ],
        "summary": "Update a cron job",
        "description": "Requires the `jobs:write` scope.",
        "security": [
          {
            "apiKey": []
          },
          {
            "accessToken": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "jobId",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated job",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Entity"
                }
              }
            }
          },
          "404": {
            "description": "No such job in your project",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "putApiJobsJobId"
      },
      "delete": {
        "tags": [
          "Jobs"
        ],
        "summary": "Delete a cron job",
        "description": "Requires the `jobs:write` scope.",
        "security": [
          {
            "apiKey": []
          },
          {
            "accessToken": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "jobId",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Entity"
                }
              }
            }
          },
          "404": {
            "description": "No such job in your project",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "deleteApiJobsJobId"
      }
    },
    "/api/jobs/{jobId}/executions": {
      "get": {
        "tags": [
          "Jobs"
        ],
        "summary": "List a job's execution history",
        "description": "Returns the recorded executions of a job (status, http status, duration, truncated response body), newest first. Requires the `executions:read` scope.\n",
        "security": [
          {
            "apiKey": []
          },
          {
            "accessToken": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "jobId",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "type": "integer",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Array of job executions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Entity"
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such job in your project",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "getApiJobsJobIdExecutions"
      }
    },
    "/api/jobs/{jobId}/execute": {
      "post": {
        "tags": [
          "Jobs"
        ],
        "summary": "Execute a cron job now",
        "description": "Runs the job immediately, out of schedule, and returns the target's response. Also records a job execution and fires the `job.executed` webhook. Requires the `jobs:write` scope.\n",
        "security": [
          {
            "apiKey": []
          },
          {
            "accessToken": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "jobId",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The target's response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Entity"
                }
              }
            }
          },
          "404": {
            "description": "No such job in your project",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "operationId": "postApiJobsJobIdExecute"
      }
    },
    "/api/webhooksubscriptions": {
      "get": {
        "tags": [
          "Webhook subscriptions"
        ],
        "summary": "List webhook subscriptions",
        "description": "Webhook subscriptions deliver `job.created`, `job.updated`, `job.deleted` and `job.executed` events to your server as signed POST requests (`X-Croncool-Signature: t=<timestamp>,v1=<hex HMAC-SHA256 of \"timestamp.body\">`). An endpoint failing 20 times in a row is disabled automatically. Subscriptions are managed with an operator access token; the `secret` is only returned once, on create.\n",
        "security": [
          {
            "accessToken": []
          }
        ],
        "parameters": [
          {
            "in": "query",
            "name": "projectId",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Array of webhook subscriptions (without secrets)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Entity"
                  }
                }
              }
            }
          }
        },
        "operationId": "getApiWebhooksubscriptions"
      },
      "post": {
        "tags": [
          "Webhook subscriptions"
        ],
        "summary": "Create a webhook subscription",
        "description": "The response includes the signing `secret` exactly once — store it; it cannot be retrieved again.\n",
        "security": [
          {
            "accessToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "projectId",
                  "url"
                ],
                "properties": {
                  "projectId": {
                    "type": "string"
                  },
                  "url": {
                    "type": "string",
                    "example": "https://example.com/croncool-webhook"
                  },
                  "events": {
                    "type": "array",
                    "description": "Empty array subscribes to all events",
                    "items": {
                      "type": "string",
                      "enum": [
                        "job.created",
                        "job.updated",
                        "job.deleted",
                        "job.executed"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created subscription, including its secret",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Entity"
                }
              }
            }
          }
        },
        "operationId": "postApiWebhooksubscriptions"
      }
    },
    "/api/webhooksubscriptions/{webhookSubscriptionId}": {
      "put": {
        "tags": [
          "Webhook subscriptions"
        ],
        "summary": "Update a webhook subscription",
        "description": "`url`, `events` and `active` are editable; the secret and project are immutable. Re-enabling an auto-disabled endpoint is done by setting `active` back to true.\n",
        "security": [
          {
            "accessToken": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "webhookSubscriptionId",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated subscription (without secret)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Entity"
                }
              }
            }
          }
        },
        "operationId": "putApiWebhooksubscriptionsWebhookSubscriptionId"
      },
      "delete": {
        "tags": [
          "Webhook subscriptions"
        ],
        "summary": "Delete a webhook subscription",
        "security": [
          {
            "accessToken": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "webhookSubscriptionId",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Entity"
                }
              }
            }
          }
        },
        "operationId": "deleteApiWebhooksubscriptionsWebhookSubscriptionId",
        "description": "Delete a webhook subscription"
      }
    }
  },
  "tags": []
}
