{"openapi":"3.1.0","jsonSchemaDialect":"https://json-schema.org/draft/2020-12/schema","info":{"title":"Surgr REST API","version":"v1","description":"Scoped agent access. Human review is recommended; draft-and-schedule connections can approve their own drafts. Examples are illustrative. Scheduled means queued, not published. Success examples show shapes, not exhaustive response schemas."},"servers":[{"url":"https://surgr.ai/api/v1"}],"tags":[{"name":"Account"},{"name":"Posts"},{"name":"Scheduling"},{"name":"Media"},{"name":"Results"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"A scoped Surgr connection key. Keep it in SURGR_API_KEY."}}},"paths":{"/account":{"get":{"operationId":"get-account","tags":["Account"],"summary":"Read account, workspace, connected accounts and this key’s effective scope.","description":"Permission: Valid scoped key; no action permission required for reads.\n\nConnections are restricted to allowed platforms. X uses the response key x, while platform enums use x_twitter. Subscription plan is workspace-derived.","parameters":[],"responses":{"200":{"description":"Read account, workspace, connected accounts and this key’s effective scope.\n\nIllustrative response shape, not real account data.\n\nConnections are restricted to allowed platforms. X uses the response key x, while platform enums use x_twitter. Subscription plan is workspace-derived.","content":{"application/json":{"example":{"id":"user_example","name":"Example founder","email":"founder@example.invalid","image":null,"timezone":"Asia/Taipei","createdAt":"2030-01-01T00:00:00.000Z","subscriptionStatus":null,"plan":"free","workspace":{"id":"workspace_example"},"connections":{"x":{"username":null,"connectedAt":null}},"agentConnection":{"name":"Example agent","accessMode":"prepare_review","permissions":["draft"],"allowedPlatforms":["x_twitter"]}}}}},"401":{"description":"Missing, invalid, expired or revoked bearer key.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Account or workspace not found.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"429":{"description":"Configured rate limit exceeded or client IP unavailable.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"500":{"description":"Handler or middleware failed.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}},"x-codeSamples":[{"lang":"Shell","source":"curl --fail-with-body --silent --show-error -X GET \"https://surgr.ai/api/v1/account\" \\\n  -H \"Authorization: Bearer $SURGR_API_KEY\""}]}},"/backlog":{"get":{"operationId":"get-backlog","tags":["Posts"],"summary":"Read all scoped drafts, newest first; no pagination or query filters.","description":"Permission: Valid scoped key; no action permission required for reads.\n\nReturns an array of post records, with threadParts, selected target delivery fields, and _count.threadParts/_count.targets. An empty backlog returns [].","parameters":[],"responses":{"200":{"description":"Read all scoped drafts, newest first; no pagination or query filters.\n\nIllustrative response shape, not real account data.\n\nReturns an array of post records, with threadParts, selected target delivery fields, and _count.threadParts/_count.targets. An empty backlog returns [].","content":{"application/json":{"example":[]}}},"401":{"description":"Missing, invalid, expired or revoked bearer key.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"429":{"description":"Configured rate limit exceeded or client IP unavailable.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"500":{"description":"Handler or middleware failed.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}},"x-codeSamples":[{"lang":"Shell","source":"curl --fail-with-body --silent --show-error -X GET \"https://surgr.ai/api/v1/backlog\" \\\n  -H \"Authorization: Bearer $SURGR_API_KEY\""}]}},"/posts":{"get":{"operationId":"get-posts","tags":["Posts"],"summary":"List scoped posts with filters, ordering and pagination.","description":"Permission: Valid scoped key; no action permission required for reads.\n\nscheduledAtGte and scheduledAtLte are validated but currently ignored by this handler. Use /timeline from/to instead.","parameters":[{"name":"status","in":"query","required":false,"description":"Filter by draft, scheduled, publishing, published or failed.","schema":{"type":"string","enum":["draft","scheduled","publishing","published","failed"]}},{"name":"platform","in":"query","required":false,"description":"Exact platform enum; filters the primary post.platform field, not all targets.","schema":{"type":"string","enum":["x_twitter","instagram","tiktok","youtube","linkedin","pinterest"]}},{"name":"search","in":"query","required":false,"description":"At most 200 characters; case-insensitive title or thread-part search.","schema":{"type":"string","maxLength":200}},{"name":"tags","in":"query","required":false,"description":"Comma-separated tags; matches any tag after trimming empty entries.","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"Integer ≥1; default 1.","schema":{"default":1,"type":"integer","minimum":1,"maximum":9007199254740991}},{"name":"limit","in":"query","required":false,"description":"Integer 1–100; default 20.","schema":{"default":20,"type":"integer","minimum":1,"maximum":100}},{"name":"sortBy","in":"query","required":false,"description":"createdAt, updatedAt, scheduledAt or sortOrder; default createdAt.","schema":{"default":"createdAt","type":"string","enum":["createdAt","updatedAt","scheduledAt","sortOrder"]}},{"name":"sortOrder","in":"query","required":false,"description":"asc or desc; default desc.","schema":{"default":"desc","type":"string","enum":["asc","desc"]}},{"name":"scheduledAtGte","in":"query","required":false,"description":"Accepted and validated ISO datetime, but the current list handler does not apply this filter. Use timeline from/to for a date range.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}},{"name":"scheduledAtLte","in":"query","required":false,"description":"Accepted and validated ISO datetime, but the current list handler does not apply this filter. Use timeline from/to for a date range.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}}],"responses":{"200":{"description":"List scoped posts with filters, ordering and pagination.\n\nIllustrative response shape, not real account data.\n\nscheduledAtGte and scheduledAtLte are validated but currently ignored by this handler. Use /timeline from/to instead.","content":{"application/json":{"example":{"data":[{"id":"post_example","userId":"user_example","workspaceId":"workspace_example","createdAt":"2030-01-01T00:00:00.000Z","updatedAt":"2030-01-01T00:00:00.000Z","title":"Launch update","platform":"x_twitter","targetPlatforms":["x_twitter"],"contentFormat":"text","status":"draft","revision":1,"reviewState":"needs_review","reviewEnforcedAt":"2030-01-01T00:00:00.000Z","reviewRequestedAt":"2030-01-01T00:00:00.000Z","proposedAt":null,"approvedRevision":null,"approvedAt":null,"approvedByUserId":null,"approvedByApiKeyId":null,"approvedPlatforms":[],"approvedScheduledAt":null,"scheduleRevision":0,"createdByApiKeyId":"connection_example","createdByName":"Example agent","clientRequestId":null,"scheduledAt":null,"publishedAt":null,"platformPostId":null,"platformUrl":null,"qstashMessageId":null,"autopublishEnabled":false,"lastError":null,"retryCount":0,"maxRetries":3,"publishingLockId":null,"publishingLockedAt":null,"tags":["launch"],"source":"api","linkUrl":null,"campaign":null,"campaignContent":null,"notes":null,"sortOrder":0,"threadParts":[{"id":"part_example","postId":"post_example","body":"A small launch update.","sortOrder":0,"createdAt":"2030-01-01T00:00:00.000Z","updatedAt":"2030-01-01T00:00:00.000Z","platformPartId":null,"media":[]}],"targets":[{"id":"target_example","postId":"post_example","platform":"x_twitter","mode":"x_text","requiresManual":false,"unsupportedReason":null,"metadata":null,"caption":"A small launch update.","title":null,"status":"draft","createdAt":"2030-01-01T00:00:00.000Z","updatedAt":"2030-01-01T00:00:00.000Z","scheduledAt":null,"publishedAt":null,"platformPostId":null,"platformUrl":null,"qstashMessageId":null,"autopublishEnabled":false,"lastError":null,"retryCount":0,"maxRetries":3,"publishingLockId":null,"publishingLockedAt":null}],"_count":{"threadParts":1}}],"total":1,"page":1,"limit":20,"totalPages":1}}}},"400":{"description":"Query validation failed.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"Missing, invalid, expired or revoked bearer key.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"429":{"description":"Configured rate limit exceeded or client IP unavailable.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"500":{"description":"Handler or middleware failed.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}},"x-codeSamples":[{"lang":"Shell","source":"curl --fail-with-body --silent --show-error -X GET \"https://surgr.ai/api/v1/posts\" \\\n  -H \"Authorization: Bearer $SURGR_API_KEY\""}]},"post":{"operationId":"post-posts","tags":["Posts"],"summary":"Create a draft with thread parts, media and per-platform text.","description":"Permission: draft\n\nIdempotency-Key replays the earlier draft with HTTP 200 and Idempotency-Replayed: true. This handler does not compare the new payload with the original; never reuse a key for new content.\n\nThe response is the post record, including targets and threadParts with media joins. source is always api.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string"},"description":"Replays the original draft; never reuse a key for different content."}],"responses":{"200":{"description":"Idempotent draft replay. Create a draft with thread parts, media and per-platform text.\n\nIllustrative response shape, not real account data.\n\nIdempotency-Key replays the earlier draft with HTTP 200 and Idempotency-Replayed: true. This handler does not compare the new payload with the original; never reuse a key for new content.\n\nThe response is the post record, including targets and threadParts with media joins. source is always api.","content":{"application/json":{"example":{"id":"post_example","userId":"user_example","workspaceId":"workspace_example","createdAt":"2030-01-01T00:00:00.000Z","updatedAt":"2030-01-01T00:00:00.000Z","title":"Launch update","platform":"x_twitter","targetPlatforms":["x_twitter"],"contentFormat":"text","status":"draft","revision":1,"reviewState":"needs_review","reviewEnforcedAt":"2030-01-01T00:00:00.000Z","reviewRequestedAt":"2030-01-01T00:00:00.000Z","proposedAt":null,"approvedRevision":null,"approvedAt":null,"approvedByUserId":null,"approvedByApiKeyId":null,"approvedPlatforms":[],"approvedScheduledAt":null,"scheduleRevision":0,"createdByApiKeyId":"connection_example","createdByName":"Example agent","clientRequestId":null,"scheduledAt":null,"publishedAt":null,"platformPostId":null,"platformUrl":null,"qstashMessageId":null,"autopublishEnabled":false,"lastError":null,"retryCount":0,"maxRetries":3,"publishingLockId":null,"publishingLockedAt":null,"tags":["launch"],"source":"api","linkUrl":null,"campaign":null,"campaignContent":null,"notes":null,"sortOrder":0,"threadParts":[{"id":"part_example","postId":"post_example","body":"A small launch update.","sortOrder":0,"createdAt":"2030-01-01T00:00:00.000Z","updatedAt":"2030-01-01T00:00:00.000Z","platformPartId":null,"media":[]}],"targets":[{"id":"target_example","postId":"post_example","platform":"x_twitter","mode":"x_text","requiresManual":false,"unsupportedReason":null,"metadata":null,"caption":"A small launch update.","title":null,"status":"draft","createdAt":"2030-01-01T00:00:00.000Z","updatedAt":"2030-01-01T00:00:00.000Z","scheduledAt":null,"publishedAt":null,"platformPostId":null,"platformUrl":null,"qstashMessageId":null,"autopublishEnabled":false,"lastError":null,"retryCount":0,"maxRetries":3,"publishingLockId":null,"publishingLockedAt":null}]}}}},"201":{"description":"Create a draft with thread parts, media and per-platform text.\n\nIllustrative response shape, not real account data.\n\nIdempotency-Key replays the earlier draft with HTTP 200 and Idempotency-Replayed: true. This handler does not compare the new payload with the original; never reuse a key for new content.\n\nThe response is the post record, including targets and threadParts with media joins. source is always api.","content":{"application/json":{"example":{"id":"post_example","userId":"user_example","workspaceId":"workspace_example","createdAt":"2030-01-01T00:00:00.000Z","updatedAt":"2030-01-01T00:00:00.000Z","title":"Launch update","platform":"x_twitter","targetPlatforms":["x_twitter"],"contentFormat":"text","status":"draft","revision":1,"reviewState":"needs_review","reviewEnforcedAt":"2030-01-01T00:00:00.000Z","reviewRequestedAt":"2030-01-01T00:00:00.000Z","proposedAt":null,"approvedRevision":null,"approvedAt":null,"approvedByUserId":null,"approvedByApiKeyId":null,"approvedPlatforms":[],"approvedScheduledAt":null,"scheduleRevision":0,"createdByApiKeyId":"connection_example","createdByName":"Example agent","clientRequestId":null,"scheduledAt":null,"publishedAt":null,"platformPostId":null,"platformUrl":null,"qstashMessageId":null,"autopublishEnabled":false,"lastError":null,"retryCount":0,"maxRetries":3,"publishingLockId":null,"publishingLockedAt":null,"tags":["launch"],"source":"api","linkUrl":null,"campaign":null,"campaignContent":null,"notes":null,"sortOrder":0,"threadParts":[{"id":"part_example","postId":"post_example","body":"A small launch update.","sortOrder":0,"createdAt":"2030-01-01T00:00:00.000Z","updatedAt":"2030-01-01T00:00:00.000Z","platformPartId":null,"media":[]}],"targets":[{"id":"target_example","postId":"post_example","platform":"x_twitter","mode":"x_text","requiresManual":false,"unsupportedReason":null,"metadata":null,"caption":"A small launch update.","title":null,"status":"draft","createdAt":"2030-01-01T00:00:00.000Z","updatedAt":"2030-01-01T00:00:00.000Z","scheduledAt":null,"publishedAt":null,"platformPostId":null,"platformUrl":null,"qstashMessageId":null,"autopublishEnabled":false,"lastError":null,"retryCount":0,"maxRetries":3,"publishingLockId":null,"publishingLockedAt":null}]}}}},"400":{"description":"Body validation failed.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"Missing, invalid, expired or revoked bearer key.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"Missing draft permission, disallowed platform or media outside this workspace.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"429":{"description":"Configured rate limit exceeded or client IP unavailable.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"500":{"description":"Handler or middleware failed.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}},"x-codeSamples":[{"lang":"Shell","source":"curl --fail-with-body --silent --show-error -X POST \"https://surgr.ai/api/v1/posts\" \\\n  -H \"Authorization: Bearer $SURGR_API_KEY\" \\\n  -H \"Idempotency-Key: example-create-1\" \\\n  -H \"Content-Type: application/json\" \\\n  --data '{\"title\":\"Launch update\",\"targetPlatforms\":[\"x_twitter\"],\"contentFormat\":\"text\",\"threadParts\":[{\"body\":\"A small launch update.\",\"sortOrder\":0}],\"tags\":[\"launch\"],\"requestReview\":true,\"platformText\":[{\"platform\":\"x_twitter\",\"caption\":\"A small launch update.\"}]}'"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"title":{"type":"string","maxLength":280},"platform":{"default":"x_twitter","type":"string","enum":["x_twitter","instagram","tiktok","youtube","linkedin","pinterest"]},"targetPlatforms":{"maxItems":6,"type":"array","items":{"type":"string","enum":["x_twitter","instagram","tiktok","youtube","linkedin","pinterest"]}},"contentFormat":{"default":"text","type":"string","enum":["text","thread","single_image","carousel","video","document","mixed"]},"threadParts":{"minItems":1,"type":"array","items":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":4000},"sortOrder":{"type":"integer","minimum":0,"maximum":9007199254740991},"mediaIds":{"maxItems":10,"type":"array","items":{"type":"string"}}},"required":["body","sortOrder"]}},"tags":{"maxItems":10,"type":"array","items":{"type":"string","maxLength":50}},"source":{"default":"web","type":"string","enum":["web","api","claude","openclaw","generated"]},"notes":{"type":"string","maxLength":5000},"proposedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"requestReview":{"default":false,"type":"boolean"},"linkUrl":{"anyOf":[{"type":"string","maxLength":2048,"format":"uri"},{"type":"null"}]},"campaign":{"anyOf":[{"type":"string","pattern":"^[a-z0-9][a-z0-9_-]{0,79}$"},{"type":"null"}]},"campaignContent":{"anyOf":[{"type":"string","pattern":"^[a-z0-9][a-z0-9_-]{0,79}$"},{"type":"null"}]},"platformText":{"maxItems":6,"type":"array","items":{"type":"object","properties":{"platform":{"type":"string","enum":["x_twitter","instagram","tiktok","youtube","linkedin","pinterest"]},"caption":{"anyOf":[{"type":"string","maxLength":4000},{"type":"null"}]},"title":{"anyOf":[{"type":"string","maxLength":280},{"type":"null"}]}},"required":["platform"]}}},"required":["threadParts"]},"example":{"title":"Launch update","targetPlatforms":["x_twitter"],"contentFormat":"text","threadParts":[{"body":"A small launch update.","sortOrder":0}],"tags":["launch"],"requestReview":true,"platformText":[{"platform":"x_twitter","caption":"A small launch update."}]}}}}}},"/posts/bulk":{"post":{"operationId":"post-posts-bulk","tags":["Posts"],"summary":"Create 1–50 drafts in one transaction.","description":"Permission: draft\n\nResponse posts include threadParts/media joins; this handler does not include a targets relation in its hydrated response.","parameters":[],"responses":{"201":{"description":"Create 1–50 drafts in one transaction.\n\nIllustrative response shape, not real account data.\n\nResponse posts include threadParts/media joins; this handler does not include a targets relation in its hydrated response.","content":{"application/json":{"example":{"created":1,"posts":[{"id":"post_example","userId":"user_example","workspaceId":"workspace_example","createdAt":"2030-01-01T00:00:00.000Z","updatedAt":"2030-01-01T00:00:00.000Z","title":"Launch update","platform":"x_twitter","targetPlatforms":["x_twitter"],"contentFormat":"text","status":"draft","revision":1,"reviewState":"needs_review","reviewEnforcedAt":"2030-01-01T00:00:00.000Z","reviewRequestedAt":"2030-01-01T00:00:00.000Z","proposedAt":null,"approvedRevision":null,"approvedAt":null,"approvedByUserId":null,"approvedByApiKeyId":null,"approvedPlatforms":[],"approvedScheduledAt":null,"scheduleRevision":0,"createdByApiKeyId":"connection_example","createdByName":"Example agent","clientRequestId":null,"scheduledAt":null,"publishedAt":null,"platformPostId":null,"platformUrl":null,"qstashMessageId":null,"autopublishEnabled":false,"lastError":null,"retryCount":0,"maxRetries":3,"publishingLockId":null,"publishingLockedAt":null,"tags":["launch"],"source":"api","linkUrl":null,"campaign":null,"campaignContent":null,"notes":null,"sortOrder":0,"threadParts":[{"id":"part_example","postId":"post_example","body":"A small launch update.","sortOrder":0,"createdAt":"2030-01-01T00:00:00.000Z","updatedAt":"2030-01-01T00:00:00.000Z","platformPartId":null,"media":[]}]}]}}}},"400":{"description":"Invalid batch or create-post body.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"Missing, invalid, expired or revoked bearer key.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"Missing draft permission, disallowed platform or foreign media.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"429":{"description":"Configured rate limit exceeded or client IP unavailable.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"500":{"description":"Handler or middleware failed.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}},"x-codeSamples":[{"lang":"Shell","source":"curl --fail-with-body --silent --show-error -X POST \"https://surgr.ai/api/v1/posts/bulk\" \\\n  -H \"Authorization: Bearer $SURGR_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  --data '{\"posts\":[{\"title\":\"Launch update\",\"targetPlatforms\":[\"x_twitter\"],\"contentFormat\":\"text\",\"threadParts\":[{\"body\":\"A small launch update.\",\"sortOrder\":0}],\"tags\":[\"launch\"],\"requestReview\":true,\"platformText\":[{\"platform\":\"x_twitter\",\"caption\":\"A small launch update.\"}]}]}'"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"posts":{"minItems":1,"maxItems":50,"type":"array","items":{"type":"object","properties":{"title":{"type":"string","maxLength":280},"platform":{"default":"x_twitter","type":"string","enum":["x_twitter","instagram","tiktok","youtube","linkedin","pinterest"]},"targetPlatforms":{"maxItems":6,"type":"array","items":{"type":"string","enum":["x_twitter","instagram","tiktok","youtube","linkedin","pinterest"]}},"contentFormat":{"default":"text","type":"string","enum":["text","thread","single_image","carousel","video","document","mixed"]},"threadParts":{"minItems":1,"type":"array","items":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":4000},"sortOrder":{"type":"integer","minimum":0,"maximum":9007199254740991},"mediaIds":{"maxItems":10,"type":"array","items":{"type":"string"}}},"required":["body","sortOrder"]}},"tags":{"maxItems":10,"type":"array","items":{"type":"string","maxLength":50}},"source":{"default":"web","type":"string","enum":["web","api","claude","openclaw","generated"]},"notes":{"type":"string","maxLength":5000},"proposedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"requestReview":{"default":false,"type":"boolean"},"linkUrl":{"anyOf":[{"type":"string","maxLength":2048,"format":"uri"},{"type":"null"}]},"campaign":{"anyOf":[{"type":"string","pattern":"^[a-z0-9][a-z0-9_-]{0,79}$"},{"type":"null"}]},"campaignContent":{"anyOf":[{"type":"string","pattern":"^[a-z0-9][a-z0-9_-]{0,79}$"},{"type":"null"}]},"platformText":{"maxItems":6,"type":"array","items":{"type":"object","properties":{"platform":{"type":"string","enum":["x_twitter","instagram","tiktok","youtube","linkedin","pinterest"]},"caption":{"anyOf":[{"type":"string","maxLength":4000},{"type":"null"}]},"title":{"anyOf":[{"type":"string","maxLength":280},{"type":"null"}]}},"required":["platform"]}}},"required":["threadParts"]}}},"required":["posts"]},"example":{"posts":[{"title":"Launch update","targetPlatforms":["x_twitter"],"contentFormat":"text","threadParts":[{"body":"A small launch update.","sortOrder":0}],"tags":["launch"],"requestReview":true,"platformText":[{"platform":"x_twitter","caption":"A small launch update."}]}]}}}}}},"/posts/{id}":{"get":{"operationId":"get-posts-id","tags":["Posts"],"summary":"Read a scoped post, its targets, feedback and recent activity.","description":"Permission: Valid scoped key; no action permission required for reads.\n\nIncludes threadParts/media, targets, the latest 5 publishLogs, all changeRequests and latest 20 integrationActivities.","parameters":[{"name":"id","in":"path","required":true,"description":"ID returned by the relevant create/presign response; fake example IDs must be replaced.","schema":{"type":"string"}}],"responses":{"200":{"description":"Read a scoped post, its targets, feedback and recent activity.\n\nIllustrative response shape, not real account data.\n\nIncludes threadParts/media, targets, the latest 5 publishLogs, all changeRequests and latest 20 integrationActivities.","content":{"application/json":{"example":{"id":"post_example","userId":"user_example","workspaceId":"workspace_example","createdAt":"2030-01-01T00:00:00.000Z","updatedAt":"2030-01-01T00:00:00.000Z","title":"Launch update","platform":"x_twitter","targetPlatforms":["x_twitter"],"contentFormat":"text","status":"draft","revision":1,"reviewState":"needs_review","reviewEnforcedAt":"2030-01-01T00:00:00.000Z","reviewRequestedAt":"2030-01-01T00:00:00.000Z","proposedAt":null,"approvedRevision":null,"approvedAt":null,"approvedByUserId":null,"approvedByApiKeyId":null,"approvedPlatforms":[],"approvedScheduledAt":null,"scheduleRevision":0,"createdByApiKeyId":"connection_example","createdByName":"Example agent","clientRequestId":null,"scheduledAt":null,"publishedAt":null,"platformPostId":null,"platformUrl":null,"qstashMessageId":null,"autopublishEnabled":false,"lastError":null,"retryCount":0,"maxRetries":3,"publishingLockId":null,"publishingLockedAt":null,"tags":["launch"],"source":"api","linkUrl":null,"campaign":null,"campaignContent":null,"notes":null,"sortOrder":0,"threadParts":[{"id":"part_example","postId":"post_example","body":"A small launch update.","sortOrder":0,"createdAt":"2030-01-01T00:00:00.000Z","updatedAt":"2030-01-01T00:00:00.000Z","platformPartId":null,"media":[]}],"targets":[{"id":"target_example","postId":"post_example","platform":"x_twitter","mode":"x_text","requiresManual":false,"unsupportedReason":null,"metadata":null,"caption":"A small launch update.","title":null,"status":"draft","createdAt":"2030-01-01T00:00:00.000Z","updatedAt":"2030-01-01T00:00:00.000Z","scheduledAt":null,"publishedAt":null,"platformPostId":null,"platformUrl":null,"qstashMessageId":null,"autopublishEnabled":false,"lastError":null,"retryCount":0,"maxRetries":3,"publishingLockId":null,"publishingLockedAt":null}],"publishLogs":[],"changeRequests":[],"integrationActivities":[]}}}},"400":{"description":"Post ID missing.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"Missing, invalid, expired or revoked bearer key.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"Post outside the workspace or allowed platform scope.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Post not found.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"429":{"description":"Configured rate limit exceeded or client IP unavailable.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"500":{"description":"Handler or middleware failed.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}},"x-codeSamples":[{"lang":"Shell","source":"curl --fail-with-body --silent --show-error -X GET \"https://surgr.ai/api/v1/posts/post_example\" \\\n  -H \"Authorization: Bearer $SURGR_API_KEY\""}]},"patch":{"operationId":"patch-posts-id","tags":["Posts"],"summary":"Edit a scoped mutable post; material edits clear its approval and schedule.","description":"Permission: draft; also manage_own for self-approved posts or manage_approved for posts approved by a person/another connection\n\nscheduledAt/status are schema-accepted but forbidden for non-legacy keys; use scheduling operations.\n\nAn edit of any already-approved post clears approval/schedule. threadParts, platforms, format and link changes also invalidate the revision. PATCH with missing or empty mediaIds preserves the prior media at that sortOrder.","parameters":[{"name":"id","in":"path","required":true,"description":"ID returned by the relevant create/presign response; fake example IDs must be replaced.","schema":{"type":"string"}}],"responses":{"200":{"description":"Edit a scoped mutable post; material edits clear its approval and schedule.\n\nIllustrative response shape, not real account data.\n\nscheduledAt/status are schema-accepted but forbidden for non-legacy keys; use scheduling operations.\n\nAn edit of any already-approved post clears approval/schedule. threadParts, platforms, format and link changes also invalidate the revision. PATCH with missing or empty mediaIds preserves the prior media at that sortOrder.","content":{"application/json":{"example":{"id":"post_example","userId":"user_example","workspaceId":"workspace_example","createdAt":"2030-01-01T00:00:00.000Z","updatedAt":"2030-01-01T00:00:00.000Z","title":"Updated launch note","platform":"x_twitter","targetPlatforms":["x_twitter"],"contentFormat":"text","status":"draft","revision":1,"reviewState":"needs_review","reviewEnforcedAt":"2030-01-01T00:00:00.000Z","reviewRequestedAt":"2030-01-01T00:00:00.000Z","proposedAt":null,"approvedRevision":null,"approvedAt":null,"approvedByUserId":null,"approvedByApiKeyId":null,"approvedPlatforms":[],"approvedScheduledAt":null,"scheduleRevision":0,"createdByApiKeyId":"connection_example","createdByName":"Example agent","clientRequestId":null,"scheduledAt":null,"publishedAt":null,"platformPostId":null,"platformUrl":null,"qstashMessageId":null,"autopublishEnabled":false,"lastError":null,"retryCount":0,"maxRetries":3,"publishingLockId":null,"publishingLockedAt":null,"tags":["launch"],"source":"api","linkUrl":null,"campaign":null,"campaignContent":null,"notes":null,"sortOrder":0,"threadParts":[{"id":"part_example","postId":"post_example","body":"A small launch update.","sortOrder":0,"createdAt":"2030-01-01T00:00:00.000Z","updatedAt":"2030-01-01T00:00:00.000Z","platformPartId":null,"media":[]}],"targets":[{"id":"target_example","postId":"post_example","platform":"x_twitter","mode":"x_text","requiresManual":false,"unsupportedReason":null,"metadata":null,"caption":"A small launch update.","title":null,"status":"draft","createdAt":"2030-01-01T00:00:00.000Z","updatedAt":"2030-01-01T00:00:00.000Z","scheduledAt":null,"publishedAt":null,"platformPostId":null,"platformUrl":null,"qstashMessageId":null,"autopublishEnabled":false,"lastError":null,"retryCount":0,"maxRetries":3,"publishingLockId":null,"publishingLockedAt":null}]}}}},"400":{"description":"Missing ID or body validation failed.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"Missing, invalid, expired or revoked bearer key.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"Permission/scope refusal, foreign media, or delivery-state fields on a non-legacy key.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Post not found.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"409":{"description":"Stale revision, publishing in progress, or published post cannot be changed.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"429":{"description":"Configured rate limit exceeded or client IP unavailable.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"500":{"description":"Handler or middleware failed.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}},"x-codeSamples":[{"lang":"Shell","source":"curl --fail-with-body --silent --show-error -X PATCH \"https://surgr.ai/api/v1/posts/post_example\" \\\n  -H \"Authorization: Bearer $SURGR_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  --data '{\"title\":\"Updated launch note\",\"expectedRevision\":1}'"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"title":{"anyOf":[{"type":"string","maxLength":280},{"type":"null"}]},"platform":{"type":"string","enum":["x_twitter","instagram","tiktok","youtube","linkedin","pinterest"]},"targetPlatforms":{"maxItems":6,"type":"array","items":{"type":"string","enum":["x_twitter","instagram","tiktok","youtube","linkedin","pinterest"]}},"contentFormat":{"type":"string","enum":["text","thread","single_image","carousel","video","document","mixed"]},"tags":{"maxItems":10,"type":"array","items":{"type":"string","maxLength":50}},"threadParts":{"minItems":1,"type":"array","items":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":4000},"sortOrder":{"type":"integer","minimum":0,"maximum":9007199254740991},"mediaIds":{"maxItems":10,"type":"array","items":{"type":"string"}}},"required":["body","sortOrder"]}},"notes":{"anyOf":[{"type":"string","maxLength":5000},{"type":"null"}]},"scheduledAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},{"type":"null"}]},"status":{"type":"string","enum":["draft","scheduled","publishing","failed"]},"proposedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},{"type":"null"}]},"requestReview":{"type":"boolean"},"expectedRevision":{"type":"integer","minimum":1,"maximum":9007199254740991},"linkUrl":{"anyOf":[{"type":"string","maxLength":2048,"format":"uri"},{"type":"null"}]},"campaign":{"anyOf":[{"type":"string","pattern":"^[a-z0-9][a-z0-9_-]{0,79}$"},{"type":"null"}]},"campaignContent":{"anyOf":[{"type":"string","pattern":"^[a-z0-9][a-z0-9_-]{0,79}$"},{"type":"null"}]},"platformText":{"maxItems":6,"type":"array","items":{"type":"object","properties":{"platform":{"type":"string","enum":["x_twitter","instagram","tiktok","youtube","linkedin","pinterest"]},"caption":{"anyOf":[{"type":"string","maxLength":4000},{"type":"null"}]},"title":{"anyOf":[{"type":"string","maxLength":280},{"type":"null"}]}},"required":["platform"]}}}},"example":{"title":"Updated launch note","expectedRevision":1}}}}},"delete":{"operationId":"delete-posts-id","tags":["Posts"],"summary":"Delete a mutable post and clean up media with no remaining references.","description":"Permission: draft; also manage_own for self-approved posts or manage_approved for posts approved by a person/another connection\n\nIrreversible deletion; shared media still attached elsewhere is preserved. Storage cleanup is asynchronous best effort.","parameters":[{"name":"id","in":"path","required":true,"description":"ID returned by the relevant create/presign response; fake example IDs must be replaced.","schema":{"type":"string"}}],"responses":{"200":{"description":"Delete a mutable post and clean up media with no remaining references.\n\nIllustrative response shape, not real account data.\n\nIrreversible deletion; shared media still attached elsewhere is preserved. Storage cleanup is asynchronous best effort.","content":{"application/json":{"example":{"success":true}}}},"400":{"description":"Post ID missing.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"Missing, invalid, expired or revoked bearer key.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"Permission or workspace/platform scope refusal.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Post not found.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"409":{"description":"Publishing in progress or already-published post cannot be deleted.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"429":{"description":"Configured rate limit exceeded or client IP unavailable.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"500":{"description":"Handler or middleware failed.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}},"x-codeSamples":[{"lang":"Shell","source":"curl --fail-with-body --silent --show-error -X DELETE \"https://surgr.ai/api/v1/posts/post_example\" \\\n  -H \"Authorization: Bearer $SURGR_API_KEY\""}]}},"/posts/{id}/schedule":{"post":{"operationId":"post-posts-id-schedule","tags":["Scheduling"],"summary":"Queue eligible targets at a future time, preserving or recording a matching approval.","description":"Permission: schedule for new drafts; manage_own for its approvals; dispatch_approved or manage_approved for matching approvals by others\n\nFor review-first use, create/request review, then stop for a person to use Inbox Approve & schedule; that action already queues the post. dispatch_approved is only for re-dispatching a still-current exact approval: first reread the post and preserve its approved revision, destinations and time. schedule can self-approve an unapproved draft; do not grant it if every post must get human review.\n\nA quota-limited Free account can receive HTTP 200 with status draft, autopublishEnabled false and autopublishLocked true: it was not queued. Normal responses contain targets/threadParts; quota responses include threadParts but not targets.\n\nrequestId takes precedence over Idempotency-Key. Replays return HTTP 200 / Idempotency-Replayed: true; changed payloads return 409. A request still in progress can return Retry-After: 30.\n\nAn HTTP 200 scheduled response confirms queueing, not successful publication. Check GET /posts/{id} for each target’s status/lastError/platformUrl.","parameters":[{"name":"id","in":"path","required":true,"description":"ID returned by the relevant create/presign response; fake example IDs must be replaced.","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string"},"description":"Fallback idempotency key when requestId is absent; changed payloads conflict."}],"responses":{"200":{"description":"Queue eligible targets at a future time, preserving or recording a matching approval.\n\nIllustrative response shape, not real account data.\n\nFor review-first use, create/request review, then stop for a person to use Inbox Approve & schedule; that action already queues the post. dispatch_approved is only for re-dispatching a still-current exact approval: first reread the post and preserve its approved revision, destinations and time. schedule can self-approve an unapproved draft; do not grant it if every post must get human review.\n\nA quota-limited Free account can receive HTTP 200 with status draft, autopublishEnabled false and autopublishLocked true: it was not queued. Normal responses contain targets/threadParts; quota responses include threadParts but not targets.\n\nrequestId takes precedence over Idempotency-Key. Replays return HTTP 200 / Idempotency-Replayed: true; changed payloads return 409. A request still in progress can return Retry-After: 30.\n\nAn HTTP 200 scheduled response confirms queueing, not successful publication. Check GET /posts/{id} for each target’s status/lastError/platformUrl.","content":{"application/json":{"example":{"id":"post_example","userId":"user_example","workspaceId":"workspace_example","createdAt":"2030-01-01T00:00:00.000Z","updatedAt":"2030-01-01T00:00:00.000Z","title":"Launch update","platform":"x_twitter","targetPlatforms":["x_twitter"],"contentFormat":"text","status":"scheduled","revision":1,"reviewState":"approved","reviewEnforcedAt":"2030-01-01T00:00:00.000Z","reviewRequestedAt":"2030-01-01T00:00:00.000Z","proposedAt":null,"approvedRevision":1,"approvedAt":"2030-01-01T00:00:00.000Z","approvedByUserId":"user_example","approvedByApiKeyId":null,"approvedPlatforms":["x_twitter"],"approvedScheduledAt":"2030-01-02T09:00:00.000Z","scheduleRevision":1,"createdByApiKeyId":"connection_example","createdByName":"Example agent","clientRequestId":null,"scheduledAt":"2030-01-02T09:00:00.000Z","publishedAt":null,"platformPostId":null,"platformUrl":null,"qstashMessageId":"message_example","autopublishEnabled":true,"lastError":null,"retryCount":0,"maxRetries":3,"publishingLockId":null,"publishingLockedAt":null,"tags":["launch"],"source":"api","linkUrl":null,"campaign":null,"campaignContent":null,"notes":null,"sortOrder":0,"threadParts":[{"id":"part_example","postId":"post_example","body":"A small launch update.","sortOrder":0,"createdAt":"2030-01-01T00:00:00.000Z","updatedAt":"2030-01-01T00:00:00.000Z","platformPartId":null}],"targets":[{"id":"target_example","postId":"post_example","platform":"x_twitter","mode":"x_text","requiresManual":false,"unsupportedReason":null,"metadata":null,"caption":"A small launch update.","title":null,"status":"scheduled","createdAt":"2030-01-01T00:00:00.000Z","updatedAt":"2030-01-01T00:00:00.000Z","scheduledAt":"2030-01-02T09:00:00.000Z","publishedAt":null,"platformPostId":null,"platformUrl":null,"qstashMessageId":"message_example","autopublishEnabled":true,"lastError":null,"retryCount":0,"maxRetries":3,"publishingLockId":null,"publishingLockedAt":null}]}}}},"400":{"description":"Missing ID, invalid body, past time, or no thread content.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"Missing, invalid, expired or revoked bearer key.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"Ownership, platform or permission refusal.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Post not found.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"409":{"description":"Publishing paused, no eligible targets, stale/changed approval, changed revision, idempotency conflict or request in progress.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"429":{"description":"Configured rate limit exceeded or client IP unavailable.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"500":{"description":"Handler or middleware failed.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"502":{"description":"Failed to queue publish jobs.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}},"x-codeSamples":[{"lang":"Shell","source":"curl --fail-with-body --silent --show-error -X POST \"https://surgr.ai/api/v1/posts/post_example/schedule\" \\\n  -H \"Authorization: Bearer $SURGR_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  --data '{\"scheduledAt\":\"2030-01-02T09:00:00Z\",\"expectedRevision\":1,\"requestId\":\"example-schedule-1\"}'"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"scheduledAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"expectedRevision":{"type":"integer","minimum":1,"maximum":9007199254740991},"requestId":{"type":"string","minLength":1,"maxLength":200}},"required":["scheduledAt"]},"example":{"scheduledAt":"2030-01-02T09:00:00Z","expectedRevision":1,"requestId":"example-schedule-1"}}}}}},"/posts/{id}/unschedule":{"post":{"operationId":"post-posts-id-unschedule","tags":["Scheduling"],"summary":"Cancel a scheduled post, return it to draft and clear scoped approval.","description":"Permission: manage_own for self-approved posts; manage_approved for other or missing approvals\n\nNo request body. The response includes targets and threadParts; scheduleRevision increases.","parameters":[{"name":"id","in":"path","required":true,"description":"ID returned by the relevant create/presign response; fake example IDs must be replaced.","schema":{"type":"string"}}],"responses":{"200":{"description":"Cancel a scheduled post, return it to draft and clear scoped approval.\n\nIllustrative response shape, not real account data.\n\nNo request body. The response includes targets and threadParts; scheduleRevision increases.","content":{"application/json":{"example":{"id":"post_example","userId":"user_example","workspaceId":"workspace_example","createdAt":"2030-01-01T00:00:00.000Z","updatedAt":"2030-01-01T00:00:00.000Z","title":"Launch update","platform":"x_twitter","targetPlatforms":["x_twitter"],"contentFormat":"text","status":"draft","revision":1,"reviewState":"draft","reviewEnforcedAt":"2030-01-01T00:00:00.000Z","reviewRequestedAt":"2030-01-01T00:00:00.000Z","proposedAt":null,"approvedRevision":null,"approvedAt":null,"approvedByUserId":null,"approvedByApiKeyId":null,"approvedPlatforms":[],"approvedScheduledAt":null,"scheduleRevision":2,"createdByApiKeyId":"connection_example","createdByName":"Example agent","clientRequestId":null,"scheduledAt":null,"publishedAt":null,"platformPostId":null,"platformUrl":null,"qstashMessageId":null,"autopublishEnabled":false,"lastError":null,"retryCount":0,"maxRetries":3,"publishingLockId":null,"publishingLockedAt":null,"tags":["launch"],"source":"api","linkUrl":null,"campaign":null,"campaignContent":null,"notes":null,"sortOrder":0,"threadParts":[{"id":"part_example","postId":"post_example","body":"A small launch update.","sortOrder":0,"createdAt":"2030-01-01T00:00:00.000Z","updatedAt":"2030-01-01T00:00:00.000Z","platformPartId":null}],"targets":[{"id":"target_example","postId":"post_example","platform":"x_twitter","mode":"x_text","requiresManual":false,"unsupportedReason":null,"metadata":null,"caption":"A small launch update.","title":null,"status":"draft","createdAt":"2030-01-01T00:00:00.000Z","updatedAt":"2030-01-01T00:00:00.000Z","scheduledAt":null,"publishedAt":null,"platformPostId":null,"platformUrl":null,"qstashMessageId":null,"autopublishEnabled":false,"lastError":null,"retryCount":0,"maxRetries":3,"publishingLockId":null,"publishingLockedAt":null}]}}}},"400":{"description":"Missing ID or post is not scheduled.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"Missing, invalid, expired or revoked bearer key.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"Ownership, platform or cancellation permission refusal.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Post not found.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"409":{"description":"Post began publishing during cancellation.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"429":{"description":"Configured rate limit exceeded or client IP unavailable.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"500":{"description":"Handler or middleware failed.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}},"x-codeSamples":[{"lang":"Shell","source":"curl --fail-with-body --silent --show-error -X POST \"https://surgr.ai/api/v1/posts/post_example/unschedule\" \\\n  -H \"Authorization: Bearer $SURGR_API_KEY\""}]}},"/posts/{id}/publish-now":{"post":{"operationId":"post-posts-id-publish-now","tags":["Scheduling"],"summary":"Enqueue eligible targets immediately; this is not a published receipt.","description":"Permission: publish_now; also manage_own or manage_approved for an already-approved post\n\nPrefer schedule plus human review. No request body. For scoped keys this records the connection’s approval; it does not require prior human review.\n\nResponse status scheduled means queued. Re-read the post/targets for published or failed delivery.","parameters":[{"name":"id","in":"path","required":true,"description":"ID returned by the relevant create/presign response; fake example IDs must be replaced.","schema":{"type":"string"}}],"responses":{"200":{"description":"Enqueue eligible targets immediately; this is not a published receipt.\n\nIllustrative response shape, not real account data.\n\nPrefer schedule plus human review. No request body. For scoped keys this records the connection’s approval; it does not require prior human review.\n\nResponse status scheduled means queued. Re-read the post/targets for published or failed delivery.","content":{"application/json":{"example":{"id":"post_example","status":"scheduled","targetCount":1,"message":"Publishing in progress — this may take a moment for posts with video."}}}},"400":{"description":"Missing ID or no thread content.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"Missing, invalid, expired or revoked bearer key.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"Ownership, platform or permission refusal.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Post not found.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"409":{"description":"No eligible targets, publishing in progress or already-published post.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"429":{"description":"Configured rate limit exceeded or client IP unavailable.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"500":{"description":"Handler or middleware failed.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}},"x-codeSamples":[{"lang":"Shell","source":"curl --fail-with-body --silent --show-error -X POST \"https://surgr.ai/api/v1/posts/post_example/publish-now\" \\\n  -H \"Authorization: Bearer $SURGR_API_KEY\""}]}},"/media/presign":{"post":{"operationId":"post-media-presign","tags":["Media"],"summary":"Reserve media and obtain a 5-minute direct-upload URL.","description":"Permission: draft\n\nPUT the exact byte count and Content-Type to uploadUrl, then confirm media.id. Do not send the Surgr bearer key to the presigned upload host.","parameters":[],"responses":{"201":{"description":"Reserve media and obtain a 5-minute direct-upload URL.\n\nIllustrative response shape, not real account data.\n\nPUT the exact byte count and Content-Type to uploadUrl, then confirm media.id. Do not send the Surgr bearer key to the presigned upload host.","content":{"application/json":{"example":{"uploadUrl":"https://upload.example.invalid/demo.mp4?example=presigned","media":{"id":"media_example","userId":"user_example","workspaceId":"workspace_example","createdAt":"2030-01-01T00:00:00.000Z","updatedAt":"2030-01-01T00:00:00.000Z","filename":"demo.mp4","mimeType":"video/mp4","sizeBytes":1000000,"width":null,"height":null,"durationMs":null,"storageUrl":"","storageKey":"media/user_example/demo.mp4","processingStatus":"processing"}}}}},"400":{"description":"Invalid fields, unsupported MIME or file larger than 104857600 bytes.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"Missing, invalid, expired or revoked bearer key.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"Missing draft permission.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"429":{"description":"Configured rate limit exceeded or client IP unavailable.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"500":{"description":"Handler or middleware failed.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}},"x-codeSamples":[{"lang":"Shell","source":"curl --fail-with-body --silent --show-error -X POST \"https://surgr.ai/api/v1/media/presign\" \\\n  -H \"Authorization: Bearer $SURGR_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  --data '{\"fileName\":\"demo.mp4\",\"fileType\":\"video/mp4\",\"fileSize\":1000000}'"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"fileName":{"type":"string","minLength":1,"maxLength":255},"fileType":{"type":"string","minLength":1,"maxLength":127},"fileSize":{"type":"integer","exclusiveMinimum":0,"maximum":104857600}},"required":["fileName","fileType","fileSize"]},"example":{"fileName":"demo.mp4","fileType":"video/mp4","fileSize":1000000}}}}}},"/media/upload":{"post":{"operationId":"post-media-upload","tags":["Media"],"summary":"Fetch a public URL server-side and create ready media.","description":"Permission: draft\n\nUses different field casing from presign: filename/mimeType. No confirm call needed; processingStatus is ready. Public media URLs must be replaceable fake examples here.","parameters":[],"responses":{"201":{"description":"Fetch a public URL server-side and create ready media.\n\nIllustrative response shape, not real account data.\n\nUses different field casing from presign: filename/mimeType. No confirm call needed; processingStatus is ready. Public media URLs must be replaceable fake examples here.","content":{"application/json":{"example":{"id":"media_example","userId":"user_example","workspaceId":"workspace_example","createdAt":"2030-01-01T00:00:00.000Z","updatedAt":"2030-01-01T00:00:00.000Z","filename":"demo.mp4","mimeType":"video/mp4","sizeBytes":1000000,"width":null,"height":null,"durationMs":null,"storageUrl":"https://assets.example.invalid/demo.mp4","storageKey":"media/user_example/demo.mp4","processingStatus":"ready"}}}},"400":{"description":"Invalid body, unsafe/private URL or failed/oversized download.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"Missing, invalid, expired or revoked bearer key.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"Missing draft permission.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"429":{"description":"Configured rate limit exceeded or client IP unavailable.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"500":{"description":"Handler or middleware failed.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}},"x-codeSamples":[{"lang":"Shell","source":"curl --fail-with-body --silent --show-error -X POST \"https://surgr.ai/api/v1/media/upload\" \\\n  -H \"Authorization: Bearer $SURGR_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  --data '{\"url\":\"https://assets.example.invalid/demo.mp4\",\"filename\":\"demo.mp4\",\"mimeType\":\"video/mp4\"}'"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"url":{"type":"string","format":"uri"},"filename":{"type":"string","maxLength":255},"mimeType":{"type":"string","maxLength":127}},"required":["url"]},"example":{"url":"https://assets.example.invalid/demo.mp4","filename":"demo.mp4","mimeType":"video/mp4"}}}}}},"/media/{id}/confirm":{"post":{"operationId":"post-media-id-confirm","tags":["Media"],"summary":"Verify a presigned object and mark reserved media ready.","description":"Permission: draft\n\nNo request body. Confirm the ID returned by presign after the PUT completes; not idempotent once processingStatus is ready.","parameters":[{"name":"id","in":"path","required":true,"description":"ID returned by the relevant create/presign response; fake example IDs must be replaced.","schema":{"type":"string"}}],"responses":{"200":{"description":"Verify a presigned object and mark reserved media ready.\n\nIllustrative response shape, not real account data.\n\nNo request body. Confirm the ID returned by presign after the PUT completes; not idempotent once processingStatus is ready.","content":{"application/json":{"example":{"id":"media_example","userId":"user_example","workspaceId":"workspace_example","createdAt":"2030-01-01T00:00:00.000Z","updatedAt":"2030-01-01T00:00:00.000Z","filename":"demo.mp4","mimeType":"video/mp4","sizeBytes":1000000,"width":null,"height":null,"durationMs":null,"storageUrl":"https://assets.example.invalid/demo.mp4","storageKey":"media/user_example/demo.mp4","processingStatus":"ready"}}}},"400":{"description":"Missing ID or stored upload fails size/content-type verification.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"Missing, invalid, expired or revoked bearer key.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"403":{"description":"Missing draft permission or foreign workspace media.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Media not found.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"409":{"description":"Media is not in processing state.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"429":{"description":"Configured rate limit exceeded or client IP unavailable.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"500":{"description":"Handler or middleware failed.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}},"x-codeSamples":[{"lang":"Shell","source":"curl --fail-with-body --silent --show-error -X POST \"https://surgr.ai/api/v1/media/media_example/confirm\" \\\n  -H \"Authorization: Bearer $SURGR_API_KEY\""}]}},"/stats":{"get":{"operationId":"get-stats","tags":["Results"],"summary":"Read scoped queue counts, next schedule, seven-day gaps and up to five failed/stuck posts.","description":"Permission: Valid scoped key; no action permission required for reads.\n\nNo query fields. Failed posts include id, preview, lastError, failedAt and targetErrors (platform, status, message, failedAt). Stale publishing/scheduled targets use a 10-minute threshold.","parameters":[],"responses":{"200":{"description":"Read scoped queue counts, next schedule, seven-day gaps and up to five failed/stuck posts.\n\nIllustrative response shape, not real account data.\n\nNo query fields. Failed posts include id, preview, lastError, failedAt and targetErrors (platform, status, message, failedAt). Stale publishing/scheduled targets use a 10-minute threshold.","content":{"application/json":{"example":{"totalPosts":0,"published":0,"failed":0,"scheduled":0,"drafts":0,"successRate":100,"nextScheduledAt":null,"nextScheduledPreview":null,"gapDays":7,"scheduledByDay":[{"date":"2030-01-01","count":0},{"date":"2030-01-02","count":0},{"date":"2030-01-03","count":0},{"date":"2030-01-04","count":0},{"date":"2030-01-05","count":0},{"date":"2030-01-06","count":0},{"date":"2030-01-07","count":0}],"failedPosts":[]}}}},"401":{"description":"Missing, invalid, expired or revoked bearer key.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"429":{"description":"Configured rate limit exceeded or client IP unavailable.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"500":{"description":"Handler or middleware failed.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}},"x-codeSamples":[{"lang":"Shell","source":"curl --fail-with-body --silent --show-error -X GET \"https://surgr.ai/api/v1/stats\" \\\n  -H \"Authorization: Bearer $SURGR_API_KEY\""}]}},"/results":{"get":{"operationId":"get-results","tags":["Results"],"summary":"Read scoped 30-day growth, post metrics, lessons and metric sync status.","description":"Permission: Valid scoped key; no action permission required for reads.\n\nNo query fields. summary, growth, daily, followers, topPosts, lessons and syncStatus are returned. Null/stale metrics must not be turned into invented results.\n\ndaily contains 30 daily points. topPosts/bestPost include per-destination counts; syncStatus reports lastAttemptAt, lastSuccessAt and lastError for connected platforms.","parameters":[],"responses":{"200":{"description":"Read scoped 30-day growth, post metrics, lessons and metric sync status.\n\nIllustrative response shape, not real account data.\n\nNo query fields. summary, growth, daily, followers, topPosts, lessons and syncStatus are returned. Null/stale metrics must not be turned into invented results.\n\ndaily contains 30 daily points. topPosts/bestPost include per-destination counts; syncStatus reports lastAttemptAt, lastSuccessAt and lastError for connected platforms.","content":{"application/json":{"example":{"summary":{"followersCurrent":null,"followersDelta7d":null,"followersDelta30d":null,"impressions7d":0,"impressions30d":0,"postsPublished7d":0,"postsPublished30d":0,"engagement30d":0,"averageImpressionsPerPost30d":0,"bestPost30d":null,"lastMetricsSyncAt":null,"xConnected":false},"growth":{"audienceCurrent":null,"audienceDelta7d":null,"audienceDeltaPrevious7d":null,"followersCurrent":null,"followersDelta7d":null,"followersDeltaPrevious7d":null,"exposure7d":0,"exposurePrevious7d":0,"impressions7d":0,"impressionsPrevious7d":0,"postsPublished7d":0,"postsPublishedPrevious7d":0,"engagement7d":0,"engagementPrevious7d":0,"lastMetricsSyncAt":null,"bestPost7d":null,"platformBreakdown":[],"nextAction":{"label":"Connect a platform to collect results.","href":"/settings","tone":"warning"},"xConnected":false,"connectedPlatforms":[]},"daily":[{"date":"2030-01-02","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-03","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-04","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-05","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-06","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-07","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-08","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-09","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-10","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-11","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-12","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-13","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-14","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-15","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-16","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-17","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-18","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-19","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-20","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-21","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-22","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-23","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-24","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-25","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-26","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-27","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-28","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-29","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-30","postsPublished":0,"impressionCount":0,"engagementCount":0},{"date":"2030-01-31","postsPublished":0,"impressionCount":0,"engagementCount":0}],"followers":[],"topPosts":[],"lessons":[{"title":"Connect a platform","detail":"Connect a social platform to start collecting result snapshots.","tone":"warning"}],"syncStatus":[]}}}},"401":{"description":"Missing, invalid, expired or revoked bearer key.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"429":{"description":"Configured rate limit exceeded or client IP unavailable.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"500":{"description":"Handler or middleware failed.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}},"x-codeSamples":[{"lang":"Shell","source":"curl --fail-with-body --silent --show-error -X GET \"https://surgr.ai/api/v1/results\" \\\n  -H \"Authorization: Bearer $SURGR_API_KEY\""}]}},"/tags":{"get":{"operationId":"get-tags","tags":["Results"],"summary":"Read distinct tags and scoped post counts, most frequent first.","description":"Permission: Valid scoped key; no action permission required for reads.\n\nNo query fields. Counts each tag once per post; ties sort by tag.","parameters":[],"responses":{"200":{"description":"Read distinct tags and scoped post counts, most frequent first.\n\nIllustrative response shape, not real account data.\n\nNo query fields. Counts each tag once per post; ties sort by tag.","content":{"application/json":{"example":[{"tag":"launch","count":1}]}}},"401":{"description":"Missing, invalid, expired or revoked bearer key.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"429":{"description":"Configured rate limit exceeded or client IP unavailable.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"500":{"description":"Handler or middleware failed.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}},"x-codeSamples":[{"lang":"Shell","source":"curl --fail-with-body --silent --show-error -X GET \"https://surgr.ai/api/v1/tags\" \\\n  -H \"Authorization: Bearer $SURGR_API_KEY\""}]}},"/timeline":{"get":{"operationId":"get-timeline","tags":["Results"],"summary":"Read scoped scheduled, publishing and published posts ordered by scheduledAt.","description":"Permission: Valid scoped key; no action permission required for reads.\n\nOnly posts with a scheduledAt are returned. Bounds are inclusive; no default range or pagination. Raw post records include threadParts, selected target delivery fields and _count.threadParts/_count.targets.","parameters":[{"name":"from","in":"query","required":false,"description":"Optional inclusive scheduledAt lower bound; ISO datetime with offset.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}},{"name":"to","in":"query","required":false,"description":"Optional inclusive scheduledAt upper bound; ISO datetime with offset.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}}],"responses":{"200":{"description":"Read scoped scheduled, publishing and published posts ordered by scheduledAt.\n\nIllustrative response shape, not real account data.\n\nOnly posts with a scheduledAt are returned. Bounds are inclusive; no default range or pagination. Raw post records include threadParts, selected target delivery fields and _count.threadParts/_count.targets.","content":{"application/json":{"example":[]}}},"400":{"description":"Invalid from/to datetime.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"Missing, invalid, expired or revoked bearer key.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"429":{"description":"Configured rate limit exceeded or client IP unavailable.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"500":{"description":"Handler or middleware failed.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}},"x-codeSamples":[{"lang":"Shell","source":"curl --fail-with-body --silent --show-error -X GET \"https://surgr.ai/api/v1/timeline\" \\\n  -H \"Authorization: Bearer $SURGR_API_KEY\""}]}}}}