{"openapi":"3.0.3","info":{"title":"Slice of Shame API","version":"1.0.0","description":"Organisation data with scoped cake write access. Create a scoped key under Admin → API Keys. 60 requests per key per fixed minute. Timestamps are Unix milliseconds unless noted."},"servers":[{"url":"/","description":"Your deployment origin"}],"security":[{"ApiKey":[]}],"paths":{"/api/v1/organisation":{"get":{"operationId":"get_organisation","summary":"Organisation profile (excludes billing and license details).","description":"Requires scope organisation:read. Organisation is determined by the key. Unknown or repeated parameters return 400.","parameters":[],"responses":{"200":{"description":"Organisation data","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per fixed minute"},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining"},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Window reset time in Unix seconds"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["id"],"additionalProperties":false,"properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"createdAt":{"type":"integer","format":"int64","description":"Unix milliseconds"}}}}}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, expired, or revoked key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"Unsupported method; framework response may not be JSON."},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds before retrying"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/cakes":{"post":{"operationId":"createCake","summary":"Create an active cake","description":"Requires cakes:write. Organisation comes from the key. Every write requires an Idempotency-Key (8–128 letters, digits, underscores or hyphens), unique per organisation. Retry with the same key and body; different payloads return 409. Receipts are retained indefinitely. No query parameters. Finalization requires a due date and uses explicit winners, previously assigned winners, or all members tied for most slices. Finalization can happen before eight slices. Slice requests apply in full or fail; eight slices do not auto-finalize. Completed cakes reject slices; purchased cakes reject PATCH. Finalization returns nextCakeId.","parameters":[{"in":"header","name":"Idempotency-Key","required":true,"schema":{"type":"string","minLength":8,"maxLength":128,"pattern":"^[A-Za-z0-9_-]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"minProperties":1,"required":["cakeTypeId"],"properties":{"cakeTypeId":{"type":"string","minLength":1,"maxLength":128},"dueDate":{"type":"string","format":"date","description":"Scheduled purchase date, YYYY-MM-DD. Returned as midnight UTC ISO timestamp."}}}}}},"responses":{"201":{"description":"Write succeeded (or original response replayed)","headers":{"Idempotency-Replayed":{"schema":{"type":"boolean"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["id"],"additionalProperties":false,"properties":{"id":{"type":"string"},"organisationId":{"type":"string"},"cakeTypeId":{"type":"string"},"status":{"type":"string","enum":["active","completed"]},"totalSlices":{"type":"integer","format":"int64","description":"Slice count"},"userSlices":{"type":"object","additionalProperties":{"type":"integer"}},"createdAt":{"type":"integer","format":"int64","description":"Unix milliseconds"},"completedAt":{"type":"integer","format":"int64","description":"Unix milliseconds"},"dueDate":{"type":"string"},"winnerUserId":{"type":"string"},"winnerUserIds":{"type":"array","items":{"type":"string"}},"isPurchased":{"type":"boolean"},"purchasedAt":{"type":"integer","format":"int64","description":"Unix milliseconds"}}}}}}}},"400":{"description":"Invalid body, date, member or idempotency key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing cakes:write","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Cake or meeting type not found in this organisation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Lifecycle, slice limit, active cake or idempotency conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal error; retry with the same idempotency key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"get_cakes","summary":"Active and completed cakes, slice totals, assignments, and purchase status.","description":"Requires scope cakes:read. Organisation is determined by the key. Unknown or repeated parameters return 400.","parameters":[{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"in":"query","name":"after","description":"Previous nextCursor. Results ordered by document ID ascending; not a snapshot.","schema":{"type":"string","minLength":1,"maxLength":128,"pattern":"^[A-Za-z0-9_-]+$"}}],"responses":{"200":{"description":"Organisation data","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per fixed minute"},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining"},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Window reset time in Unix seconds"}},"content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"type":"object","required":["id"],"additionalProperties":false,"properties":{"id":{"type":"string"},"organisationId":{"type":"string"},"cakeTypeId":{"type":"string"},"status":{"type":"string","enum":["active","completed"]},"totalSlices":{"type":"integer","format":"int64","description":"Slice count"},"userSlices":{"type":"object","additionalProperties":{"type":"integer"}},"createdAt":{"type":"integer","format":"int64","description":"Unix milliseconds"},"completedAt":{"type":"integer","format":"int64","description":"Unix milliseconds"},"dueDate":{"type":"string"},"winnerUserId":{"type":"string"},"winnerUserIds":{"type":"array","items":{"type":"string"}},"isPurchased":{"type":"boolean"},"purchasedAt":{"type":"integer","format":"int64","description":"Unix milliseconds"}}}},"pagination":{"type":"object","required":["limit","hasMore","nextCursor"],"properties":{"limit":{"type":"integer"},"hasMore":{"type":"boolean"},"nextCursor":{"type":"string","nullable":true}}}}}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, expired, or revoked key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"Unsupported method; framework response may not be JSON."},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds before retrying"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/cake-types":{"get":{"operationId":"get_cake_types","summary":"Meeting types configured for the organisation.","description":"Requires scope cake-types:read. Organisation is determined by the key. Unknown or repeated parameters return 400.","parameters":[{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"in":"query","name":"after","description":"Previous nextCursor. Results ordered by document ID ascending; not a snapshot.","schema":{"type":"string","minLength":1,"maxLength":128,"pattern":"^[A-Za-z0-9_-]+$"}}],"responses":{"200":{"description":"Organisation data","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per fixed minute"},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining"},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Window reset time in Unix seconds"}},"content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"type":"object","required":["id"],"additionalProperties":false,"properties":{"id":{"type":"string"},"organisationId":{"type":"string"},"name":{"type":"string"},"isActive":{"type":"boolean"}}}},"pagination":{"type":"object","required":["limit","hasMore","nextCursor"],"properties":{"limit":{"type":"integer"},"hasMore":{"type":"boolean"},"nextCursor":{"type":"string","nullable":true}}}}}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, expired, or revoked key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"Unsupported method; framework response may not be JSON."},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds before retrying"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/members":{"get":{"operationId":"get_members","summary":"Member names, emails, user IDs, roles, and rotation status. Includes personal data.","description":"Requires scope members:read. Organisation is determined by the key. Unknown or repeated parameters return 400.","parameters":[{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"in":"query","name":"after","description":"Previous nextCursor. Results ordered by document ID ascending; not a snapshot.","schema":{"type":"string","minLength":1,"maxLength":128,"pattern":"^[A-Za-z0-9_-]+$"}}],"responses":{"200":{"description":"Organisation data","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per fixed minute"},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining"},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Window reset time in Unix seconds"}},"content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"type":"object","required":["id"],"additionalProperties":false,"properties":{"id":{"type":"string"},"organisationId":{"type":"string"},"authUid":{"type":"string"},"displayName":{"type":"string"},"email":{"type":"string"},"role":{"type":"string","enum":["owner","admin","member"]},"isActive":{"type":"boolean"},"joinedAt":{"type":"integer","format":"int64","description":"Unix milliseconds"}}}},"pagination":{"type":"object","required":["limit","hasMore","nextCursor"],"properties":{"limit":{"type":"integer"},"hasMore":{"type":"boolean"},"nextCursor":{"type":"string","nullable":true}}}}}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, expired, or revoked key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"Unsupported method; framework response may not be JSON."},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds before retrying"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/activities":{"get":{"operationId":"get_activities","summary":"Slice activity, including cake IDs, user IDs, timestamps, and reasons.","description":"Requires scope activities:read. Organisation is determined by the key. Unknown or repeated parameters return 400.","parameters":[{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"in":"query","name":"after","description":"Previous nextCursor. Results ordered by document ID ascending; not a snapshot.","schema":{"type":"string","minLength":1,"maxLength":128,"pattern":"^[A-Za-z0-9_-]+$"}}],"responses":{"200":{"description":"Organisation data","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per fixed minute"},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining"},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Window reset time in Unix seconds"}},"content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"type":"object","required":["id"],"additionalProperties":false,"properties":{"id":{"type":"string"},"organisationId":{"type":"string"},"cakeId":{"type":"string"},"userId":{"type":"string"},"timestamp":{"type":"integer","format":"int64","description":"Unix milliseconds"},"reason":{"type":"string"}}}},"pagination":{"type":"object","required":["limit","hasMore","nextCursor"],"properties":{"limit":{"type":"integer"},"hasMore":{"type":"boolean"},"nextCursor":{"type":"string","nullable":true}}}}}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, expired, or revoked key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"Unsupported method; framework response may not be JSON."},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds before retrying"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/cakes/{cakeId}":{"patch":{"operationId":"updateCake","summary":"Set the scheduled purchase date or winners","description":"Requires cakes:write. Organisation comes from the key. Every write requires an Idempotency-Key (8–128 letters, digits, underscores or hyphens), unique per organisation. Retry with the same key and body; different payloads return 409. Receipts are retained indefinitely. No query parameters. Finalization requires a due date and uses explicit winners, previously assigned winners, or all members tied for most slices. Finalization can happen before eight slices. Slice requests apply in full or fail; eight slices do not auto-finalize. Completed cakes reject slices; purchased cakes reject PATCH. Finalization returns nextCakeId.","parameters":[{"in":"header","name":"Idempotency-Key","required":true,"schema":{"type":"string","minLength":8,"maxLength":128,"pattern":"^[A-Za-z0-9_-]+$"}},{"in":"path","name":"cakeId","required":true,"schema":{"type":"string","minLength":1,"maxLength":128,"pattern":"^[A-Za-z0-9_-]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"minProperties":1,"required":[],"properties":{"dueDate":{"type":"string","format":"date","description":"Scheduled purchase date, YYYY-MM-DD. Returned as midnight UTC ISO timestamp."},"winnerUserIds":{"type":"array","items":{"type":"string","minLength":1,"maxLength":128,"pattern":"^[A-Za-z0-9_-]+$"},"minItems":1,"maxItems":8,"uniqueItems":true}}}}}},"responses":{"200":{"description":"Write succeeded (or original response replayed)","headers":{"Idempotency-Replayed":{"schema":{"type":"boolean"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["id"],"additionalProperties":false,"properties":{"id":{"type":"string"},"organisationId":{"type":"string"},"cakeTypeId":{"type":"string"},"status":{"type":"string","enum":["active","completed"]},"totalSlices":{"type":"integer","format":"int64","description":"Slice count"},"userSlices":{"type":"object","additionalProperties":{"type":"integer"}},"createdAt":{"type":"integer","format":"int64","description":"Unix milliseconds"},"completedAt":{"type":"integer","format":"int64","description":"Unix milliseconds"},"dueDate":{"type":"string"},"winnerUserId":{"type":"string"},"winnerUserIds":{"type":"array","items":{"type":"string"}},"isPurchased":{"type":"boolean"},"purchasedAt":{"type":"integer","format":"int64","description":"Unix milliseconds"}}}}}}}},"400":{"description":"Invalid body, date, member or idempotency key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing cakes:write","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Cake or meeting type not found in this organisation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Lifecycle, slice limit, active cake or idempotency conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal error; retry with the same idempotency key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/cakes/{cakeId}/slices":{"post":{"operationId":"slicesCake","summary":"Add one slice per user","description":"Requires cakes:write. Organisation comes from the key. Every write requires an Idempotency-Key (8–128 letters, digits, underscores or hyphens), unique per organisation. Retry with the same key and body; different payloads return 409. Receipts are retained indefinitely. No query parameters. Finalization requires a due date and uses explicit winners, previously assigned winners, or all members tied for most slices. Finalization can happen before eight slices. Slice requests apply in full or fail; eight slices do not auto-finalize. Completed cakes reject slices; purchased cakes reject PATCH. Finalization returns nextCakeId.","parameters":[{"in":"header","name":"Idempotency-Key","required":true,"schema":{"type":"string","minLength":8,"maxLength":128,"pattern":"^[A-Za-z0-9_-]+$"}},{"in":"path","name":"cakeId","required":true,"schema":{"type":"string","minLength":1,"maxLength":128,"pattern":"^[A-Za-z0-9_-]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"minProperties":1,"required":["userIds"],"properties":{"userIds":{"type":"array","items":{"type":"string","minLength":1,"maxLength":128,"pattern":"^[A-Za-z0-9_-]+$"},"minItems":1,"maxItems":8,"uniqueItems":true},"reason":{"type":"string","maxLength":500}}}}}},"responses":{"200":{"description":"Write succeeded (or original response replayed)","headers":{"Idempotency-Replayed":{"schema":{"type":"boolean"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["id"],"additionalProperties":false,"properties":{"id":{"type":"string"},"organisationId":{"type":"string"},"cakeTypeId":{"type":"string"},"status":{"type":"string","enum":["active","completed"]},"totalSlices":{"type":"integer","format":"int64","description":"Slice count"},"userSlices":{"type":"object","additionalProperties":{"type":"integer"}},"createdAt":{"type":"integer","format":"int64","description":"Unix milliseconds"},"completedAt":{"type":"integer","format":"int64","description":"Unix milliseconds"},"dueDate":{"type":"string"},"winnerUserId":{"type":"string"},"winnerUserIds":{"type":"array","items":{"type":"string"}},"isPurchased":{"type":"boolean"},"purchasedAt":{"type":"integer","format":"int64","description":"Unix milliseconds"}}}}}}}},"400":{"description":"Invalid body, date, member or idempotency key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing cakes:write","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Cake or meeting type not found in this organisation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Lifecycle, slice limit, active cake or idempotency conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal error; retry with the same idempotency key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/cakes/{cakeId}/complete":{"post":{"operationId":"completeCake","summary":"Finalize a cake and start the next tracker","description":"Requires cakes:write. Organisation comes from the key. Every write requires an Idempotency-Key (8–128 letters, digits, underscores or hyphens), unique per organisation. Retry with the same key and body; different payloads return 409. Receipts are retained indefinitely. No query parameters. Finalization requires a due date and uses explicit winners, previously assigned winners, or all members tied for most slices. Finalization can happen before eight slices. Slice requests apply in full or fail; eight slices do not auto-finalize. Completed cakes reject slices; purchased cakes reject PATCH. Finalization returns nextCakeId.","parameters":[{"in":"header","name":"Idempotency-Key","required":true,"schema":{"type":"string","minLength":8,"maxLength":128,"pattern":"^[A-Za-z0-9_-]+$"}},{"in":"path","name":"cakeId","required":true,"schema":{"type":"string","minLength":1,"maxLength":128,"pattern":"^[A-Za-z0-9_-]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"minProperties":1,"required":["dueDate"],"properties":{"dueDate":{"type":"string","format":"date","description":"Scheduled purchase date, YYYY-MM-DD. Returned as midnight UTC ISO timestamp."},"winnerUserIds":{"type":"array","items":{"type":"string","minLength":1,"maxLength":128,"pattern":"^[A-Za-z0-9_-]+$"},"minItems":1,"maxItems":8,"uniqueItems":true}}}}}},"responses":{"200":{"description":"Write succeeded (or original response replayed)","headers":{"Idempotency-Replayed":{"schema":{"type":"boolean"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds"}},"content":{"application/json":{"schema":{"type":"object","required":["data","nextCakeId"],"properties":{"data":{"type":"object","required":["id"],"additionalProperties":false,"properties":{"id":{"type":"string"},"organisationId":{"type":"string"},"cakeTypeId":{"type":"string"},"status":{"type":"string","enum":["active","completed"]},"totalSlices":{"type":"integer","format":"int64","description":"Slice count"},"userSlices":{"type":"object","additionalProperties":{"type":"integer"}},"createdAt":{"type":"integer","format":"int64","description":"Unix milliseconds"},"completedAt":{"type":"integer","format":"int64","description":"Unix milliseconds"},"dueDate":{"type":"string"},"winnerUserId":{"type":"string"},"winnerUserIds":{"type":"array","items":{"type":"string"}},"isPurchased":{"type":"boolean"},"purchasedAt":{"type":"integer","format":"int64","description":"Unix milliseconds"}}},"nextCakeId":{"type":"string"}}}}}},"400":{"description":"Invalid body, date, member or idempotency key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing cakes:write","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Cake or meeting type not found in this organisation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Lifecycle, slice limit, active cake or idempotency conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal error; retry with the same idempotency key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"ApiKey":{"type":"http","scheme":"bearer","bearerFormat":"sos_<key-id>_<secret>"}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}}