{"openapi":"3.1.0","info":{"title":"Untimely API","version":"0.1.0","description":"Canonical API for dashboard users and API-key authenticated automation. API keys are created in the dashboard by signed-in users."},"servers":[{"url":"https://untimely.app","description":"Production"},{"url":"https://untimely-preview.bitspice.workers.dev","description":"Preview"}],"paths":{"/api/events":{"get":{"summary":"List events with schedule and run status","security":[{"ApiKey":[]}],"responses":{"200":{"description":"Events owned by the authenticated user","content":{"application/json":{"schema":{"type":"object","required":["events"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/EventStatus"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"summary":"Create an event","description":"Creates random or deterministic schedules. Use Idempotency-Key for safe retries.","security":[{"ApiKey":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":200},"description":"Use the same key with the same JSON body to retry safely."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEventRequest"}}}},"responses":{"201":{"description":"Created event and generated schedule dates","headers":{"Idempotency-Replayed":{"schema":{"type":"string","enum":["true","false"]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEventResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/api/events/{id}":{"get":{"summary":"Read schedule and run status for one event","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/EventId"}],"responses":{"200":{"description":"Event status","content":{"application/json":{"schema":{"type":"object","required":["event"],"properties":{"event":{"$ref":"#/components/schemas/EventStatus"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"summary":"Update an event","security":[{"ApiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEventRequest"}}}},"responses":{"204":{"$ref":"#/components/responses/NoContent"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"summary":"Delete an event","security":[{"ApiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"$ref":"#/components/responses/NoContent"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/events/{id}/schedules/{scheduleId}":{"get":{"summary":"Read one schedule run and tool attempts","security":[{"ApiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"scheduleId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Schedule details with run and tool attempt history","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleDetailResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/users/api-keys":{"get":{"summary":"List dashboard API key metadata","description":"Requires a browser session. Key material is never returned.","responses":{"200":{"description":"API key metadata","content":{"application/json":{"schema":{"type":"object","required":["keys"],"properties":{"keys":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyMetadata"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}},"security":[{"CookieSession":[]}]},"post":{"summary":"Create a dashboard API key","description":"Requires a browser session. The raw API key is returned once.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","default":"API key"}}}}}},"responses":{"201":{"description":"New one-time API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreateResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}},"security":[{"CookieSession":[]}]}},"/api/users/api-keys/{id}":{"delete":{"summary":"Revoke a dashboard API key","description":"Requires a browser session.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"API key revoked"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"CookieSession":[]}]}}},"components":{"securitySchemes":{"ApiKey":{"type":"http","scheme":"bearer","bearerFormat":"utly"},"CookieSession":{"type":"apiKey","in":"cookie","name":"better-auth.session_token","description":"Browser session cookie used by dashboard-only endpoints."}},"parameters":{"EventId":{"name":"id","in":"path","required":true,"schema":{"type":"string"}},"ScheduleId":{"name":"scheduleId","in":"path","required":true,"schema":{"type":"string"}}},"responses":{"BadRequest":{"description":"Request body or parameters were invalid"},"Unauthorized":{"description":"Missing session or invalid API key"},"Forbidden":{"description":"Plan limit or permission boundary prevented the request"},"NotFound":{"description":"The requested resource was not found for the authenticated user"},"Conflict":{"description":"Idempotency key was already used with a different request body"},"NoContent":{"description":"The request completed successfully with no response body"}},"schemas":{"ApiKeyMetadata":{"type":"object","required":["id","name","keyPrefix","createdAt"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"keyPrefix":{"type":"string"},"lastUsedAt":{"type":["string","null"],"format":"date-time"},"revokedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"}}},"ApiKeyCreateResponse":{"allOf":[{"$ref":"#/components/schemas/ApiKeyMetadata"},{"type":"object","required":["apiKey"],"properties":{"apiKey":{"type":"string","description":"Returned once. Store it securely; the server stores only its hash."}}}]},"CreateEventRequest":{"type":"object","allOf":[{"$ref":"#/components/schemas/EventWriteFields"},{"if":{"properties":{"scheduleType":{"const":"deterministic"}},"required":["scheduleType"]},"then":{"required":["fixedTime","timezone"]}},{"if":{"properties":{"actionType":{"const":"WEBHOOK"}},"required":["actionType"]},"then":{"required":["webhook"]}}],"properties":{"scheduleType":{"type":"string","enum":["random","deterministic"],"default":"random"},"fixedTime":{"type":"string","description":"Deterministic schedules only. HH:MM in the provided timezone."},"timezone":{"type":"string","description":"Required for deterministic schedules. IANA timezone, for example America/Toronto."},"betweenTimeStart":{"type":"string","description":"Random schedules only. HH:MM UTC."},"actionType":{"type":"string","enum":["EMAIL","WEBHOOK"],"description":"Delivery action to run when a schedule triggers."},"webhook":{"$ref":"#/components/schemas/WebhookConfig"}},"unevaluatedProperties":false,"required":[]},"UpdateEventRequest":{"allOf":[{"$ref":"#/components/schemas/EventWriteFields"}],"unevaluatedProperties":false},"EventWriteFields":{"type":"object","properties":{"name":{"type":"string"},"enabled":{"type":"boolean"},"scheduleType":{"type":"string","enum":["random","deterministic"],"default":"random"},"interval":{"type":"integer","minimum":1,"maximum":365,"default":7},"frequency":{"type":"integer","minimum":1,"maximum":5,"default":1,"description":"Random schedules only."},"betweenTimeStart":{"type":"string","pattern":"^\\d{2}:\\d{2}$","default":"09:00","description":"Random schedules only. HH:MM UTC."},"betweenTimeEnd":{"type":"string","pattern":"^\\d{2}:\\d{2}$","default":"17:00","description":"Random schedules only. HH:MM UTC."},"fixedTime":{"type":"string","pattern":"^\\d{2}:\\d{2}$","description":"Deterministic schedules only. HH:MM in the provided timezone."},"timezone":{"type":"string","description":"Required for deterministic schedules. IANA timezone, for example America/Toronto."},"daysOfWeek":{"type":"array","minItems":1,"maxItems":7,"items":{"type":"integer","minimum":0,"maximum":6},"default":[0,1,2,3,4,5,6]},"actionType":{"type":"string","enum":["EMAIL","WEBHOOK"],"default":"EMAIL"},"content":{"type":"string","description":"EMAIL action content."},"contentType":{"type":"string","enum":["static","gpt"],"default":"static"},"webhook":{"$ref":"#/components/schemas/WebhookConfig"}}},"WebhookConfig":{"type":"object","required":["method","url"],"properties":{"method":{"type":"string","enum":["GET","POST","PUT","PATCH","DELETE"]},"url":{"type":"string","format":"uri","description":"Public HTTP or HTTPS webhook URL."},"headers":{"type":"array","items":{"$ref":"#/components/schemas/WebhookHeader"},"default":[],"maxItems":25},"body":{"type":"string","description":"Optional request body. GET requests reject non-empty bodies.","maxLength":65536}}},"WebhookHeader":{"type":"object","required":["key","value"],"properties":{"key":{"type":"string","minLength":1,"maxLength":256},"value":{"type":"string","minLength":1,"maxLength":2048}}},"CreateEventResponse":{"type":"object","required":["id","dates"],"properties":{"id":{"type":"string"},"dates":{"type":"array","items":{"type":"string","format":"date-time"}}}},"EventStatus":{"type":"object","required":["id","name","schedules"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"rule":{"type":["object","null"]},"action":{"type":["object","null"]},"tools":{"type":"array","items":{"$ref":"#/components/schemas/EventTool"}},"schedules":{"type":"array","items":{"$ref":"#/components/schemas/EventSchedule"}}}},"EventTool":{"type":"object","properties":{"id":{"type":"string"},"toolType":{"type":"string","enum":["EMAIL","WEBHOOK"]},"enabled":{"type":"boolean"},"toolConfig":{"type":["object","null"],"additionalProperties":true}}},"EventSchedule":{"type":"object","properties":{"id":{"type":"string"},"triggersAt":{"type":"string","format":"date-time"},"triggeredAt":{"type":["string","null"],"format":"date-time"},"output":{"type":["object","null"],"additionalProperties":true}}},"ScheduleRun":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"startedAt":{"type":["string","null"],"format":"date-time"},"completedAt":{"type":["string","null"],"format":"date-time"}}},"ToolRunAttempt":{"type":"object","properties":{"id":{"type":"string"},"toolType":{"type":"string","enum":["EMAIL","WEBHOOK"]},"status":{"type":"string"},"output":{"type":["object","null"],"additionalProperties":true,"description":"Stored outputs are redacted before persistence."}}},"ScheduleDetailResponse":{"type":"object","properties":{"schedule":{"allOf":[{"$ref":"#/components/schemas/EventSchedule"},{"type":"object","properties":{"run":{"anyOf":[{"$ref":"#/components/schemas/ScheduleRunWithAttempts"},{"type":"null"}]}}}]}}},"ScheduleRunWithAttempts":{"allOf":[{"$ref":"#/components/schemas/ScheduleRun"},{"type":"object","properties":{"attempts":{"type":"array","items":{"$ref":"#/components/schemas/ToolRunAttempt"}}}}]}}}}