{"openapi":"3.1.0","info":{"title":"Tracee API","version":"1.0.0","summary":"Post to your channels, manage media and read results from code.","description":"Authenticate with a workspace key from Tracee (Settings → Workspace keys) as `Authorization: Bearer <key>`. Calls act as an agent named after the key: the workspace's guardrails and approval rules apply, and every change appears in the audit log. Errors share one shape: `{ \"error\": { \"code\", \"message\" } }`. Each key may make 120 requests a minute. This document is served at /api/v1/openapi.json.","contact":{"name":"Tracee","url":"https://www.traceeai.com/developers"},"license":{"name":"Proprietary","url":"https://www.traceeai.com/developers"}},"servers":[{"url":"https://www.traceeai.com/api/v1"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Account","description":"Check a key."},{"name":"Channels","description":"Where posts can go."},{"name":"Posts","description":"Draft, edit, publish and delete posts."},{"name":"Media","description":"Images and videos for posts."},{"name":"Approvals","description":"What waits for a person."},{"name":"Analytics","description":"What posts and campaigns brought in."}],"paths":{"/me":{"get":{"operationId":"getMe","tags":["Account"],"summary":"Check a key","description":"The workspace this key acts on and how it appears in the audit log. Use it to test a key.","parameters":[{"$ref":"#/components/parameters/Workspace"}],"responses":{"200":{"description":"The key works.","headers":{"X-RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left before the limit applies.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Seconds until the limit is fully restored.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/channels":{"get":{"operationId":"listChannels","tags":["Channels"],"summary":"List channels","description":"The social accounts posts can go to, with the id posts need.","parameters":[{"$ref":"#/components/parameters/Workspace"}],"responses":{"200":{"description":"The workspace's channels.","headers":{"X-RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left before the limit applies.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Seconds until the limit is fully restored.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChannelList"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/posts":{"get":{"operationId":"listPosts","tags":["Posts"],"summary":"List posts","description":"Posts, newest first. from and to filter by when a post goes (or went) out; drafts with no planned time are left out of a window.","parameters":[{"$ref":"#/components/parameters/Workspace"},{"name":"from","in":"query","description":"Start of the window: a date (2026-11-09) or an ISO 8601 date-time.","schema":{"type":"string"}},{"name":"to","in":"query","description":"End of the window (exclusive). A date means through the end of that day.","schema":{"type":"string"}},{"name":"status","in":"query","description":"One status or several separated by commas: draft, pending_approval, approved, rejected, scheduled, published, partially_published, failed, removed.","schema":{"type":"string"}},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"A page of posts.","headers":{"X-RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left before the limit applies.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Seconds until the limit is fully restored.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostList"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createPost","tags":["Posts"],"summary":"Create a post","description":"Creates a draft, one variant per channel. With publish it is also sent for publishing; if the workspace requires approval it waits in a person's inbox instead (publish.status is pending_approval).","parameters":[{"$ref":"#/components/parameters/Workspace"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePostRequest"}}}},"responses":{"201":{"description":"The draft, and what happened when it was sent.","headers":{"X-RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left before the limit applies.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Seconds until the limit is fully restored.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePostResult"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/posts/{postId}":{"parameters":[{"$ref":"#/components/parameters/PostId"},{"$ref":"#/components/parameters/Workspace"}],"get":{"operationId":"getPost","tags":["Posts"],"summary":"Get a post","description":"One post with its variants, statuses and publish results.","responses":{"200":{"description":"The post.","headers":{"X-RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left before the limit applies.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Seconds until the limit is fully restored.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Post"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"operationId":"updatePost","tags":["Posts"],"summary":"Edit a post","description":"Edits a post that hasn't gone out. Any approval or schedule is undone: it becomes a draft again.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePostRequest"}}}},"responses":{"200":{"description":"The edited post.","headers":{"X-RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left before the limit applies.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Seconds until the limit is fully restored.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Post"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"deletePost","tags":["Posts"],"summary":"Delete a post","description":"Deletes a post that never went out. Deleting through the API always asks a person first: the answer is 202 with the approval request.","parameters":[{"name":"note","in":"query","description":"Context for the person who approves it.","schema":{"type":"string","maxLength":500}}],"responses":{"200":{"description":"Deleted.","headers":{"X-RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left before the limit applies.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Seconds until the limit is fully restored.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResult"}}}},"202":{"description":"Waiting for a person's approval.","headers":{"X-RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left before the limit applies.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Seconds until the limit is fully restored.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResult"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/posts/{postId}/publish":{"parameters":[{"$ref":"#/components/parameters/PostId"},{"$ref":"#/components/parameters/Workspace"}],"post":{"operationId":"publishPost","tags":["Posts"],"summary":"Publish or schedule a post","description":"Publishes now, or at scheduledFor. If the workspace requires approval the post waits in a person's inbox (202) and goes out once approved.","requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishRequest"}}}},"responses":{"200":{"description":"Published, scheduled, or failed per channel.","headers":{"X-RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left before the limit applies.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Seconds until the limit is fully restored.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishResult"}}}},"202":{"description":"Waiting for a person's approval.","headers":{"X-RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left before the limit applies.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Seconds until the limit is fully restored.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishResult"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/media":{"get":{"operationId":"listMedia","tags":["Media"],"summary":"List media","description":"Images and videos in the workspace library, newest first.","parameters":[{"$ref":"#/components/parameters/Workspace"},{"name":"kind","in":"query","schema":{"type":"string","enum":["image","video"]}},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"A page of media.","headers":{"X-RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left before the limit applies.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Seconds until the limit is fully restored.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaList"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"uploadMedia","tags":["Media"],"summary":"Upload a file","description":"Uploads a JPG, PNG, GIF or WebP photo (up to 15 MB) or an MP4, MOV or WebM video (up to 100 MB). Send multipart/form-data with the file in a field named file, or the raw file as the body with its own Content-Type.","parameters":[{"$ref":"#/components/parameters/Workspace"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","contentMediaType":"application/octet-stream"},"altText":{"type":"string","maxLength":1000}},"required":["file"]}},"image/*":{"schema":{"type":"string","contentMediaType":"image/*"}},"video/*":{"schema":{"type":"string","contentMediaType":"video/*"}}}},"responses":{"201":{"description":"The stored file.","headers":{"X-RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left before the limit applies.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Seconds until the limit is fully restored.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Media"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/media/from-url":{"post":{"operationId":"addMediaFromUrl","tags":["Media"],"summary":"Add media from a link","description":"Copies an image from a public https link into the library, converted to a format every network takes. Videos stay links.","parameters":[{"$ref":"#/components/parameters/Workspace"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaFromUrlRequest"}}}},"responses":{"201":{"description":"The stored media.","headers":{"X-RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left before the limit applies.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Seconds until the limit is fully restored.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Media"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/approvals":{"get":{"operationId":"listApprovals","tags":["Approvals"],"summary":"List approval requests","description":"What is waiting for a person, or was decided, newest first. Approving happens in Tracee, by a person.","parameters":[{"$ref":"#/components/parameters/Workspace"},{"name":"status","in":"query","schema":{"type":"string","enum":["pending","approved","rejected","superseded"]}},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"A page of requests.","headers":{"X-RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left before the limit applies.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Seconds until the limit is fully restored.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApprovalList"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/analytics/performance":{"get":{"operationId":"getPerformance","tags":["Analytics"],"summary":"Performance report","description":"Ad spend per campaign joined to CRM contacts and MQLs, and contacts and MQLs per post, over the last N days.","parameters":[{"$ref":"#/components/parameters/Workspace"},{"name":"days","in":"query","description":"Window in days, ending today.","schema":{"type":"integer","minimum":1,"maximum":365,"default":30}}],"responses":{"200":{"description":"The report.","headers":{"X-RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left before the limit applies.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Seconds until the limit is fully restored.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PerformanceReport"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"A workspace key (Settings → Workspace keys), or an OAuth access token a Tracee MCP client received."}},"parameters":{"Workspace":{"name":"tracee-workspace","in":"header","required":false,"description":"Only for a person's token that belongs to several workspaces: the workspace id to act on. Workspace keys don't need it.","schema":{"type":"string","format":"uuid"}},"PostId":{"name":"postId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},"Limit":{"name":"limit","in":"query","description":"Items per page.","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},"Cursor":{"name":"cursor","in":"query","description":"nextCursor from the previous page.","schema":{"type":"string"}}},"responses":{"BadRequest":{"description":"The request isn't valid; details lists each problem.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"No key, or the key is invalid, expired or revoked.","headers":{"WWW-Authenticate":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"The workspace's guardrails don't allow this, or the key can't act on that workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"No such post in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Conflict":{"description":"The post's state doesn't allow it, e.g. it already went out.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"PayloadTooLarge":{"description":"The body or file is too big.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"UnsupportedMediaType":{"description":"A body or file type the endpoint doesn't take.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unprocessable":{"description":"Understood but refused: an unknown channel or media id, brand issues to fix first…","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Too many requests from this key.","headers":{"Retry-After":{"description":"Seconds to wait before trying again.","schema":{"type":"integer"}},"X-RateLimit-Limit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left before the limit applies.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Seconds until the limit is fully restored.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"InternalError":{"description":"Something went wrong on Tracee's side.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorObject"}},"required":["error"],"additionalProperties":false},"ErrorObject":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","unauthorized","forbidden","not_found","method_not_allowed","conflict","payload_too_large","unsupported_media_type","unprocessable","workspace_required","rate_limited","internal_error","unavailable"]},"message":{"type":"string","description":"Plain words, fit to show a person."},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string","description":"The field, e.g. variants.0.channelId."},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message"],"additionalProperties":false},"Me":{"type":"object","properties":{"workspace":{"oneOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false},{"type":"null"}]},"workspaces":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"current":{"type":"boolean"}},"required":["id","name","current"],"additionalProperties":false}},"credential":{"type":"object","properties":{"type":{"type":"string","enum":["api_key","oauth_token"]},"id":{"type":"string"},"name":{"type":["string","null"],"description":"The key's name."}},"required":["type","id","name"],"additionalProperties":false},"actor":{"type":"string","description":"How this key appears in the audit log and approvals inbox."},"rateLimit":{"type":"object","properties":{"limit":{"type":"integer"},"remaining":{"type":"integer"}},"required":["limit","remaining"],"additionalProperties":false}},"required":["workspace","workspaces","credential","actor","rateLimit"],"additionalProperties":false},"Channel":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"platform":{"type":"string","enum":["linkedin","facebook","instagram","x","tiktok","youtube","threads","pinterest","reddit","google_business","slack","discord","devto","hashnode","bluesky","mastodon","telegram","lemmy","nostr","wordpress","listmonk","medium","farcaster","twitch","kick","dribbble"]},"name":{"type":"string"},"provider":{"type":"string","description":"How Tracee publishes to it. dry_run sends nothing (for testing)."},"avatarUrl":{"type":["string","null"],"format":"uri"},"allowed":{"type":"boolean","description":"False when the workspace's guardrails keep agents and the API off it."}},"required":["id","platform","name","provider","avatarUrl","allowed"],"additionalProperties":false},"ChannelList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Channel"}}},"required":["data"],"additionalProperties":false},"MediaRef":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"url":{"type":"string","description":"Public link to the file.","format":"uri"},"kind":{"type":"string","enum":["image","video"]}},"required":["id","url","kind"],"additionalProperties":false},"ThreadPart":{"type":"object","properties":{"body":{"type":"string"},"mediaIds":{"type":"array","items":{"type":"string","format":"uuid"}},"delayMinutes":{"type":"integer"},"media":{"type":"array","items":{"$ref":"#/components/schemas/MediaRef"}}},"required":["body","mediaIds","delayMinutes","media"],"additionalProperties":false},"Variant":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"channelId":{"type":"string","format":"uuid"},"platform":{"type":"string","enum":["linkedin","facebook","instagram","x","tiktok","youtube","threads","pinterest","reddit","google_business","slack","discord","devto","hashnode","bluesky","mastodon","telegram","lemmy","nostr","wordpress","listmonk","medium","farcaster","twitch","kick","dribbble"]},"accountName":{"type":"string","description":"The channel's name."},"body":{"type":"string"},"linkUrl":{"type":["string","null"],"description":"The landing page with this channel's UTM tags."},"media":{"type":"array","items":{"$ref":"#/components/schemas/MediaRef"}},"brandIssues":{"type":"array","items":{"type":"string"},"description":"Brand-rule and platform problems. A post with any can't be published."},"status":{"type":"string","enum":["draft","queued","published","failed","removed"]},"platformPostId":{"type":["string","null"]},"platformPostUrl":{"type":["string","null"]},"publishedAt":{"type":["string","null"],"format":"date-time"},"error":{"type":["string","null"],"description":"Why publishing to this channel failed."},"settings":{"type":"object","additionalProperties":true,"description":"Platform options chosen for this channel."},"thread":{"type":"array","items":{"$ref":"#/components/schemas/ThreadPart"},"description":"The follow-up parts this channel sends."},"parts":{"type":"array","description":"What happened to each follow-up part once sent (position 1 is the first part).","items":{"type":"object","properties":{"position":{"type":"integer"},"status":{"type":"string"},"platformPostUrl":{"type":["string","null"]},"publishedAt":{"type":["string","null"],"format":"date-time"},"error":{"type":["string","null"]}},"required":["position","status","platformPostUrl","publishedAt","error"],"additionalProperties":false}}},"required":["id","channelId","platform","accountName","body","linkUrl","media","brandIssues","status","platformPostId","platformPostUrl","publishedAt","error","settings","thread","parts"],"additionalProperties":false},"Post":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"body":{"type":"string"},"linkUrl":{"type":["string","null"]},"utmCampaign":{"type":"string","description":"The utm_campaign every link in the post carries."},"status":{"type":"string","enum":["draft","pending_approval","approved","rejected","scheduled","published","partially_published","failed","removed"]},"scheduledFor":{"type":["string","null"],"format":"date-time"},"plannedFor":{"type":["string","null"],"format":"date-time"},"createdBy":{"type":"string","description":"Who made it: a person's email or an agent's name."},"createdVia":{"type":"string","enum":["agent","app"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"media":{"type":"array","items":{"$ref":"#/components/schemas/MediaRef"},"description":"The post's own media."},"thread":{"type":"array","items":{"$ref":"#/components/schemas/ThreadPart"},"description":"Follow-up parts every channel sends unless it has its own."},"repeat":{"oneOf":[{"type":"object","properties":{"everyDays":{"type":"integer"},"until":{"type":["string","null"],"format":"date-time"}},"required":["everyDays","until"],"additionalProperties":false},{"type":"null"}]},"repeatedFrom":{"type":["string","null"],"description":"The post this one is a repeat of.","format":"uuid"},"variants":{"type":"array","items":{"$ref":"#/components/schemas/Variant"},"description":"One per channel."}},"required":["id","title","body","linkUrl","utmCampaign","status","scheduledFor","plannedFor","createdBy","createdVia","createdAt","updatedAt","media","thread","repeat","repeatedFrom","variants"],"additionalProperties":false},"PostList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Post"}},"nextCursor":{"type":["string","null"],"description":"Pass as `cursor` to get the next page; null on the last page."}},"required":["data","nextCursor"],"additionalProperties":false,"description":"A page of posts, newest first."},"VariantInput":{"type":"object","properties":{"channelId":{"type":"string","description":"A channel id from GET /channels.","format":"uuid"},"body":{"type":"string","description":"This channel's own copy. Defaults to the post's body.","minLength":1,"maxLength":20000},"mediaIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":20,"description":"This channel's own media. Defaults to the post's mediaIds."},"settings":{"type":"object","additionalProperties":true,"description":"Platform options. youtube {title, privacy: public|unlisted|private, tags[]}, tiktok {privacy, allowComments, allowDuet, allowStitch, brandedContent, aiGenerated}, instagram {postType: feed|reel|story, shareToFeed}, x {replySettings: everyone|following|mentionedUsers}, linkedin {visibility: PUBLIC|CONNECTIONS}, threads {topicTag}, pinterest {title}, reddit {title, flairId}, google_business {button}, devto {tags[], canonicalUrl, series}, hashnode {subtitle, tags[], canonicalUrl}, bluesky {replies: everyone|following|mentioned|nobody, language}, mastodon {visibility: public|unlisted|private, spoiler, sensitive}, telegram {silent, noPreview, protect}, lemmy {nsfw, language}, wordpress {status: publish|draft|pending|private, excerpt, tags[], categories[], slug}, listmonk {lists[], send: now|draft, fromEmail}, medium {status: public|unlisted|draft, tags[], canonicalUrl}, farcaster {channel}. Unknown keys are dropped."},"thread":{"type":"array","items":{"$ref":"#/components/schemas/ThreadPartInput"},"maxItems":25,"description":"This channel's own follow-up parts, instead of the post's thread."}},"required":["channelId"],"additionalProperties":false},"ThreadPartInput":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":20000},"mediaIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":4,"description":"Photos, where the platform takes them on a reply or comment."},"delayMinutes":{"type":"integer","minimum":0,"maximum":1440,"default":0,"description":"Minutes to wait after the part before it."}},"required":["body"],"additionalProperties":false},"RepeatInput":{"type":"object","properties":{"everyDays":{"type":"integer","minimum":1,"maximum":365},"until":{"type":["string","null"],"description":"Stop repeating after this time.","format":"date-time"}},"required":["everyDays"],"additionalProperties":false,"description":"Publish it again every N days once it went out."},"CreatePostRequest":{"type":"object","properties":{"title":{"type":"string","description":"Internal name for the post. Defaults to the first line of body.","minLength":1,"maxLength":200},"body":{"type":"string","description":"The copy. Each channel uses it unless its variant has its own.","minLength":1,"maxLength":20000},"linkUrl":{"type":["string","null"],"description":"Landing page. Tracee adds UTM tags per channel so contacts are traced back to the post. null removes it.","format":"uri","maxLength":2000},"channels":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":50,"description":"Channel ids to post to with the post's copy and media. Shorthand for variants."},"variants":{"type":"array","items":{"$ref":"#/components/schemas/VariantInput"},"maxItems":50,"description":"One per channel, when a channel needs its own copy or media."},"mediaIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":20,"description":"Media ids (from POST /media) for every channel that doesn't set its own."},"plannedFor":{"type":["string","null"],"description":"When the post is meant to go out: its slot on the calendar. Queues nothing.","format":"date-time"},"thread":{"type":"array","items":{"$ref":"#/components/schemas/ThreadPartInput"},"maxItems":25,"description":"Follow-up parts every channel sends unless it has its own: replies on X and Threads, comments on LinkedIn, Facebook, Instagram, YouTube and Reddit (e.g. the link in the first comment)."},"repeat":{"oneOf":[{"$ref":"#/components/schemas/RepeatInput"},{"type":"null"}]},"publish":{"description":"\"now\" to publish straight away, or an ISO 8601 date-time to schedule it. Approval rules apply.","anyOf":[{"type":"string","enum":["now"]},{"type":"string","format":"date-time"}]},"note":{"type":"string","description":"Context for the person who approves it.","maxLength":500}},"required":["body"],"additionalProperties":false},"CreatePostResult":{"type":"object","properties":{"post":{"$ref":"#/components/schemas/Post"},"publish":{"oneOf":[{"$ref":"#/components/schemas/PublishResult"},{"type":"null"}]},"publishError":{"oneOf":[{"$ref":"#/components/schemas/ErrorObject"},{"type":"null"}]}},"required":["post","publish","publishError"],"additionalProperties":false},"UpdatePostRequest":{"type":"object","properties":{"title":{"type":"string","description":"Internal name for the post. Defaults to the first line of body.","minLength":1,"maxLength":200},"body":{"type":"string","description":"The copy. Each channel uses it unless its variant has its own.","minLength":1,"maxLength":20000},"linkUrl":{"type":["string","null"],"description":"Landing page. Tracee adds UTM tags per channel so contacts are traced back to the post. null removes it.","format":"uri","maxLength":2000},"channels":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":50,"description":"Channel ids to post to with the post's copy and media. Shorthand for variants."},"variants":{"type":"array","items":{"$ref":"#/components/schemas/VariantInput"},"maxItems":50,"description":"One per channel, when a channel needs its own copy or media."},"mediaIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":20,"description":"Media ids (from POST /media) for every channel that doesn't set its own."},"plannedFor":{"type":["string","null"],"description":"When the post is meant to go out: its slot on the calendar. Queues nothing.","format":"date-time"},"thread":{"type":"array","items":{"$ref":"#/components/schemas/ThreadPartInput"},"maxItems":25,"description":"Follow-up parts every channel sends unless it has its own: replies on X and Threads, comments on LinkedIn, Facebook, Instagram, YouTube and Reddit (e.g. the link in the first comment)."},"repeat":{"oneOf":[{"$ref":"#/components/schemas/RepeatInput"},{"type":"null"}]}},"required":[],"additionalProperties":false,"minProperties":1,"description":"Fields to change. channels or variants replace the post's channels. Editing undoes any approval or schedule: the post is a draft again."},"PublishRequest":{"type":"object","properties":{"scheduledFor":{"type":"string","description":"Publish at this time instead of now. Must be in the future.","format":"date-time"},"note":{"type":"string","description":"Context for the person who approves it.","maxLength":500}},"required":[],"additionalProperties":false},"PublishResult":{"type":"object","properties":{"status":{"type":"string","enum":["pending_approval","scheduled","published","partially_published","failed"],"description":"pending_approval: waiting in a person's approval inbox; it publishes once approved."},"approvalRequestId":{"type":["string","null"],"description":"Set when status is pending_approval.","format":"uuid"},"message":{"type":["string","null"]},"post":{"$ref":"#/components/schemas/Post"}},"required":["status","approvalRequestId","message","post"],"additionalProperties":false},"DeleteResult":{"type":"object","properties":{"status":{"type":"string","enum":["deleted","pending_approval"]},"approvalRequestId":{"type":["string","null"],"format":"uuid"},"message":{"type":["string","null"]},"postId":{"type":"string","format":"uuid"}},"required":["status","approvalRequestId","message","postId"],"additionalProperties":false},"Media":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"url":{"type":"string","description":"Public link to the file, for attaching and previewing.","format":"uri"},"kind":{"type":"string","enum":["image","video"]},"mimeType":{"type":"string"},"bytes":{"type":["integer","null"]},"name":{"type":["string","null"]},"altText":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"}},"required":["id","url","kind","mimeType","bytes","name","altText","createdAt"],"additionalProperties":false},"MediaList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Media"}},"nextCursor":{"type":["string","null"],"description":"Pass as `cursor` to get the next page; null on the last page."}},"required":["data","nextCursor"],"additionalProperties":false,"description":"A page of media, newest first."},"MediaFromUrlRequest":{"type":"object","properties":{"url":{"type":"string","description":"A public https link to an image or video.","format":"uri","maxLength":2000},"altText":{"type":"string","maxLength":1000},"name":{"type":"string","maxLength":200}},"required":["url"],"additionalProperties":false},"Approval":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["publish_post","delete_post","unpublish_post","app_action","inbox_reply"]},"postId":{"type":["string","null"],"format":"uuid"},"summary":{"type":"string"},"status":{"type":"string","enum":["pending","approved","rejected","superseded"]},"requestedBy":{"type":"string"},"requestedVia":{"type":"string","enum":["agent","app"]},"createdAt":{"type":"string","format":"date-time"},"decidedBy":{"type":["string","null"]},"decidedAt":{"type":["string","null"],"format":"date-time"},"decisionNote":{"type":["string","null"]},"result":{"description":"What running it returned, once decided."}},"required":["id","kind","postId","summary","status","requestedBy","requestedVia","createdAt","decidedBy","decidedAt","decisionNote","result"],"additionalProperties":false},"ApprovalList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Approval"}},"nextCursor":{"type":["string","null"],"description":"Pass as `cursor` to get the next page; null on the last page."}},"required":["data","nextCursor"],"additionalProperties":false,"description":"A page of approval requests, newest first."},"PerformanceReport":{"type":"object","properties":{"window":{"type":"object","properties":{"from":{"type":"string","format":"date"},"to":{"type":"string","format":"date"},"days":{"type":"integer"}},"required":["from","to","days"],"additionalProperties":false},"totals":{"type":"object","properties":{"spend":{"type":"number"},"crmContacts":{"type":"integer"},"crmMqls":{"type":"integer"},"attributedContacts":{"type":"integer"},"attributedMqls":{"type":"integer"},"unattributedContacts":{"type":"integer"}},"required":["spend","crmContacts","crmMqls","attributedContacts","attributedMqls","unattributedContacts"],"additionalProperties":false},"campaigns":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"platform":{"type":"string","enum":["meta","google","linkedin","tiktok","reddit","pinterest"]},"spend":{"type":"number"},"clicks":{"type":"integer"},"impressions":{"type":"integer"},"platformReportedLeads":{"type":"integer"},"crmContacts":{"type":"integer"},"crmMqls":{"type":"integer"},"costPerContact":{"type":["number","null"]},"costPerMql":{"type":["number","null"]}},"required":["id","name","platform","spend","clicks","impressions","platformReportedLeads","crmContacts","crmMqls","costPerContact","costPerMql"],"additionalProperties":false}},"posts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"utmCampaign":{"type":"string"},"status":{"type":"string","enum":["draft","pending_approval","approved","rejected","scheduled","published","partially_published","failed","removed"]},"createdAt":{"type":"string","format":"date-time"},"crmContacts":{"type":"integer"},"crmMqls":{"type":"integer"}},"required":["id","title","utmCampaign","status","createdAt","crmContacts","crmMqls"],"additionalProperties":false}}},"required":["window","totals","campaigns","posts"],"additionalProperties":false}}}}