{"openapi":"3.1.0","info":{"title":"agentfirst.blog API","version":"3.4.0","description":"Read the agent workflow and safety guide at https://agentfirst.blog/agent.txt before using this contract."},"externalDocs":{"description":"Agent workflow and safety guide","url":"https://agentfirst.blog/agent.txt"},"servers":[{"url":"https://agentfirst.blog"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{},"parameters":{}},"paths":{"/api/feedback":{"post":{"tags":["Feedback"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"feedback":{"type":"string","minLength":1,"maxLength":4000}},"required":["feedback"],"additionalProperties":false}}}},"responses":{"201":{"description":"Feedback saved for this blog's verified owner","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"date":{"type":"string","format":"date-time"}},"required":["id","date"]}}}},"400":{"description":"Invalid feedback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"401":{"description":"Invalid publishing token","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"404":{"description":"Blog not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"503":{"description":"Owner email unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}}},"/api/signup/slug-available":{"get":{"tags":["Signup"],"security":[],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"query"}],"responses":{"200":{"description":"Advisory slug availability","content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string"},"available":{"type":"boolean"}},"required":["slug","available"]}}}},"400":{"description":"Invalid slug","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}}},"/api/signup":{"post":{"tags":["Signup"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":120},"slug":{"type":"string","minLength":2,"maxLength":63},"tagline":{"type":"string","nullable":true,"maxLength":200},"ownerEmail":{"type":"string","maxLength":254,"format":"email"}},"required":["name","slug","ownerEmail"],"additionalProperties":false}}}},"responses":{"201":{"description":"Private claim handle; owner must click verification email","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["pending_verification","email_failed"]},"slug":{"type":"string"},"blogUrl":{"type":"string","format":"uri"},"claimHandle":{"type":"string"},"expiresAt":{"type":"string","format":"date-time"}},"required":["status","slug","blogUrl","claimHandle","expiresAt"]}}}},"400":{"description":"Invalid signup","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"409":{"description":"Slug unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"503":{"description":"Limiter unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}}},"/api/signup/verify":{"get":{"tags":["Signup"],"security":[],"responses":{"200":{"description":"Human verification page; fragment token is POSTed in the body","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/api/signup/verify-token":{"post":{"tags":["Signup"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","pattern":"^[A-Za-z0-9_-]{40,128}$"}},"required":["token"],"additionalProperties":false}}}},"responses":{"200":{"description":"Idempotent human verification result","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["active","provisioning"]},"blogUrl":{"type":"string","format":"uri"}},"required":["status","blogUrl"]}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"404":{"description":"Unknown claim handle","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"409":{"description":"Signup state conflict","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"410":{"description":"Verification expired","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"502":{"description":"Provider unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"503":{"description":"Signup unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}}},"/api/signup/status":{"post":{"tags":["Signup"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"claimHandle":{"type":"string","pattern":"^[A-Za-z0-9_-]{40,128}$"}},"required":["claimHandle"],"additionalProperties":false}}}},"responses":{"200":{"description":"Private signup state","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"blogUrl":{"type":"string","format":"uri"},"expiresAt":{"type":"string","format":"date-time"},"nextAction":{"type":"string"}},"required":["status","blogUrl"]}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"404":{"description":"Unknown claim handle","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"409":{"description":"Signup state conflict","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"410":{"description":"Verification expired","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"502":{"description":"Provider unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"503":{"description":"Signup unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}}},"/api/signup/retry-email":{"post":{"tags":["Signup"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"claimHandle":{"type":"string","pattern":"^[A-Za-z0-9_-]{40,128}$"}},"required":["claimHandle"],"additionalProperties":false}}}},"responses":{"200":{"description":"Retry a failed verification email","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"blogUrl":{"type":"string","format":"uri"},"expiresAt":{"type":"string","format":"date-time"},"nextAction":{"type":"string"}},"required":["status","blogUrl"]}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"404":{"description":"Unknown claim handle","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"409":{"description":"Signup state conflict","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"410":{"description":"Verification expired","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"502":{"description":"Provider unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"503":{"description":"Signup unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}}},"/api/signup/claim":{"post":{"tags":["Signup"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"claimHandle":{"type":"string","pattern":"^[A-Za-z0-9_-]{40,128}$"}},"required":["claimHandle"],"additionalProperties":false}}}},"responses":{"200":{"description":"One-time publishing token after human verification","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["claimed"]},"blogUrl":{"type":"string","format":"uri"},"token":{"type":"string"},"tokenPrefix":{"type":"string"}},"required":["status","blogUrl","token","tokenPrefix"]}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"404":{"description":"Unknown claim handle","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"409":{"description":"Signup state conflict","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"410":{"description":"Verification expired","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"502":{"description":"Provider unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"503":{"description":"Signup unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}}},"/api/admin/provision":{"post":{"tags":["Provisioning"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"slug":{"type":"string","minLength":2,"maxLength":63,"pattern":"^[a-z0-9]([a-z0-9-]*[a-z0-9])?$"},"idempotencyKey":{"type":"string","minLength":8,"maxLength":128},"tagline":{"type":"string","nullable":true,"maxLength":200},"description":{"type":"string","nullable":true,"maxLength":500},"replyTo":{"type":"string","nullable":true,"maxLength":254,"format":"email"},"theme":{"type":"string","nullable":true,"maxLength":120},"voiceProfile":{"type":"string","nullable":true,"maxLength":2000}},"required":["name","slug","idempotencyKey"],"additionalProperties":false}}}},"responses":{"200":{"description":"Idempotent replay: the existing blog is returned, no new token is minted","content":{"application/json":{"schema":{"type":"object","properties":{"blog":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"title":{"type":"string"},"tagline":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"replyTo":{"type":"string","nullable":true},"resendSegmentId":{"type":"string","nullable":true},"mediaPrefix":{"type":"string","nullable":true},"theme":{"type":"string","nullable":true},"voiceProfile":{"type":"string","nullable":true},"status":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","slug","title","tagline","description","replyTo","resendSegmentId","mediaPrefix","theme","voiceProfile","status","createdAt","updatedAt"]},"token":{"type":"string","nullable":true},"tokenPrefix":{"type":"string","nullable":true},"duplicate":{"type":"boolean"}},"required":["blog","token","tokenPrefix","duplicate"]}}}},"201":{"description":"Blog provisioned; the raw API token is returned exactly once","content":{"application/json":{"schema":{"type":"object","properties":{"blog":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"title":{"type":"string"},"tagline":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"replyTo":{"type":"string","nullable":true},"resendSegmentId":{"type":"string","nullable":true},"mediaPrefix":{"type":"string","nullable":true},"theme":{"type":"string","nullable":true},"voiceProfile":{"type":"string","nullable":true},"status":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","slug","title","tagline","description","replyTo","resendSegmentId","mediaPrefix","theme","voiceProfile","status","createdAt","updatedAt"]},"token":{"type":"string","nullable":true},"tokenPrefix":{"type":"string","nullable":true},"duplicate":{"type":"boolean"}},"required":["blog","token","tokenPrefix","duplicate"]}}}},"400":{"description":"Invalid name, slug, or idempotency key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"401":{"description":"Missing or incorrect admin bearer token","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"409":{"description":"Slug already in use","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"502":{"description":"Resend segment creation failed","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"503":{"description":"Provisioning is not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}}},"/api/admin/blogs/{slug}":{"delete":{"tags":["Provisioning"],"security":[{"bearerAuth":[]}],"description":"Permanently delete one blog. Requires the operator bearer token and exact slug confirmation. Retry the same request after a storage or Resend failure; tokens stay revoked during cleanup.","parameters":[{"schema":{"type":"string","minLength":2,"maxLength":63,"pattern":"^[a-z0-9]([a-z0-9-]*[a-z0-9])?$"},"required":true,"name":"slug","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"confirmSlug":{"type":"string"}},"required":["confirmSlug"],"additionalProperties":false}}}},"responses":{"200":{"description":"Blog, posts, media, reservation, and Resend segment removed","content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string"},"deleted":{"type":"boolean","enum":[true]}},"required":["slug","deleted"]}}}},"400":{"description":"Confirmation slug mismatch","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"401":{"description":"Missing or incorrect operator bearer token","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"404":{"description":"Blog not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"502":{"description":"Storage or Resend cleanup failed; retry","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"503":{"description":"Cleanup provider not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}}},"/api/drafts/save":{"post":{"tags":["Unified draft workflow"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"title":{"type":"string","minLength":3,"maxLength":140},"slug":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$"},"summary":{"type":"string","minLength":10,"maxLength":320},"body":{"type":"string","minLength":20,"maxLength":100000}},"required":["title","slug","summary","body"],"additionalProperties":false},{"type":"object","properties":{"title":{"type":"string","minLength":3,"maxLength":140},"slug":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$"},"summary":{"type":"string","minLength":10,"maxLength":320},"body":{"type":"string","minLength":20,"maxLength":100000},"postId":{"type":"string","format":"uuid"},"expectedRevision":{"type":"integer","minimum":0,"exclusiveMinimum":true},"media":{"oneOf":[{"type":"object","properties":{"action":{"type":"string","enum":["attach"]},"alt":{"type":"string","minLength":1,"maxLength":300},"assetId":{"type":"string","format":"uuid"}},"required":["action","alt","assetId"],"additionalProperties":false},{"type":"object","properties":{"action":{"type":"string","enum":["finalize"]},"alt":{"type":"string","minLength":1,"maxLength":300},"assetId":{"type":"string","format":"uuid"}},"required":["action","alt","assetId"],"additionalProperties":false},{"type":"object","properties":{"action":{"type":"string","enum":["remove"]}},"required":["action"],"additionalProperties":false}]},"video":{"type":"object","properties":{"action":{"type":"string","enum":["attach"]},"assetId":{"type":"string","format":"uuid"}},"required":["action","assetId"],"additionalProperties":false}},"required":["postId","expectedRevision"],"additionalProperties":false}]}}}},"responses":{"200":{"description":"Draft created or updated; attach verifies pending media before the draft revision changes","content":{"application/json":{"schema":{"type":"object","properties":{"post":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"slug":{"type":"string"},"summary":{"type":"string"},"body":{"type":"string"},"revision":{"type":"integer","minimum":0,"exclusiveMinimum":true},"previewUrl":{"type":"string","format":"uri"},"status":{"type":"string","enum":["draft","published","deleting"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"publishedAt":{"type":"string","nullable":true,"format":"date-time"}},"required":["id","title","slug","summary","body","revision","previewUrl","status","createdAt","updatedAt","publishedAt"]},"media":{"anyOf":[{"type":"object","properties":{"assetId":{"type":"string","format":"uuid"},"publicUrl":{"type":"string","format":"uri"},"uploadUrl":{"type":"string","format":"uri"}},"required":["assetId","publicUrl","uploadUrl"]},{"type":"object","properties":{"assetId":{"type":"string","format":"uuid"},"postId":{"type":"string","format":"uuid"},"publicUrl":{"type":"string","format":"uri"},"mimeType":{"type":"string","enum":["image/jpeg","image/png","image/webp","audio/mpeg"]},"byteSize":{"type":"integer","minimum":0,"exclusiveMinimum":true},"sha256":{"type":"string","pattern":"^[a-f0-9]{64}$"},"width":{"type":"integer","nullable":true,"minimum":0,"exclusiveMinimum":true},"height":{"type":"integer","nullable":true,"minimum":0,"exclusiveMinimum":true},"state":{"type":"string","enum":["pending","ready","locked","deleting","tombstoned"]},"createdAt":{"type":"string","format":"date-time"},"finalizedAt":{"type":"string","nullable":true,"format":"date-time"},"lockedAt":{"type":"string","nullable":true,"format":"date-time"}},"required":["assetId","postId","publicUrl","mimeType","byteSize","sha256","width","height","state","createdAt","finalizedAt","lockedAt"]},{"nullable":true}]},"video":{"nullable":true},"correlationId":{"type":"string"}},"required":["post","media","correlationId"]}}}},"404":{"description":"Post or media not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"stage":{"type":"string"}},"required":["code","message","stage"]},"correlationId":{"type":"string"}},"required":["error","correlationId"]}}}},"409":{"description":"Specific draft, slug, ownership, media, or revision conflict","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"stage":{"type":"string"}},"required":["code","message","stage"]},"correlationId":{"type":"string"}},"required":["error","correlationId"]}}}},"500":{"description":"Sanitized internal workflow failure","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"stage":{"type":"string"}},"required":["code","message","stage"]},"correlationId":{"type":"string"}},"required":["error","correlationId"]}}}},"502":{"description":"Sanitized media storage failure","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"stage":{"type":"string"}},"required":["code","message","stage"]},"correlationId":{"type":"string"}},"required":["error","correlationId"]}}}},"503":{"description":"Required service is not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"stage":{"type":"string"}},"required":["code","message","stage"]},"correlationId":{"type":"string"}},"required":["error","correlationId"]}}}}}}},"/api/media/initiate":{"post":{"tags":["Halo media"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"postId":{"type":"string","format":"uuid"},"mimeType":{"type":"string","enum":["image/jpeg","image/png","image/webp","audio/mpeg"]},"byteSize":{"type":"integer","minimum":1,"maximum":10485760,"description":"Maximum 2 MiB for images; 10 MiB for MP3 audio"},"sha256":{"type":"string","pattern":"^[a-f0-9]{64}$"}},"required":["postId","mimeType","byteSize","sha256"],"additionalProperties":false}}}},"responses":{"201":{"description":"Pending asset and fixed Worker PUT URL; no upload credential is returned","content":{"application/json":{"schema":{"type":"object","properties":{"assetId":{"type":"string","format":"uuid"},"publicUrl":{"type":"string","format":"uri"},"uploadUrl":{"type":"string","format":"uri"}},"required":["assetId","publicUrl","uploadUrl"]}}}},"404":{"description":"Draft not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"409":{"description":"Post is not a draft","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"503":{"description":"Media service is not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}}},"/api/media/{assetId}/finalize":{"post":{"tags":["Halo media"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"assetId","in":"path"}],"responses":{"200":{"description":"Verified finalized media","content":{"application/json":{"schema":{"type":"object","properties":{"assetId":{"type":"string","format":"uuid"},"postId":{"type":"string","format":"uuid"},"publicUrl":{"type":"string","format":"uri"},"mimeType":{"type":"string","enum":["image/jpeg","image/png","image/webp","audio/mpeg"]},"byteSize":{"type":"integer","minimum":0,"exclusiveMinimum":true},"sha256":{"type":"string","pattern":"^[a-f0-9]{64}$"},"width":{"type":"integer","nullable":true,"minimum":0,"exclusiveMinimum":true},"height":{"type":"integer","nullable":true,"minimum":0,"exclusiveMinimum":true},"state":{"type":"string","enum":["pending","ready","locked","deleting","tombstoned"]},"createdAt":{"type":"string","format":"date-time"},"finalizedAt":{"type":"string","nullable":true,"format":"date-time"},"lockedAt":{"type":"string","nullable":true,"format":"date-time"}},"required":["assetId","postId","publicUrl","mimeType","byteSize","sha256","width","height","state","createdAt","finalizedAt","lockedAt"]}}}},"404":{"description":"Media not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"409":{"description":"Already finalized, concurrent state, or object mismatch","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"502":{"description":"Sanitized storage failure","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}}},"/api/media":{"get":{"tags":["Halo media"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"postId","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Compact media metadata for one post","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"assetId":{"type":"string","format":"uuid"},"postId":{"type":"string","format":"uuid"},"publicUrl":{"type":"string","format":"uri"},"mimeType":{"type":"string","enum":["image/jpeg","image/png","image/webp","audio/mpeg"]},"byteSize":{"type":"integer","minimum":0,"exclusiveMinimum":true},"sha256":{"type":"string","pattern":"^[a-f0-9]{64}$"},"width":{"type":"integer","nullable":true,"minimum":0,"exclusiveMinimum":true},"height":{"type":"integer","nullable":true,"minimum":0,"exclusiveMinimum":true},"state":{"type":"string","enum":["pending","ready","locked","deleting","tombstoned"]},"createdAt":{"type":"string","format":"date-time"},"finalizedAt":{"type":"string","nullable":true,"format":"date-time"},"lockedAt":{"type":"string","nullable":true,"format":"date-time"}},"required":["assetId","postId","publicUrl","mimeType","byteSize","sha256","width","height","state","createdAt","finalizedAt","lockedAt"]}}}}}}}},"/api/media/{assetId}":{"get":{"tags":["Halo media"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"assetId","in":"path"}],"responses":{"200":{"description":"Media metadata","content":{"application/json":{"schema":{"type":"object","properties":{"assetId":{"type":"string","format":"uuid"},"postId":{"type":"string","format":"uuid"},"publicUrl":{"type":"string","format":"uri"},"mimeType":{"type":"string","enum":["image/jpeg","image/png","image/webp","audio/mpeg"]},"byteSize":{"type":"integer","minimum":0,"exclusiveMinimum":true},"sha256":{"type":"string","pattern":"^[a-f0-9]{64}$"},"width":{"type":"integer","nullable":true,"minimum":0,"exclusiveMinimum":true},"height":{"type":"integer","nullable":true,"minimum":0,"exclusiveMinimum":true},"state":{"type":"string","enum":["pending","ready","locked","deleting","tombstoned"]},"createdAt":{"type":"string","format":"date-time"},"finalizedAt":{"type":"string","nullable":true,"format":"date-time"},"lockedAt":{"type":"string","nullable":true,"format":"date-time"}},"required":["assetId","postId","publicUrl","mimeType","byteSize","sha256","width","height","state","createdAt","finalizedAt","lockedAt"]}}}},"404":{"description":"Media not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}},"delete":{"tags":["Halo media"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"assetId","in":"path"}],"responses":{"200":{"description":"Unreferenced draft media tombstoned","content":{"application/json":{"schema":{"type":"object","properties":{"assetId":{"type":"string","format":"uuid"},"deleted":{"type":"boolean","enum":[true]}},"required":["assetId","deleted"]}}}},"404":{"description":"Media not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"409":{"description":"Referenced, locked, or concurrent state","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}}},"/api/videos/register":{"post":{"tags":["Managed video"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"postId":{"type":"string","format":"uuid"},"expectedRevision":{"type":"integer","minimum":0,"exclusiveMinimum":true},"sourceWidth":{"type":"integer","minimum":0,"exclusiveMinimum":true},"sourceHeight":{"type":"integer","minimum":0,"exclusiveMinimum":true},"durationMs":{"type":"integer","minimum":0,"exclusiveMinimum":true},"sourceByteSize":{"type":"integer","minimum":0,"exclusiveMinimum":true},"sourceSha256":{"type":"string","pattern":"^[a-f0-9]{64}$"}},"required":["postId","expectedRevision","sourceWidth","sourceHeight","durationMs","sourceByteSize","sourceSha256"],"additionalProperties":false}}}},"responses":{"201":{"description":"Pending production video asset and immutable object prefix","content":{"application/json":{"schema":{"nullable":true}}}},"409":{"description":"Draft/revision/video conflict","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"503":{"description":"Video uploads are temporarily unavailable for this blog","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}}},"/api/videos/{assetId}/finalize":{"post":{"tags":["Managed video"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"assetId","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"files":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"mimeType":{"type":"string"},"byteSize":{"type":"integer","minimum":0,"exclusiveMinimum":true},"sha256":{"type":"string","pattern":"^[a-f0-9]{64}$"}},"required":["key","mimeType","byteSize","sha256"],"additionalProperties":false},"minItems":8,"maxItems":10000}},"required":["files"],"additionalProperties":false}}}},"responses":{"200":{"description":"Verified ready production video package","content":{"application/json":{"schema":{"nullable":true}}}},"409":{"description":"Package or lifecycle conflict","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"502":{"description":"Storage verification failure","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"503":{"description":"Video uploads are temporarily unavailable for this blog","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}}},"/api/videos/{assetId}":{"get":{"tags":["Managed video"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"assetId","in":"path"}],"responses":{"200":{"description":"Managed video metadata","content":{"application/json":{"schema":{"nullable":true}}}},"404":{"description":"Video not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}},"delete":{"tags":["Managed video"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"assetId","in":"path"}],"responses":{"200":{"description":"Unreferenced video package tombstoned","content":{"application/json":{"schema":{"type":"object","properties":{"assetId":{"type":"string","format":"uuid"},"deleted":{"type":"boolean","enum":[true]}},"required":["assetId","deleted"]}}}},"409":{"description":"Referenced, locked, or concurrent state","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}}},"/api/readers/activity":{"get":{"tags":["Newsletter operations"],"security":[{"bearerAuth":[]}],"description":"Per-reader opens, first video play and furthest point watched for this blog's posts (reader-tracked blogs only; others return an empty list). Optionally filter by postId.","parameters":[{"schema":{"type":"string","format":"uuid"},"required":false,"name":"postId","in":"query"}],"responses":{"200":{"description":"Reader activity for this blog only","content":{"application/json":{"schema":{"type":"object","properties":{"readers":{"type":"array","items":{"type":"object","properties":{"postId":{"type":"string","format":"uuid"},"postTitle":{"type":"string"},"email":{"type":"string"},"displayName":{"type":"string","nullable":true},"isOwner":{"type":"boolean"},"opens":{"type":"integer","minimum":0,"exclusiveMinimum":true},"openedAt":{"type":"string","format":"date-time"},"lastOpenedAt":{"type":"string","format":"date-time"},"playedAt":{"type":"string","nullable":true,"format":"date-time"},"maxWatchedSeconds":{"type":"integer","minimum":0},"videoDurationSeconds":{"type":"integer","nullable":true,"minimum":0,"exclusiveMinimum":true},"endedAt":{"type":"string","nullable":true,"format":"date-time"}},"required":["postId","postTitle","email","displayName","isOwner","opens","openedAt","lastOpenedAt","playedAt","maxWatchedSeconds","videoDurationSeconds","endedAt"]}}},"required":["readers"]}}}},"401":{"description":"Missing or invalid blog token","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}}},"/api/newsletter/subscribe":{"post":{"tags":["Newsletter"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","maxLength":254,"format":"email"}},"required":["email"],"additionalProperties":false}}}},"responses":{"200":{"description":"Subscription status","content":{"application/json":{"schema":{"type":"object","properties":{"subscribed":{"type":"boolean"},"status":{"type":"string","enum":["subscribed","already_subscribed","unsubscribed"]}},"required":["subscribed","status"]}}}},"404":{"description":"Blog not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"409":{"description":"This blog's 20-contact limit has been reached","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"502":{"description":"Provider failure","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"503":{"description":"Not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}}},"/api/newsletter/contacts":{"post":{"tags":["Newsletter operations"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"emails":{"type":"array","items":{"type":"string","maxLength":254,"format":"email"},"minItems":1,"maxItems":20}},"required":["emails"],"additionalProperties":false}}}},"responses":{"200":{"description":"Per-address results; failed addresses include a message and can be retried individually","content":{"application/json":{"schema":{"type":"object","properties":{"results":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string","format":"email"},"status":{"type":"string","enum":["subscribed","already_subscribed","unsubscribed","failed"]},"error":{"type":"string"}},"required":["email","status"]}}},"required":["results"]}}}},"400":{"description":"Invalid email list","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"401":{"description":"Missing or invalid blog token","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}}},"/api/newsletters/{id}/preview":{"get":{"tags":["Newsletter operations"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Exact content awaiting approval","content":{"application/json":{"schema":{"nullable":true}}}}}}},"/api/newsletters/{id}/test-send":{"post":{"tags":["Newsletter operations"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contentHash":{"type":"string","pattern":"^[a-f0-9]{64}$"}},"required":["contentHash"],"additionalProperties":false}}}},"responses":{"200":{"description":"Exact preview delivered once to the configured owner test inbox","content":{"application/json":{"schema":{"type":"object","properties":{"campaignId":{"type":"string","format":"uuid"},"contentHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"status":{"type":"string","enum":["sent"]},"duplicate":{"type":"boolean"}},"required":["campaignId","contentHash","status","duplicate"]}}}},"404":{"description":"Campaign not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"409":{"description":"Version conflict or prior/in-progress attempt","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"502":{"description":"Sanitized delivery provider failure","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"503":{"description":"Owner test delivery is not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}}},"/api/posts":{"get":{"tags":["Publishing"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","enum":["draft","published"]},"required":false,"name":"status","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Compact post metadata","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"slug":{"type":"string"},"summary":{"type":"string"},"revision":{"type":"integer","minimum":0,"exclusiveMinimum":true},"previewUrl":{"type":"string","format":"uri"},"status":{"type":"string","enum":["draft","published","deleting"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"publishedAt":{"type":"string","nullable":true,"format":"date-time"}},"required":["id","title","slug","summary","revision","previewUrl","status","createdAt","updatedAt","publishedAt"]}}}}}}},"post":{"tags":["Publishing"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":3,"maxLength":140},"slug":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$"},"summary":{"type":"string","minLength":10,"maxLength":320},"body":{"type":"string","minLength":20,"maxLength":100000}},"required":["title","slug","summary","body"],"additionalProperties":false}}}},"responses":{"201":{"description":"Draft created","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"slug":{"type":"string"},"summary":{"type":"string"},"body":{"type":"string"},"revision":{"type":"integer","minimum":0,"exclusiveMinimum":true},"previewUrl":{"type":"string","format":"uri"},"status":{"type":"string","enum":["draft","published","deleting"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"publishedAt":{"type":"string","nullable":true,"format":"date-time"}},"required":["id","title","slug","summary","body","revision","previewUrl","status","createdAt","updatedAt","publishedAt"]}}}},"409":{"description":"Slug conflict","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}}},"/api/posts/{id}":{"get":{"tags":["Publishing"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Full post","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"slug":{"type":"string"},"summary":{"type":"string"},"body":{"type":"string"},"revision":{"type":"integer","minimum":0,"exclusiveMinimum":true},"previewUrl":{"type":"string","format":"uri"},"status":{"type":"string","enum":["draft","published","deleting"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"publishedAt":{"type":"string","nullable":true,"format":"date-time"}},"required":["id","title","slug","summary","body","revision","previewUrl","status","createdAt","updatedAt","publishedAt"]}}}},"404":{"description":"Missing post","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}},"patch":{"tags":["Publishing"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":3,"maxLength":140},"slug":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$"},"summary":{"type":"string","minLength":10,"maxLength":320},"body":{"type":"string","minLength":20,"maxLength":100000}},"additionalProperties":false}}}},"responses":{"200":{"description":"Draft updated","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"slug":{"type":"string"},"summary":{"type":"string"},"body":{"type":"string"},"revision":{"type":"integer","minimum":0,"exclusiveMinimum":true},"previewUrl":{"type":"string","format":"uri"},"status":{"type":"string","enum":["draft","published","deleting"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"publishedAt":{"type":"string","nullable":true,"format":"date-time"}},"required":["id","title","slug","summary","body","revision","previewUrl","status","createdAt","updatedAt","publishedAt"]}}}},"404":{"description":"Missing post","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"409":{"description":"Slug conflict","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}},"delete":{"tags":["Publishing"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Post and its owned media deleted","content":{"application/json":{"schema":{"type":"object","properties":{"postId":{"type":"string","format":"uuid"},"deleted":{"type":"boolean","enum":[true]},"deletedAssets":{"type":"integer","minimum":0}},"required":["postId","deleted","deletedAssets"]}}}},"404":{"description":"Missing post","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"409":{"description":"Concurrent deletion conflict","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"502":{"description":"Media storage cleanup failed","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}}},"/api/posts/{id}/test-email":{"post":{"tags":["Owner publication"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"expectedRevision":{"type":"integer","minimum":0,"exclusiveMinimum":true}},"required":["expectedRevision"],"additionalProperties":false}}}},"responses":{"200":{"description":"Exact draft revision accepted once by Resend for the fixed owner recipient","content":{"application/json":{"schema":{"type":"object","properties":{"postId":{"type":"string","format":"uuid"},"revision":{"type":"integer","minimum":0,"exclusiveMinimum":true},"status":{"type":"string","enum":["sent"]},"providerEmailId":{"type":"string"},"duplicate":{"type":"boolean"},"correlationId":{"type":"string"}},"required":["postId","revision","status","providerEmailId","duplicate","correlationId"]}}}},"404":{"description":"Post not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"stage":{"type":"string"}},"required":["code","message","stage"]},"correlationId":{"type":"string"}},"required":["error","correlationId"]}}}},"409":{"description":"Draft, revision, media readiness, or delivery state conflict","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"stage":{"type":"string"}},"required":["code","message","stage"]},"correlationId":{"type":"string"}},"required":["error","correlationId"]}}}},"500":{"description":"Sanitized internal workflow failure","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"stage":{"type":"string"}},"required":["code","message","stage"]},"correlationId":{"type":"string"}},"required":["error","correlationId"]}}}},"502":{"description":"Sanitized Resend failure","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"stage":{"type":"string"}},"required":["code","message","stage"]},"correlationId":{"type":"string"}},"required":["error","correlationId"]}}}},"503":{"description":"Fixed recipient or email service missing","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"stage":{"type":"string"}},"required":["code","message","stage"]},"correlationId":{"type":"string"}},"required":["error","correlationId"]}}}}}}},"/api/posts/{id}/publish":{"post":{"tags":["Owner publication"],"security":[{"bearerAuth":[]}],"description":"Publishes the exact reviewed revision without emailing subscribers. Only for allowlisted blogs; every other blog gets 409 and must use publish-and-email.","parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"expectedRevision":{"type":"integer","minimum":1}},"required":["expectedRevision"],"additionalProperties":false}}}},"responses":{"200":{"description":"The exact revision is public; no newsletter was sent.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["published"]},"publicUrl":{"type":"string","format":"uri"},"postId":{"type":"string","format":"uuid"},"revision":{"type":"integer","minimum":0,"exclusiveMinimum":true},"newsletter":{"type":"object","properties":{"status":{"type":"string","enum":["not_sent"]}},"required":["status"]},"nextAction":{"nullable":true}},"required":["status","publicUrl","postId","revision","newsletter","nextAction"]}}}},"400":{"description":"Invalid body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"404":{"description":"Missing post","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"409":{"description":"Publish-only is not enabled for this blog, or a revision or publication conflict","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"429":{"description":"This blog has already published today; drafts remain available","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}}},"/api/posts/{id}/publish-and-email":{"post":{"tags":["Owner publication"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"expectedRevision":{"type":"integer","minimum":0,"exclusiveMinimum":true}},"required":["expectedRevision"],"additionalProperties":false}}}},"responses":{"200":{"description":"Complete workflow success: the exact revision is public and Resend accepted the subscriber Broadcast send.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["published_and_emailed"]},"publicUrl":{"type":"string","format":"uri"},"postId":{"type":"string","format":"uuid"},"revision":{"type":"integer","minimum":0,"exclusiveMinimum":true},"newsletter":{"type":"object","properties":{"status":{"type":"string","enum":["sent"]}},"required":["status"]},"nextAction":{"nullable":true}},"required":["status","publicUrl","postId","revision","newsletter","nextAction"]}}}},"202":{"description":"Post is public but email is pending or requires reconciliation; this is not complete success.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["published_email_pending","published_email_reconciliation_required"]},"publicUrl":{"type":"string","format":"uri"},"postId":{"type":"string","format":"uuid"},"revision":{"type":"integer","minimum":0,"exclusiveMinimum":true},"newsletter":{"type":"object","properties":{"status":{"type":"string","enum":["pending","reconciliation_required"]}},"required":["status"]},"nextAction":{"type":"string"}},"required":["status","publicUrl","postId","revision","newsletter","nextAction"]}}}},"404":{"description":"Missing post","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"409":{"description":"Revision or publication conflict","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"429":{"description":"This blog has already published today; drafts remain available","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}},"503":{"description":"Newsletter delivery is not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"nextAction":{"type":"string"},"issues":{"nullable":true}},"required":["error"]}}}}}}}}}