{"openapi":"3.0.0","info":{"title":"PostPeer API","description":"Cross-platform social media posting API","version":"1.0.0"},"components":{"securitySchemes":{"accessKey":{"type":"apiKey","in":"header","name":"x-access-key"}},"schemas":{"Platform":{"type":"string","enum":["twitter","instagram","youtube","tiktok","pinterest","linkedin","bluesky"]},"Status":{"type":"string","enum":["draft","pending","scheduled","publishing","published","failed","partial"]},"SortOrder":{"type":"string","enum":["asc","desc"]},"ErrorResponse":{"type":"object","required":["success","message"],"properties":{"success":{"type":"boolean"},"message":{"type":"string"}}},"PostPayload":{"additionalProperties":false,"type":"object","required":["content","platforms"],"properties":{"content":{"description":"Post text body","type":"string"},"mediaItems":{"description":"Media attachments (images, videos, GIFs)","type":"array","items":{"additionalProperties":false,"type":"object","required":["type","url"],"properties":{"type":{"type":"string","enum":["image","video","gif"]},"url":{"format":"uri","type":"string"},"thumbnail":{"format":"uri","description":"Thumbnail image URL for video items. Supported on YouTube regular videos (not Shorts). JPEG, PNG, or GIF, max 2 MB, min 640 px wide.","type":"string"}}}},"platforms":{"minItems":1,"description":"Target platform accounts to publish to","type":"array","items":{"additionalProperties":false,"type":"object","required":["platform","accountId"],"properties":{"platform":{"type":"string","enum":["twitter","instagram","youtube","tiktok","pinterest","linkedin","bluesky"]},"accountId":{"description":"Integration._id — find yours via GET /connect/integrations","type":"string"},"platformSpecificData":{"type":"object","additionalProperties":true,"description":"Platform-specific options. See TwitterConfigurations, YouTubeConfigurations, TikTokConfigurations, PinterestConfigurations, or LinkedInConfigurations in the schema reference for available fields per platform."}}}},"publishNow":{"description":"Publish immediately. Required when scheduledFor is omitted.","type":"boolean"},"scheduledFor":{"format":"date-time","description":"ISO 8601 datetime to schedule the post for future publishing","type":"string"},"timezone":{"description":"IANA timezone for the scheduled time (e.g. America/New_York). Defaults to UTC.","type":"string"}}},"TwitterConfigurations":{"additionalProperties":false,"description":"Pass this object in platformSpecificData when posting to Twitter/X, including Community post options.","type":"object","properties":{"communityId":{"description":"Community ID to publish this post into.","type":"string"},"shareWithFollowers":{"description":"When posting to a Community, also share the post with followers.","type":"boolean"},"replyToTweetId":{"description":"Tweet ID to reply to.","type":"string"},"replySettings":{"type":"string","enum":["following","mentionedUsers","subscribers","verified"]},"threadItems":{"description":"Additional tweets to chain as a thread. The root tweet uses post.content.","type":"array","items":{"additionalProperties":false,"type":"object","required":["content"],"properties":{"content":{"description":"Text of this thread tweet (max 280 chars)","type":"string"},"mediaItems":{"type":"array","items":{"additionalProperties":false,"type":"object","required":["type","url"],"properties":{"type":{"type":"string","enum":["image","video","gif"]},"url":{"format":"uri","type":"string"},"thumbnail":{"format":"uri","description":"Thumbnail image URL for video items. Supported on YouTube regular videos (not Shorts). JPEG, PNG, or GIF, max 2 MB, min 640 px wide.","type":"string"}}}}}}},"poll":{"additionalProperties":false,"description":"Cannot be combined with media or threadItems.","type":"object","required":["options","durationMinutes"],"properties":{"options":{"minItems":2,"maxItems":4,"description":"2–4 poll options.","type":"array","items":{"type":"string"}},"durationMinutes":{"minimum":5,"maximum":10080,"description":"Poll duration in minutes (5 min – 7 days).","type":"number"}}}}},"YouTubeConfigurations":{"additionalProperties":false,"description":"Pass this object in platformSpecificData when posting to YouTube.","type":"object","properties":{"title":{"maxLength":100,"description":"Video title (max 100 chars, no < or >). Defaults to first 100 chars of content, or \"Untitled Video\".","type":"string"},"tags":{"description":"Video tags. Total characters across all tags must be ≤500.","type":"array","items":{"type":"string"}},"visibility":{"type":"string","enum":["public","private","unlisted"],"description":"Who can see the video. Defaults to \"public\". Scheduled posts upload as private and flip to this value at publish time."},"madeForKids":{"description":"COPPA compliance flag. Setting to true permanently disables comments, notification bell, personalized ads, end screens, and cards on the video. Defaults to false.","type":"boolean"},"containsSyntheticMedia":{"description":"AI-generated content disclosure. YouTube is increasingly enforcing this requirement. Defaults to false.","type":"boolean"},"categoryId":{"description":"YouTube category ID. Defaults to \"22\" (People & Blogs). Common values: \"1\" Film & Animation, \"10\" Music, \"20\" Gaming, \"22\" People & Blogs, \"27\" Education, \"28\" Science & Technology.","type":"string"},"firstComment":{"maxLength":10000,"description":"Auto-posted comment after the video goes live. Max 10,000 characters. For publishNow posts: posted immediately after upload. For scheduled posts: posted when the video becomes public.","type":"string"}}},"TikTokConfigurations":{"additionalProperties":false,"description":"Pass this object in platformSpecificData when posting to TikTok.","type":"object","properties":{"privacyLevel":{"type":"string","enum":["PUBLIC_TO_EVERYONE","MUTUAL_FOLLOW_FRIENDS","FOLLOWER_OF_CREATOR","SELF_ONLY"],"description":"Who can see this post. Defaults to \"SELF_ONLY\" (required for unreviewed apps). Upgrade to PUBLIC_TO_EVERYONE after TikTok app review."},"disableComment":{"description":"Disable comments on this post. Defaults to false.","type":"boolean"},"disableDuet":{"description":"Disable duet for this video. Videos only. Defaults to false.","type":"boolean"},"disableStitch":{"description":"Disable stitch for this video. Videos only. Defaults to false.","type":"boolean"},"brandContentToggle":{"description":"Mark as branded content (paid partnership). Defaults to false.","type":"boolean"},"brandOrganicToggle":{"description":"Mark as organic brand promotion. Defaults to false.","type":"boolean"},"isAigc":{"description":"AI-generated content disclosure. Defaults to false.","type":"boolean"},"videoCoverTimestampMs":{"description":"Timestamp in milliseconds to use as the video cover frame. Videos only. Defaults to 1000ms.","type":"number"},"autoAddMusic":{"description":"Automatically add background music to photo carousels. Photo posts only. Defaults to true.","type":"boolean"},"photoCoverIndex":{"minimum":0,"description":"0-indexed position of the cover image in a photo carousel. Photo posts only. Defaults to 0.","type":"number"},"draft":{"description":"When true (default), sends content to the creator's TikTok inbox as a draft. Set to false to publish immediately (requires an audited app).","type":"boolean"}}},"PinterestConfigurations":{"additionalProperties":false,"description":"Pass this object in platformSpecificData when posting to Pinterest.","type":"object","required":["boardId"],"properties":{"boardId":{"description":"Target board ID. Retrieve available boards via GET /v1/pinterest/boards.","type":"string"},"title":{"maxLength":100,"description":"Pin title. Max 100 characters. Defaults to first line of content.","type":"string"},"link":{"format":"uri","description":"HTTPS destination URL when the pin is clicked. Important for driving traffic.","type":"string"},"altText":{"maxLength":500,"description":"Accessible image description. Max 500 characters.","type":"string"},"dominantColor":{"description":"Hex color for the loading placeholder (e.g. \"#6E7874\").","type":"string"},"coverImageUrl":{"format":"uri","description":"Custom cover image URL for video pins.","type":"string"}}},"LinkedInConfigurations":{"additionalProperties":false,"description":"Pass this object in platformSpecificData when posting to LinkedIn.","type":"object","properties":{"visibility":{"type":"string","enum":["PUBLIC","CONNECTIONS"],"description":"Post visibility. \"PUBLIC\" = visible to everyone, \"CONNECTIONS\" = visible to connections only. Defaults to \"PUBLIC\"."},"articleUrl":{"format":"uri","description":"URL for an article/link post. When provided, the post becomes a link share with a preview card.","type":"string"},"articleTitle":{"maxLength":400,"description":"Title for the article preview card. Max 400 characters.","type":"string"},"articleDescription":{"maxLength":400,"description":"Description for the article preview card. Max 400 characters.","type":"string"}}},"BlueskyConfigurations":{"additionalProperties":false,"description":"Pass this object in platformSpecificData when posting to Bluesky.","type":"object","properties":{"langs":{"description":"BCP-47 language tags for the post (e.g. [\"en\"], [\"en-US\", \"es\"]). Defaults to [\"en\"].","type":"array","items":{"type":"string"}},"altText":{"description":"Alt text for each image, in the same order as mediaItems. Strongly encouraged for accessibility.","type":"array","items":{"type":"string"}}}}}},"paths":{"/v1/health":{"get":{"operationId":"healthCheck","summary":"Health check","tags":["Health"],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["ok"],"properties":{"ok":{"type":"boolean"}}}}}}}}},"/v1/health/auth":{"get":{"operationId":"healthCheckAuth","summary":"Verify that the provided access key is valid","tags":["Health"],"security":[{"accessKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["ok"],"properties":{"ok":{"type":"boolean"}}}}}}}}},"/v1/connect/{platform}":{"get":{"operationId":"getOAuthUrl","summary":"Get OAuth URL for a platform","tags":["Connect"],"parameters":[{"schema":{"format":"uri","type":"string"},"in":"query","name":"redirectUri","required":false,"description":"URL to redirect to after a successful connection"},{"schema":{"type":"string","enum":["twitter","instagram","youtube","tiktok","pinterest","linkedin","bluesky"]},"in":"path","name":"platform","required":true}],"security":[{"accessKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string"}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}}}}}}}},"/v1/connect/bluesky/auth":{"post":{"operationId":"connectBluesky","summary":"Connect a Bluesky account via app password","tags":["Connect"],"description":"Bluesky has no OAuth redirect. Have the user generate an app password at https://bsky.app/settings/app-passwords, then submit it here.","requestBody":{"required":true,"content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","required":["identifier","password"],"properties":{"identifier":{"description":"Bluesky handle (e.g. \"alice.bsky.social\") or DID (e.g. \"did:plc:abc123\").","type":"string"},"password":{"description":"An app password generated at https://bsky.app/settings/app-passwords. Do NOT use the account password.","type":"string"}}}}}},"parameters":[{"schema":{"format":"uri","type":"string"},"in":"query","name":"redirectUri","required":false,"description":"URL to redirect to after a successful connection"}],"security":[{"accessKey":[]}],"responses":{"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}}}}}}}},"/v1/connect/integrations":{"get":{"operationId":"listIntegrations","summary":"List all integrations connected to this project","tags":["Connect"],"security":[{"accessKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","integrations"],"properties":{"success":{"type":"boolean"},"integrations":{"type":"array","items":{"type":"object","required":["id","platform","platformUserId","displayName","imageUrl","createdAt"],"properties":{"id":{"description":"Use this as accountId when creating posts","type":"string"},"platform":{"type":"string","enum":["twitter","instagram","youtube","tiktok","pinterest","linkedin","bluesky"]},"platformUserId":{"type":"string","nullable":true,"description":"The user ID on the platform, or null if not yet retrieved"},"displayName":{"type":"string","nullable":true,"description":"Display name of the connected account (e.g. @handle or channel name)"},"imageUrl":{"type":"string","format":"uri","nullable":true,"description":"Profile image URL for the connected account, or null if unavailable"},"createdAt":{"format":"date-time","type":"string"}}}}}}}}}}}},"/v1/connect/integrations/{id}":{"delete":{"operationId":"disconnectIntegration","summary":"Disconnect a platform integration","tags":["Connect"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true,"description":"Integration ID to disconnect"}],"security":[{"accessKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","message"],"properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}}}}}}}},"/v1/platforms":{"get":{"operationId":"listPlatforms","summary":"List available platforms and their status","tags":["Platforms"],"security":[{"accessKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["platforms"],"properties":{"platforms":{"type":"array","items":{"type":"object","required":["name","status"],"properties":{"name":{"type":"string","enum":["twitter","instagram","youtube","tiktok","pinterest","linkedin","bluesky"]},"status":{"type":"string","enum":["prod","beta","dev"]}}}}}}}}}}}},"/v1/posts/":{"post":{"operationId":"createPost","summary":"Publish a post to one or more social media platforms","tags":["Posts"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","required":["content","platforms"],"properties":{"content":{"description":"Post text body","type":"string"},"mediaItems":{"description":"Media attachments (images, videos, GIFs)","type":"array","items":{"additionalProperties":false,"type":"object","required":["type","url"],"properties":{"type":{"type":"string","enum":["image","video","gif"]},"url":{"format":"uri","type":"string"},"thumbnail":{"format":"uri","description":"Thumbnail image URL for video items. Supported on YouTube regular videos (not Shorts). JPEG, PNG, or GIF, max 2 MB, min 640 px wide.","type":"string"}}}},"platforms":{"minItems":1,"description":"Target platform accounts to publish to","type":"array","items":{"additionalProperties":false,"type":"object","required":["platform","accountId"],"properties":{"platform":{"type":"string","enum":["twitter","instagram","youtube","tiktok","pinterest","linkedin","bluesky"]},"accountId":{"description":"Integration._id — find yours via GET /connect/integrations","type":"string"},"platformSpecificData":{"type":"object","additionalProperties":true,"description":"Platform-specific options. See TwitterConfigurations, YouTubeConfigurations, TikTokConfigurations, PinterestConfigurations, or LinkedInConfigurations in the schema reference for available fields per platform."}}}},"publishNow":{"description":"Publish immediately. Required when scheduledFor is omitted.","type":"boolean"},"scheduledFor":{"format":"date-time","description":"ISO 8601 datetime to schedule the post for future publishing","type":"string"},"timezone":{"description":"IANA timezone for the scheduled time (e.g. America/New_York). Defaults to UTC.","type":"string"}}},"example":{"content":"Hello world!","platforms":[{"platform":"twitter","accountId":"<your-account-id>"}],"publishNow":true}}}},"security":[{"accessKey":[]}],"responses":{"202":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","status","postId","platforms"],"properties":{"success":{"description":"false only when every platform failed","type":"boolean"},"status":{"type":"string","enum":["draft","pending","scheduled","publishing","published","failed","partial"]},"scheduledFor":{"format":"date-time","description":"ISO 8601 datetime the post is scheduled for (only present for scheduled posts)","type":"string"},"postId":{"description":"id of the saved Post document","type":"string"},"platforms":{"type":"array","items":{"type":"object","required":["platform","success"],"properties":{"platform":{"type":"string","enum":["twitter","instagram","youtube","tiktok","pinterest","linkedin","bluesky"]},"success":{"type":"boolean"},"platformPostUrl":{"description":"Direct URL to the published post","type":"string"},"error":{"description":"Error message when success is false","type":"string"}}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","message"],"properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}},"402":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","message"],"properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","message"],"properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}},"503":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","message"],"properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}}}},"get":{"operationId":"listPosts","summary":"List all posts for the project","tags":["Posts"],"description":"Returns a paginated list of posts. Filter by status, platform (OR logic), and date ranges. Published posts include platformPostUrl per platform.","parameters":[{"schema":{"type":"string","enum":["draft","pending","scheduled","publishing","published","failed","partial"]},"in":"query","name":"status","required":false},{"schema":{"type":"array","items":{"type":"string","enum":["twitter","instagram","youtube","tiktok","pinterest","linkedin","bluesky"]}},"in":"query","name":"platform","required":false,"description":"Filter by platform (repeatable — OR logic)"},{"schema":{"format":"date-time","type":"string"},"in":"query","name":"createdAfter","required":false,"description":"ISO 8601 lower bound on createdAt"},{"schema":{"format":"date-time","type":"string"},"in":"query","name":"createdBefore","required":false,"description":"ISO 8601 upper bound on createdAt"},{"schema":{"format":"date-time","type":"string"},"in":"query","name":"scheduledAfter","required":false,"description":"ISO 8601 lower bound on scheduledFor"},{"schema":{"format":"date-time","type":"string"},"in":"query","name":"scheduledBefore","required":false,"description":"ISO 8601 upper bound on scheduledFor"},{"schema":{"minimum":1,"maximum":100,"default":20,"type":"integer"},"in":"query","name":"limit","required":false,"description":"Page size (max 100)"},{"schema":{"minimum":0,"default":0,"type":"integer"},"in":"query","name":"offset","required":false,"description":"Number of posts to skip"},{"schema":{"$ref":"#/components/schemas/SortOrder"},"in":"query","name":"sort","required":false}],"security":[{"accessKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","total","posts"],"properties":{"success":{"type":"boolean"},"total":{"minimum":0,"description":"Total matched posts across all pages","type":"integer"},"posts":{"type":"array","items":{"type":"object","required":["postId","content","status","scheduledFor","timezone","mediaItems","platforms","crosspostingEnabled","rawRequestBody","createdAt","updatedAt"],"properties":{"postId":{"description":"MongoDB ObjectId of the Post document","type":"string"},"content":{"type":"string"},"status":{"type":"string","enum":["draft","pending","scheduled","publishing","published","failed","partial"]},"scheduledFor":{"type":"string","format":"date-time","nullable":true,"description":"ISO 8601 scheduled datetime"},"timezone":{"type":"string"},"mediaItems":{"type":"array","items":{"type":"object","required":["type","url","filename","size","mimeType"],"properties":{"type":{"type":"string","enum":["image","video","gif"]},"url":{"type":"string"},"filename":{"type":"string"},"size":{"type":"number"},"mimeType":{"type":"string"}}}},"platforms":{"type":"array","items":{"type":"object","required":["platform","status","platformPostId","platformPostUrl","publishedAt","errorMessage"],"properties":{"platform":{"type":"string","enum":["twitter","instagram","youtube","tiktok","pinterest","linkedin","bluesky"]},"status":{"type":"string","enum":["draft","pending","scheduled","publishing","published","failed","partial"]},"platformPostId":{"type":"string","nullable":true},"platformPostUrl":{"type":"string","nullable":true,"description":"Direct URL to the published post"},"publishedAt":{"type":"string","format":"date-time","nullable":true},"errorMessage":{"type":"string","nullable":true}}}},"crosspostingEnabled":{"type":"boolean"},"rawRequestBody":{"type":"object","additionalProperties":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","message"],"properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}}}}},"/v1/posts/{postId}":{"get":{"operationId":"getPost","summary":"Get a single post by ID","tags":["Posts"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"postId","required":true,"description":"Post identifier"}],"security":[{"accessKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","post"],"properties":{"success":{"type":"boolean"},"post":{"type":"object","required":["postId","content","status","scheduledFor","timezone","mediaItems","platforms","crosspostingEnabled","rawRequestBody","createdAt","updatedAt"],"properties":{"postId":{"description":"MongoDB ObjectId of the Post document","type":"string"},"content":{"type":"string"},"status":{"type":"string","enum":["draft","pending","scheduled","publishing","published","failed","partial"]},"scheduledFor":{"type":"string","format":"date-time","nullable":true,"description":"ISO 8601 scheduled datetime"},"timezone":{"type":"string"},"mediaItems":{"type":"array","items":{"type":"object","required":["type","url","filename","size","mimeType"],"properties":{"type":{"type":"string","enum":["image","video","gif"]},"url":{"type":"string"},"filename":{"type":"string"},"size":{"type":"number"},"mimeType":{"type":"string"}}}},"platforms":{"type":"array","items":{"type":"object","required":["platform","status","platformPostId","platformPostUrl","publishedAt","errorMessage"],"properties":{"platform":{"type":"string","enum":["twitter","instagram","youtube","tiktok","pinterest","linkedin","bluesky"]},"status":{"type":"string","enum":["draft","pending","scheduled","publishing","published","failed","partial"]},"platformPostId":{"type":"string","nullable":true},"platformPostUrl":{"type":"string","nullable":true,"description":"Direct URL to the published post"},"publishedAt":{"type":"string","format":"date-time","nullable":true},"errorMessage":{"type":"string","nullable":true}}}},"crosspostingEnabled":{"type":"boolean"},"rawRequestBody":{"type":"object","additionalProperties":true},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","message"],"properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}}}},"delete":{"operationId":"deletePost","summary":"Delete a post by ID","tags":["Posts"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"postId","required":true,"description":"Post identifier"}],"security":[{"accessKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","required":["success"],"properties":{"success":{"type":"boolean"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","message"],"properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}}}}},"/v1/posts/scheduled/":{"get":{"operationId":"listScheduledPosts","summary":"List all scheduled posts","tags":["Schedule"],"security":[{"accessKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","posts"],"properties":{"success":{"type":"boolean"},"posts":{"type":"array","items":{"type":"object","required":["postId","content","scheduledFor","timezone","platforms","createdAt"],"properties":{"postId":{"description":"MongoDB ObjectId of the Post document","type":"string"},"content":{"description":"Post text body","type":"string"},"scheduledFor":{"type":"string","format":"date-time","nullable":true,"description":"ISO 8601 scheduled datetime"},"timezone":{"description":"IANA timezone for the scheduled time","type":"string"},"mediaItems":{"description":"Media attachments","type":"array","items":{"additionalProperties":false,"type":"object","required":["type","url"],"properties":{"type":{"type":"string","enum":["image","video","gif"]},"url":{"format":"uri","type":"string"},"thumbnail":{"format":"uri","description":"Thumbnail image URL for video items. Supported on YouTube regular videos (not Shorts). JPEG, PNG, or GIF, max 2 MB, min 640 px wide.","type":"string"}}}},"platforms":{"type":"array","items":{"type":"object","required":["platform","status"],"properties":{"platform":{"type":"string","enum":["twitter","instagram","youtube","tiktok","pinterest","linkedin","bluesky"]},"status":{"type":"string","enum":["draft","pending","scheduled","publishing","published","failed","partial"]}}}},"createdAt":{"format":"date-time","type":"string"}}}}}}}}}}}},"/v1/posts/scheduled/{postId}":{"delete":{"operationId":"cancelScheduledPost","summary":"Cancel a scheduled post (moves it back to draft)","tags":["Schedule"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"postId","required":true}],"security":[{"accessKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","message"],"properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","message"],"properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","message"],"properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}}}},"patch":{"operationId":"reschedulePost","summary":"Reschedule a post to a new time","tags":["Schedule"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["scheduledFor"],"properties":{"scheduledFor":{"format":"date-time","description":"New ISO 8601 datetime to schedule the post","type":"string"},"timezone":{"description":"IANA timezone","type":"string"}}}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"postId","required":true}],"security":[{"accessKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","message","scheduledFor"],"properties":{"success":{"type":"boolean"},"message":{"type":"string"},"scheduledFor":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","message"],"properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","message"],"properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}},"503":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","message"],"properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}}}}},"/v1/media/upload":{"post":{"operationId":"createMediaUpload","summary":"Get a presigned S3 URL to upload a media file","tags":["Media"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"additionalProperties":false,"type":"object","required":["filename","mimeType"],"properties":{"filename":{"minLength":1,"type":"string"},"mimeType":{"minLength":1,"type":"string"}}}}}},"security":[{"accessKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","required":["uploadUrl","publicUrl"],"properties":{"uploadUrl":{"type":"string"},"publicUrl":{"type":"string"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","message"],"properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}}}}},"/v1/analytics/":{"get":{"operationId":"getAnalytics","summary":"Get post analytics","tags":["Analytics"],"description":"With postId, returns analytics for a single post. Without postId, returns a paginated list of published posts with analytics. Accepts both PostPeer post IDs and external platform post IDs (auto-resolved). fromDate defaults to 90 days ago if omitted, max range 366 days. Each call costs 1 credit.","parameters":[{"schema":{"type":"string"},"in":"query","name":"postId","required":false,"description":"PostPeer post ID or external platform post ID (auto-resolved). When omitted, returns a paginated list of all published posts with analytics."},{"schema":{"type":"string","enum":["twitter","instagram","youtube","tiktok","pinterest","linkedin","bluesky"]},"in":"query","name":"platform","required":false},{"schema":{"type":"string"},"in":"query","name":"accountId","required":false,"description":"Integration ID. Required for external ID lookups and source=platform."},{"schema":{"type":"string","enum":["postpeer","platform"]},"in":"query","name":"source","required":false,"description":"Where the result came from. \"postpeer\" = posts published via PostPeer (stored in our DB). \"platform\" = fetched directly from the connected platform account."},{"schema":{"format":"date","type":"string"},"in":"query","name":"fromDate","required":false,"description":"Inclusive start date (YYYY-MM-DD). Defaults to 90 days ago."},{"schema":{"format":"date","type":"string"},"in":"query","name":"toDate","required":false,"description":"Inclusive end date (YYYY-MM-DD). Defaults to today."},{"schema":{"type":"string","enum":["date","likes","comments","impressions","views","shares","saves","clicks","engagement"],"default":"date"},"in":"query","name":"sortBy","required":false,"description":"Sort results by this metric"},{"schema":{"$ref":"#/components/schemas/SortOrder"},"in":"query","name":"order","required":false},{"schema":{"minimum":1,"maximum":100,"default":50,"type":"integer"},"in":"query","name":"limit","required":false,"description":"Page size (1-100)"},{"schema":{"minimum":1,"default":1,"type":"integer"},"in":"query","name":"page","required":false,"description":"Page number"}],"security":[{"accessKey":[]}],"responses":{"200":{"description":"Single-post response (when postId is supplied) or paginated list response.","content":{"application/json":{"schema":{"description":"Single-post response (when postId is supplied) or paginated list response.","anyOf":[{"type":"object","required":["success","post"],"properties":{"success":{"type":"boolean"},"post":{"type":"object","required":["source","postId","content","publishedAt","aggregated","platforms"],"properties":{"source":{"type":"string","enum":["postpeer","platform"],"description":"Where the result came from. \"postpeer\" = posts published via PostPeer (stored in our DB). \"platform\" = fetched directly from the connected platform account."},"postId":{"type":"string","nullable":true,"description":"PostPeer post ID. null when source=platform (post fetched directly from the platform)."},"content":{"type":"string","nullable":true},"publishedAt":{"type":"string","format":"date-time","nullable":true},"aggregated":{"type":"object","required":["impressions","reach","likes","comments","shares","saves","clicks","views","engagementRate"],"properties":{"impressions":{"type":"number","nullable":true},"reach":{"type":"number","nullable":true},"likes":{"type":"number","nullable":true},"comments":{"type":"number","nullable":true},"shares":{"type":"number","nullable":true},"saves":{"type":"number","nullable":true},"clicks":{"type":"number","nullable":true},"views":{"type":"number","nullable":true},"engagementRate":{"type":"number","nullable":true,"description":"Engagement rate (0-1). null when the platform does not report engagement."}}},"platforms":{"type":"array","items":{"type":"object","required":["platform","platformPostId","platformPostUrl","metrics"],"properties":{"platform":{"$ref":"#/components/schemas/Platform"},"platformPostId":{"description":"Native post ID on the platform","type":"string"},"platformPostUrl":{"type":"string","nullable":true,"description":"Direct URL to the published post, if known"},"metrics":{"type":"object","required":["impressions","reach","likes","comments","shares","saves","clicks","views","engagementRate"],"properties":{"impressions":{"type":"number","nullable":true},"reach":{"type":"number","nullable":true},"likes":{"type":"number","nullable":true},"comments":{"type":"number","nullable":true},"shares":{"type":"number","nullable":true},"saves":{"type":"number","nullable":true},"clicks":{"type":"number","nullable":true},"views":{"type":"number","nullable":true},"engagementRate":{"type":"number","nullable":true,"description":"Engagement rate (0-1). null when the platform does not report engagement."}}}}}}}}}},{"type":"object","required":["success","total","page","limit","posts"],"properties":{"success":{"type":"boolean"},"total":{"minimum":0,"description":"Total matched posts across all pages","type":"integer"},"page":{"minimum":1,"type":"integer"},"limit":{"minimum":1,"type":"integer"},"posts":{"type":"array","items":{"type":"object","required":["source","postId","content","publishedAt","aggregated","platforms"],"properties":{"source":{"type":"string","enum":["postpeer","platform"],"description":"Where the result came from. \"postpeer\" = posts published via PostPeer (stored in our DB). \"platform\" = fetched directly from the connected platform account."},"postId":{"type":"string","nullable":true,"description":"PostPeer post ID. null when source=platform (post fetched directly from the platform)."},"content":{"type":"string","nullable":true},"publishedAt":{"type":"string","format":"date-time","nullable":true},"aggregated":{"type":"object","required":["impressions","reach","likes","comments","shares","saves","clicks","views","engagementRate"],"properties":{"impressions":{"type":"number","nullable":true},"reach":{"type":"number","nullable":true},"likes":{"type":"number","nullable":true},"comments":{"type":"number","nullable":true},"shares":{"type":"number","nullable":true},"saves":{"type":"number","nullable":true},"clicks":{"type":"number","nullable":true},"views":{"type":"number","nullable":true},"engagementRate":{"type":"number","nullable":true,"description":"Engagement rate (0-1). null when the platform does not report engagement."}}},"platforms":{"type":"array","items":{"type":"object","required":["platform","platformPostId","platformPostUrl","metrics"],"properties":{"platform":{"$ref":"#/components/schemas/Platform"},"platformPostId":{"description":"Native post ID on the platform","type":"string"},"platformPostUrl":{"type":"string","nullable":true,"description":"Direct URL to the published post, if known"},"metrics":{"type":"object","required":["impressions","reach","likes","comments","shares","saves","clicks","views","engagementRate"],"properties":{"impressions":{"type":"number","nullable":true},"reach":{"type":"number","nullable":true},"likes":{"type":"number","nullable":true},"comments":{"type":"number","nullable":true},"shares":{"type":"number","nullable":true},"saves":{"type":"number","nullable":true},"clicks":{"type":"number","nullable":true},"views":{"type":"number","nullable":true},"engagementRate":{"type":"number","nullable":true,"description":"Engagement rate (0-1). null when the platform does not report engagement."}}}}}}}}}}}]}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","message"],"properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}},"402":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","message"],"properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","message"],"properties":{"success":{"type":"boolean"},"message":{"type":"string"}}}}}}}}},"/v1/pinterest/boards":{"get":{"operationId":"getPinterestBoards","summary":"List Pinterest boards for a connected account","tags":["Pinterest"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"accountId","required":false,"description":"Integration ID of the Pinterest account. If omitted, uses the first connected Pinterest account."}],"security":[{"accessKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success","boards"],"properties":{"success":{"type":"boolean"},"boards":{"type":"array","items":{"type":"object","required":["id","name","description","privacy"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"privacy":{"type":"string"}}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}}}}}}}},"/v1/tiktok/creator-info":{"get":{"operationId":"getTikTokCreatorInfo","summary":"Fetch TikTok creator info for a connected account","tags":["TikTok"],"description":"Proxies TikTok's /v2/post/publish/creator_info/query/ endpoint. Use the returned `privacyLevelOptions`, `commentDisabled`, `duetDisabled`, `stitchDisabled`, and `maxVideoPostDurationSec` to build a compliant \"Post to TikTok\" UX.","parameters":[{"schema":{"type":"string"},"in":"query","name":"accountId","required":false,"description":"Integration ID of the TikTok account. If omitted, uses the first connected TikTok account."}],"security":[{"accessKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["success"],"properties":{"success":{"type":"boolean"},"data":{"type":"object","required":["creatorAvatarUrl","creatorUsername","creatorNickname","privacyLevelOptions","commentDisabled","duetDisabled","stitchDisabled","maxVideoPostDurationSec"],"properties":{"creatorAvatarUrl":{"description":"Profile avatar URL returned by TikTok.","anyOf":[{"type":"string"},{"type":"null"}]},"creatorUsername":{"description":"Username (@handle) of the creator.","anyOf":[{"type":"string"},{"type":"null"}]},"creatorNickname":{"description":"Display name of the creator.","anyOf":[{"type":"string"},{"type":"null"}]},"privacyLevelOptions":{"description":"Privacy levels available to this creator. Your UX must restrict the privacy dropdown to these values.","type":"array","items":{"type":"string","enum":["PUBLIC_TO_EVERYONE","MUTUAL_FOLLOW_FRIENDS","FOLLOWER_OF_CREATOR","SELF_ONLY"]}},"commentDisabled":{"description":"If true, the creator has disabled comments in their app settings — grey out the Allow Comment toggle.","type":"boolean"},"duetDisabled":{"description":"If true, the creator has disabled duet in their app settings — grey out the Allow Duet toggle.","type":"boolean"},"stitchDisabled":{"description":"If true, the creator has disabled stitch in their app settings — grey out the Allow Stitch toggle.","type":"boolean"},"maxVideoPostDurationSec":{"description":"Maximum video duration (in seconds) this creator may post. Reject videos longer than this before upload.","type":"number"}}},"error":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}}}}}}}}},"servers":[{"url":"https://api.postpeer.dev","description":"Production"}]}