{"openapi":"3.1.0","info":{"title":"StableSchedule","description":"Prepaid cron scheduling for HTTP webhooks with custom methods, headers, and bodies.","version":"0.1.0","x-guidance":"# StableSchedule API\n\nStableSchedule creates prepaid cron schedules that fire HTTP webhooks. A schedule stores the destination URL, HTTP method, headers, optional body, timeout, and cron expression. Each cron trigger consumes one prepaid run credit before the webhook is sent. When credits reach zero, StableSchedule pauses provider delivery and marks the schedule exhausted; top up to resume.\n\nUse `POST /api/schedule/create` first. It is paid and requires a `sku` run-credit pack plus `cron` and `request`. The returned `schedule.id` is used for all later calls.\n\nUse SIWX with the same paying wallet for management:\n- `GET /api/schedules` lists your schedules.\n- `GET /api/schedule?id=...` returns one schedule.\n- `GET /api/schedule/runs?schedule_id=...` returns recent delivery attempts.\n- `POST /api/schedule/pause`, `/resume`, and `/delete` manage an existing schedule.\n\nUse `POST /api/schedule/topup` when `credits.remaining` is low or the schedule is exhausted. Topup is paid and adds credits to the existing schedule. If the schedule was exhausted, topup resumes it automatically.\n\nCron expressions are passed to Upstash QStash. UTC is the default. Use a `CRON_TZ=Area/City` prefix for timezone-aware schedules, for example `CRON_TZ=America/New_York 0 9 * * *`.\n\nWebhook body can be any JSON value. If the body is a string it is sent as-is; otherwise StableSchedule JSON stringifies it and defaults `content-type` to `application/json` unless you supplied one.","guidance":"# StableSchedule API\n\nStableSchedule creates prepaid cron schedules that fire HTTP webhooks. A schedule stores the destination URL, HTTP method, headers, optional body, timeout, and cron expression. Each cron trigger consumes one prepaid run credit before the webhook is sent. When credits reach zero, StableSchedule pauses provider delivery and marks the schedule exhausted; top up to resume.\n\nUse `POST /api/schedule/create` first. It is paid and requires a `sku` run-credit pack plus `cron` and `request`. The returned `schedule.id` is used for all later calls.\n\nUse SIWX with the same paying wallet for management:\n- `GET /api/schedules` lists your schedules.\n- `GET /api/schedule?id=...` returns one schedule.\n- `GET /api/schedule/runs?schedule_id=...` returns recent delivery attempts.\n- `POST /api/schedule/pause`, `/resume`, and `/delete` manage an existing schedule.\n\nUse `POST /api/schedule/topup` when `credits.remaining` is low or the schedule is exhausted. Topup is paid and adds credits to the existing schedule. If the schedule was exhausted, topup resumes it automatically.\n\nCron expressions are passed to Upstash QStash. UTC is the default. Use a `CRON_TZ=Area/City` prefix for timezone-aware schedules, for example `CRON_TZ=America/New_York 0 9 * * *`.\n\nWebhook body can be any JSON value. If the body is a string it is sent as-is; otherwise StableSchedule JSON stringifies it and defaults `content-type` to `application/json` unless you supplied one."},"servers":[{"url":"https://stableschedule.dev"}],"tags":[{"name":"Schedule"},{"name":"Schedules"}],"paths":{"/api/schedule/create":{"post":{"operationId":"schedule_create","summary":"Create a prepaid cron schedule that dispatches a configured HTTP webhook.","tags":["Schedule"],"x-payment-info":{"price":{"mode":"dynamic","currency":"USD","min":"0.01","max":"1.00"},"protocols":[{"x402":{}},{"mpp":{"method":"tempo","intent":"charge","currency":"0x20c000000000000000000000b9537d11c60e8b50"}}]},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"cron":{"type":"string","minLength":1,"maxLength":120},"sku":{"type":"string","enum":["1k","10k","100k"]},"request":{"type":"object","properties":{"url":{"type":"string","maxLength":2048,"format":"uri"},"method":{"default":"POST","type":"string","enum":["GET","POST","PUT","PATCH","DELETE"]},"headers":{"default":{},"type":"object","propertyNames":{"type":"string","minLength":1,"maxLength":120},"additionalProperties":{"type":"string","maxLength":4096}},"body":{},"timeout_ms":{"type":"integer","minimum":1000,"maximum":30000}},"required":["url"]}},"required":["cron","sku","request"]}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"schedule":{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["active","paused","exhausted","deleted","failed"]},"cron":{"type":"string"},"request":{"type":"object","properties":{"url":{"type":"string"},"method":{"type":"string","enum":["GET","POST","PUT","PATCH","DELETE"]},"headers":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"body":{"anyOf":[{},{"type":"null"}]},"timeout_ms":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["url","method","headers","body","timeout_ms"],"additionalProperties":false},"credits":{"type":"object","properties":{"total":{"type":"integer","minimum":0,"maximum":9007199254740991},"used":{"type":"integer","minimum":0,"maximum":9007199254740991},"remaining":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["total","used","remaining"],"additionalProperties":false},"created_at":{"type":"string"},"updated_at":{"type":"string"},"last_run_at":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","status","cron","request","credits","created_at","updated_at","last_run_at"],"additionalProperties":false}},"required":["schedule"],"additionalProperties":false}}}},"402":{"description":"Payment Required"}}}},"/api/schedule/topup":{"post":{"operationId":"schedule_topup","summary":"Add prepaid run credits to an existing schedule.","tags":["Schedule"],"x-payment-info":{"price":{"mode":"dynamic","currency":"USD","min":"0.01","max":"1.00"},"protocols":[{"x402":{}},{"mpp":{"method":"tempo","intent":"charge","currency":"0x20c000000000000000000000b9537d11c60e8b50"}}]},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"schedule_id":{"type":"string","minLength":1},"sku":{"type":"string","enum":["1k","10k","100k"]}},"required":["schedule_id","sku"]}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"schedule_id":{"type":"string"},"added_runs":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"credits":{"type":"object","properties":{"total":{"type":"integer","minimum":0,"maximum":9007199254740991},"used":{"type":"integer","minimum":0,"maximum":9007199254740991},"remaining":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["total","used","remaining"],"additionalProperties":false},"status":{"type":"string","enum":["active","paused","exhausted","deleted","failed"]}},"required":["schedule_id","added_runs","credits","status"],"additionalProperties":false}}}},"402":{"description":"Payment Required"}}}},"/api/schedule/pause":{"post":{"operationId":"schedule_pause","summary":"Pause an existing schedule without deleting its config.","tags":["Schedule"],"security":[{"siwx":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"schedule_id":{"type":"string","minLength":1}},"required":["schedule_id"]}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"schedule_id":{"type":"string"},"status":{"type":"string","enum":["active","paused","exhausted","deleted","failed"]}},"required":["success","schedule_id","status"],"additionalProperties":false}}}},"402":{"description":"Authentication Required"}}}},"/api/schedule/resume":{"post":{"operationId":"schedule_resume","summary":"Resume a paused or topped-up exhausted schedule.","tags":["Schedule"],"security":[{"siwx":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"schedule_id":{"type":"string","minLength":1}},"required":["schedule_id"]}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"schedule_id":{"type":"string"},"status":{"type":"string","enum":["active","paused","exhausted","deleted","failed"]}},"required":["success","schedule_id","status"],"additionalProperties":false}}}},"402":{"description":"Authentication Required"}}}},"/api/schedule/delete":{"post":{"operationId":"schedule_delete","summary":"Delete a schedule and stop future cron triggers.","tags":["Schedule"],"security":[{"siwx":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"schedule_id":{"type":"string","minLength":1}},"required":["schedule_id"]}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"schedule_id":{"type":"string"},"status":{"type":"string","enum":["active","paused","exhausted","deleted","failed"]}},"required":["success","schedule_id","status"],"additionalProperties":false}}}},"402":{"description":"Authentication Required"}}}},"/api/schedule/runs":{"get":{"operationId":"schedule_runs","summary":"List recent webhook delivery attempts for a schedule.","tags":["Schedule"],"security":[{"siwx":[]}],"parameters":[{"in":"query","name":"schedule_id","schema":{"type":"string","minLength":1},"required":true},{"in":"query","name":"limit","schema":{"default":25,"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"runs":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"schedule_id":{"type":"string"},"status":{"type":"string","enum":["sent","failed","skipped"]},"started_at":{"type":"string"},"completed_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"duration_ms":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"http_status":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"response_bytes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"error":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","schedule_id","status","started_at","completed_at","duration_ms","http_status","response_bytes","error"],"additionalProperties":false}}},"required":["runs"],"additionalProperties":false}}}},"402":{"description":"Authentication Required"}}}},"/api/schedule":{"get":{"operationId":"schedule","summary":"Get one schedule by ID.","tags":["Schedule"],"security":[{"siwx":[]}],"parameters":[{"in":"query","name":"id","schema":{"type":"string","minLength":1},"required":true}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"schedule":{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["active","paused","exhausted","deleted","failed"]},"cron":{"type":"string"},"request":{"type":"object","properties":{"url":{"type":"string"},"method":{"type":"string","enum":["GET","POST","PUT","PATCH","DELETE"]},"headers":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"body":{"anyOf":[{},{"type":"null"}]},"timeout_ms":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["url","method","headers","body","timeout_ms"],"additionalProperties":false},"credits":{"type":"object","properties":{"total":{"type":"integer","minimum":0,"maximum":9007199254740991},"used":{"type":"integer","minimum":0,"maximum":9007199254740991},"remaining":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["total","used","remaining"],"additionalProperties":false},"created_at":{"type":"string"},"updated_at":{"type":"string"},"last_run_at":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","status","cron","request","credits","created_at","updated_at","last_run_at"],"additionalProperties":false}},"required":["schedule"],"additionalProperties":false}}}},"402":{"description":"Authentication Required"}}}},"/api/schedules":{"get":{"operationId":"schedules","summary":"List all schedules owned by the authenticated wallet.","tags":["Schedules"],"security":[{"siwx":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"schedules":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["active","paused","exhausted","deleted","failed"]},"cron":{"type":"string"},"request":{"type":"object","properties":{"url":{"type":"string"},"method":{"type":"string","enum":["GET","POST","PUT","PATCH","DELETE"]},"headers":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"body":{"anyOf":[{},{"type":"null"}]},"timeout_ms":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["url","method","headers","body","timeout_ms"],"additionalProperties":false},"credits":{"type":"object","properties":{"total":{"type":"integer","minimum":0,"maximum":9007199254740991},"used":{"type":"integer","minimum":0,"maximum":9007199254740991},"remaining":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["total","used","remaining"],"additionalProperties":false},"created_at":{"type":"string"},"updated_at":{"type":"string"},"last_run_at":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","status","cron","request","credits","created_at","updated_at","last_run_at"],"additionalProperties":false}}},"required":["schedules"],"additionalProperties":false}}}},"402":{"description":"Authentication Required"}}}}},"components":{"securitySchemes":{"siwx":{"type":"apiKey","in":"header","name":"SIGN-IN-WITH-X"}}}}