{"openapi":"3.1.0","info":{"title":"CronWizard HTTP API","version":"1.0.0","description":"Public JSON endpoints for generating, validating, previewing, and exporting cron schedules.","license":{"name":"MIT","identifier":"MIT"}},"servers":[{"url":"https://cronwizard.com","description":"Production"}],"externalDocs":{"description":"Human-readable API reference","url":"https://cronwizard.com/docs/api"},"tags":[{"name":"Cron","description":"Cron expression operations"},{"name":"Service","description":"Service status"}],"paths":{"/api/v1/cron/generate":{"post":{"tags":["Cron"],"operationId":"generateCron","summary":"Generate a cron expression","description":"Build a Unix or Quartz expression from a supported wizard mode and parameters.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateRequest"},"example":{"mode":"daily","params":{"at":{"hour":9,"minute":0}},"format":"unix"}}}},"responses":{"200":{"description":"The generated expression and its lossless format equivalents. An unavailable equivalent is null.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateResponse"},"example":{"cron":"0 9 * * *","description":"At 09:00","warnings":[],"normalized":{"unix":"0 9 * * *","quartz":"0 0 9 * * ?"}}}}},"400":{"description":"The request body or cron expression is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"An unexpected processing error occurred.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/cron/next":{"post":{"tags":["Cron"],"operationId":"getNextCronRuns","summary":"Calculate upcoming run times","description":"Return the next 1–50 matching run times in an IANA timezone.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NextRunsRequest"},"example":{"cron":"0 9 * * 1-5","format":"unix","timezone":"Europe/Istanbul","count":5}}}},"responses":{"200":{"description":"Upcoming run times in ISO 8601 and human-readable forms.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NextRunsResponse"}}}},"400":{"description":"The request body or cron expression is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"An unexpected processing error occurred.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/cron/validate":{"post":{"tags":["Cron"],"operationId":"validateCron","summary":"Validate a cron expression","description":"Validate a Unix or supported Quartz cron expression. The Unix normalization is null when a valid Quartz schedule has no lossless 5-field equivalent.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateRequest"},"example":{"cron":"*/15 * * * *","format":"unix"}}}},"responses":{"200":{"description":"Validation result. Invalid cron syntax still returns HTTP 200 with valid set to false. For valid Quartz input, normalized may be null.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateResponse"},"example":{"valid":true,"errors":[],"normalized":"*/15 * * * *"}}}},"400":{"description":"The request body or cron expression is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"An unexpected processing error occurred.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/v1/cron/export":{"post":{"tags":["Cron"],"operationId":"exportCron","summary":"Export a scheduler configuration","description":"Render a schedule for Kubernetes, GitHub Actions, systemd, Docker, AWS EventBridge Scheduler Terraform, crontab, or launchd. Export requires a lossless 5-field Unix equivalent.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExportRequest"},"example":{"cron":"0 9 * * 1-5","format":"unix","target":"k8s","options":{"name":"weekday-job","image":"busybox:latest","command":"echo hello","timezone":"Europe/Istanbul"}}}}},"responses":{"200":{"description":"Rendered configuration text.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExportResponse"}}}},"400":{"description":"The request or cron is invalid, the expression has no lossless 5-field Unix equivalent, or the selected target cannot represent the schedule safely.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"examples":{"invalidRequest":{"summary":"Invalid request body","value":{"code":"VALIDATION_ERROR","message":"Invalid input","details":[]}},"invalidCron":{"summary":"Invalid cron expression","value":{"code":"INVALID_CRON","message":"Invalid Quartz cron: expected 6 or 7 fields, received 5","details":["Invalid Quartz cron: expected 6 or 7 fields, received 5"]}},"unsupportedExportFormat":{"summary":"Valid but not losslessly exportable","value":{"code":"UNSUPPORTED_EXPORT_FORMAT","message":"This expression has no lossless 5-field Unix equivalent and cannot be exported to this target."}},"unsupportedExportSchedule":{"summary":"Target cannot represent this otherwise valid Unix schedule safely","value":{"code":"UNSUPPORTED_EXPORT_SCHEDULE","message":"Cannot convert to Quartz without changing semantics: Unix combines restricted day-of-month and day-of-week fields with OR"}}}}}},"500":{"description":"An unexpected processing error occurred.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}}}},"/api/healthz":{"get":{"tags":["Service"],"operationId":"getHealth","summary":"Check service health","description":"Return the health state and current server timestamp.","responses":{"200":{"description":"The service is available.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"},"example":{"status":"ok","timestamp":"2026-08-05T09:00:00.000Z"}}}}}}}},"components":{"schemas":{"CronFormat":{"type":"string","enum":["unix","quartz"],"description":"Unix accepts portable 5-field cron. Quartz accepts the supported 6- or 7-field syntax described by CronExpression."},"CronExpression":{"type":"string","minLength":1,"maxLength":200,"description":"With format=unix, use a portable 5-field expression; ?, L, W, H, and # are rejected. With format=quartz, use 6 or 7 fields and put ? in exactly one of day-of-month or day-of-week. Quartz seconds, optional years from 1970 through 2099, L, and day-of-week # are supported; W and H are not."},"WizardMode":{"type":"string","enum":["minutes","hourly","daily","weekly","monthly","yearly","advanced"]},"WizardParams":{"type":"object","properties":{"every":{"type":"integer","enum":[1,2,3,4,5,6,10,12,15,20,30],"description":"A divisor of 60, so every gap within the hour is uniform."},"at":{"type":"object","required":["hour","minute"],"properties":{"hour":{"type":"integer","minimum":0,"maximum":23},"minute":{"type":"integer","minimum":0,"maximum":59}}},"days":{"type":"array","items":{"type":"integer","minimum":0,"maximum":6}},"month":{"type":"integer","minimum":1,"maximum":12},"dayOfMonth":{"type":"integer","minimum":1,"maximum":31},"expression":{"$ref":"#/components/schemas/CronExpression"}}},"GenerateRequest":{"type":"object","required":["mode","params","format"],"properties":{"mode":{"$ref":"#/components/schemas/WizardMode"},"params":{"$ref":"#/components/schemas/WizardParams"},"format":{"$ref":"#/components/schemas/CronFormat"}}},"GenerateResponse":{"type":"object","required":["cron","description","warnings","normalized"],"properties":{"cron":{"$ref":"#/components/schemas/CronExpression"},"description":{"type":"string"},"warnings":{"type":"array","items":{"type":"string"}},"normalized":{"$ref":"#/components/schemas/NormalizedCron"}}},"NextRunsRequest":{"type":"object","required":["cron","format","timezone","count"],"properties":{"cron":{"$ref":"#/components/schemas/CronExpression"},"format":{"$ref":"#/components/schemas/CronFormat"},"timezone":{"type":"string","minLength":1,"maxLength":100,"description":"IANA timezone name, for example Europe/Istanbul."},"count":{"type":"integer","minimum":1,"maximum":50},"startDate":{"type":"string","format":"date-time"}}},"NextRunsResponse":{"type":"object","required":["nextRuns","human"],"properties":{"nextRuns":{"type":"array","items":{"type":"string","format":"date-time"}},"human":{"type":"array","items":{"type":"string"}}}},"ValidateRequest":{"type":"object","required":["cron","format"],"properties":{"cron":{"$ref":"#/components/schemas/CronExpression"},"format":{"$ref":"#/components/schemas/CronFormat"}}},"ValidateResponse":{"type":"object","required":["valid","errors"],"properties":{"valid":{"type":"boolean"},"errors":{"type":"array","items":{"type":"string"}},"normalized":{"type":["string","null"],"description":"Canonical 5-field Unix equivalent. Omitted for invalid input and null for valid Quartz input that cannot be converted losslessly."}}},"ExportRequest":{"type":"object","required":["cron","format","target"],"properties":{"cron":{"$ref":"#/components/schemas/CronExpression"},"format":{"$ref":"#/components/schemas/CronFormat"},"target":{"type":"string","enum":["k8s","gha","systemd","docker","terraform","crontab","launchd"]},"options":{"$ref":"#/components/schemas/ExportOptions"}}},"ExportOptions":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":128},"image":{"type":"string","minLength":1,"maxLength":512},"command":{"type":"string","minLength":1,"maxLength":8192},"description":{"type":"string","minLength":1,"maxLength":1024},"timezone":{"type":"string","minLength":1,"maxLength":100,"description":"IANA timezone embedded by Kubernetes, GitHub Actions, systemd, Ofelia, and EventBridge Scheduler. Omit for crontab and launchd, which use the runtime or host timezone."}}},"ExportResponse":{"type":"object","required":["text"],"properties":{"text":{"type":"string"}}},"NormalizedCron":{"type":"object","required":["unix","quartz"],"description":"Canonical lossless equivalents. A field is null when the schedule cannot be represented in that dialect without changing its behavior.","properties":{"unix":{"type":["string","null"],"description":"Null for Quartz schedules with nonzero seconds, a restricted year, day-of-month L, weekday nL, or # syntax."},"quartz":{"type":["string","null"],"description":"Null when Unix restricts both day-of-month and day-of-week because Unix OR semantics are not losslessly expressible in Quartz."}},"examples":[{"unix":"0 9 * * *","quartz":"0 0 9 * * ?"},{"unix":null,"quartz":"30 0 9 ? * MON"}]},"ApiError":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["VALIDATION_ERROR","INVALID_CRON","INVALID_GENERATED_CRON","NO_FUTURE_RUNS","UNSUPPORTED_EXPORT_FORMAT","UNSUPPORTED_EXPORT_SCHEDULE","INTERNAL_ERROR"]},"message":{"type":"string"},"details":{}}},"HealthResponse":{"type":"object","required":["status","timestamp"],"properties":{"status":{"type":"string","const":"ok"},"timestamp":{"type":"string","format":"date-time"}}}}}}