{"openapi":"3.0.3","info":{"title":"AdaptlyPost Public API","version":"1.0.0","description":"REST API for creating, scheduling, and managing social media posts across Facebook, Instagram, Threads, TikTok, X (Twitter), Bluesky, Mastodon, LinkedIn, Pinterest, YouTube, Google Business Profile, Tumblr, WordPress and Telegram. Register webhooks to receive `post.published`, `post.partially_failed`, `post.failed`, `post.scheduled`, `account.unauthorized`, `image.completed` and `image.failed` events. Read post performance through the `/analytics/*` endpoints: views, likes, comments, shares, followers and engagement rate per workspace, per platform, per day and per post, with a comparison against the previous window of the same length. Connecting an account imports its posts from the last 180 days, and analytics are kept from then on for as long as the account stays connected, so any date range in that history can be queried. A post keeps refreshing for 180 days after it is published and then holds its last captured numbers. Refreshes run on a schedule; `POST /analytics/sync` asks for one now. Webhook deliveries are signed: the `x-adaptly-signature` header contains `sha256=HMAC_SHA256(secret, \"{x-adaptly-timestamp}.{rawBody}\")`. Every response carries the RFC 9331 rate-limit fields so a client can pace itself instead of discovering the limit through a 429: `RateLimit-Policy`, `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`, the seconds until the window rolls over. A 429 adds `Retry-After` with the same number of seconds. Limits are counted per API key."},"servers":[{"url":"https://post.adaptlypost.com/post/api/v1"}],"security":[{"bearerAuth":[]}],"paths":{"/me":{"get":{"operationId":"getMe","summary":"Describe the calling key","tags":["Account"],"responses":{"200":{"description":"The calling key, its role and its permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Open to every valid key, whatever its role, so an agent can find out what it may do before it tries.","parameters":[{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}]}},"/workspaces":{"get":{"operationId":"listWorkspaces","summary":"List the workspaces the caller can act in","description":"An OAuth sign-in reaches every workspace its member belongs to, across organizations; an API key reaches only its own. Send a returned `id` in the `X-Workspace-Id` header to act in that workspace. `current` marks the workspace this call landed in. Open to every valid key, whatever its role, so an agent can find out what it may do before it tries.","tags":["Account"],"responses":{"200":{"description":"The reachable workspaces","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceList"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}]}},"/social-posts":{"post":{"operationId":"createPost","summary":"Create a post (immediate, scheduled, or draft)","description":"A draft (`saveAsDraft: true`) needs only `posts.draft`. A post with a future `scheduledAt` also needs `posts.schedule`, and a post that publishes now also needs `posts.publish`; without it the call answers 403 `permission_denied`. Requires the `posts.draft` permission.","tags":["Posts"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSocialPostRequest"}}}},"responses":{"201":{"description":"Post created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePostResponse"}}}},"400":{"description":"Validation error. When the post itself is invalid, `code` is `post_validation_failed` and `issues` lists every problem found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.draft`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}]},"get":{"operationId":"listPosts","summary":"List posts","tags":["Posts"],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}},{"name":"sortOrder","in":"query","schema":{"type":"string","enum":["NEWEST","OLDEST"]}},{"name":"statuses","in":"query","schema":{"type":"array","items":{"type":"string","enum":["DRAFT","SCHEDULED","PENDING","PUBLISHING","COMPLETED","PARTIAL_FAILURE","FAILED"]}},"explode":true,"description":"Filter by status"},{"name":"platforms","in":"query","schema":{"type":"array","items":{"type":"string","enum":["FACEBOOK","INSTAGRAM","THREADS","TIKTOK","TWITTER","BLUESKY","LINKEDIN","PINTEREST","YOUTUBE","MASTODON","TELEGRAM","GOOGLE_BUSINESS","TUMBLR","WORDPRESS"]}},"explode":true,"description":"Posts targeting any of these platforms"},{"name":"startDate","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"endDate","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"Paginated posts","content":{"application/json":{"schema":{"type":"object","properties":{"posts":{"type":"array","items":{"$ref":"#/components/schemas/Post"}},"total":{"type":"integer"},"hasMore":{"type":"boolean"}}}}}},"400":{"description":"Unknown query parameter or invalid filter value. The message names the offending parameter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.read`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires the `posts.read` permission."}},"/social-posts/validate":{"post":{"operationId":"validatePost","summary":"Dry-run a post without creating it","description":"Takes the same body as `POST /social-posts` and runs every check the create call runs, plus the ones that usually fail only at publish time (TikTok creator limits, YouTube upload quota, expired tokens, Pinterest boards, X credits), without creating a post, uploading media or writing anything. Always answers 200 with a report: `valid` is false when any issue has severity `ERROR`. Issues tied to one account are listed under that account in `accounts`; the rest are in `issues`. `notChecked` lists what only the platform can decide at publish time, so `valid: true` is not a guarantee. The report also names the permissions creating the post would need, and a missing one shows up as a `PERMISSION_DENIED` issue. Requires the `posts.draft` permission.","tags":["Posts"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSocialPostRequest"}}}},"responses":{"200":{"description":"Validation report","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostValidationReport"}}}},"400":{"description":"Malformed request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.draft`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}]}},"/social-posts/bulk/validate":{"post":{"operationId":"validateBulkPosts","summary":"Dry-run a bulk schedule without creating posts","description":"Takes the same body as `POST /social-posts/bulk` and answers with one validation report per item, in request order. Requires the `posts.draft` permission.","tags":["Posts"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkSchedulePostsRequest"}}}},"responses":{"200":{"description":"Validation report per item","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkPostValidationReport"}}}},"400":{"description":"Malformed request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.draft`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}]}},"/social-posts/bulk":{"post":{"operationId":"bulkSchedulePosts","summary":"Bulk schedule up to 100 posts","tags":["Posts"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkSchedulePostsRequest"}}}},"responses":{"201":{"description":"Bulk scheduling result","content":{"application/json":{"schema":{"type":"object","properties":{"totalScheduled":{"type":"integer"},"totalFailed":{"type":"integer"},"results":{"type":"array","items":{"type":"object","properties":{"postId":{"type":"string"},"success":{"type":"boolean"},"isScheduled":{"type":"boolean"},"scheduledAt":{"type":"string","format":"date-time"},"errorMessage":{"type":"string"}}}}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.schedule`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires the `posts.schedule` permission.","parameters":[{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}]}},"/social-posts/{id}":{"get":{"operationId":"getPost","summary":"Get a post by ID","tags":["Posts"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Post ID"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"The post","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Post"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.read`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"Post not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires the `posts.read` permission."},"patch":{"operationId":"updatePost","summary":"Update a draft or scheduled post","tags":["Posts"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Post ID"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSocialPostRequest"}}}},"responses":{"200":{"description":"Updated post","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Post"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.draft`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"Post not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires the `posts.draft` permission."},"delete":{"operationId":"deletePost","summary":"Delete a post","tags":["Posts"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Post ID"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"}}}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.draft`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"Post not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Post is being published and cannot be deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires the `posts.draft` permission."}},"/social-posts/{id}/results":{"get":{"operationId":"getPostResults","summary":"Get per-platform publishing results for a post","tags":["Posts"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Post ID"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"Per-platform results","content":{"application/json":{"schema":{"type":"object","properties":{"postId":{"type":"string"},"status":{"$ref":"#/components/schemas/PostStatus"},"results":{"type":"array","items":{"type":"object","properties":{"platformId":{"type":"string"},"platform":{"$ref":"#/components/schemas/PlatformType"},"accountName":{"type":"string"},"status":{"$ref":"#/components/schemas/PlatformPostStatus"},"platformPostId":{"type":"string"},"errorMessage":{"type":"string"},"tiktokDraftFallback":{"type":"boolean","description":"TikTok delivered the content to the inbox as a draft because the daily active-user cap was hit"},"publishedAt":{"type":"string","format":"date-time"}}}}}}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.read`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"Post not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires the `posts.read` permission."}},"/social-posts/{id}/publish":{"post":{"operationId":"publishDraft","summary":"Publish or schedule a draft post","description":"Without `scheduledAt` the draft is scheduled for its planned date when it has one in the future, and published now otherwise; send `publishNow: true` to publish a dated draft now. Scheduling the draft for a future date also needs `posts.schedule`, and publishing it now also needs `posts.publish`, so a key that holds only `posts.draft` cannot publish; the call answers 403 `permission_denied`. Requires the `posts.draft` permission.","tags":["Posts"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Post ID"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishDraftRequest"}}}},"responses":{"201":{"description":"Publish result","content":{"application/json":{"schema":{"type":"object","properties":{"postId":{"type":"string"},"queuedPlatforms":{"type":"array","items":{"$ref":"#/components/schemas/PlatformType"}},"isScheduled":{"type":"boolean"},"scheduledAt":{"type":"string","format":"date-time"}}}}}},"400":{"description":"Post is not a draft, or both `scheduledAt` and `publishNow` were sent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.draft`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"Post not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/social-posts/{id}/unschedule":{"post":{"operationId":"unschedulePost","summary":"Unschedule a post","description":"Turns a scheduled or dated draft post back into an undated draft. Requires the `posts.draft` permission.","tags":["Posts"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Post ID"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"The post as an undated draft","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Post"}}}},"400":{"description":"Post is neither a draft nor scheduled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.draft`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"Post not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/social-posts/{id}/retry":{"post":{"operationId":"retryFailedPlatforms","summary":"Retry failed platforms of a post","tags":["Posts"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Post ID"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetryFailedPlatformsRequest"}}}},"responses":{"201":{"description":"Retry result","content":{"application/json":{"schema":{"type":"object","properties":{"postId":{"type":"string"},"queuedPlatforms":{"type":"array","items":{"$ref":"#/components/schemas/PlatformType"}},"isScheduled":{"type":"boolean"}}}}}},"400":{"description":"A value in `platformIds` matches no platform entry of the post, or none of the matched entries has failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.publish`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"Post not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires the `posts.publish` permission."}},"/recurring-posts":{"get":{"operationId":"listRecurringPosts","summary":"List recurring posts","description":"Series created by passing `recurrence` to `POST /social-posts`. Only the next occurrence of an active series exists as a scheduled post. Requires the `posts.read` permission.","tags":["Recurring posts"],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}},{"name":"statuses","in":"query","schema":{"type":"array","items":{"type":"string","enum":["ACTIVE","PAUSED","ENDED"]}},"explode":true},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"Paginated recurring posts","content":{"application/json":{"schema":{"type":"object","properties":{"recurringPosts":{"type":"array","items":{"$ref":"#/components/schemas/RecurringPost"}},"total":{"type":"integer"},"hasMore":{"type":"boolean"}}}}}},"400":{"description":"Unknown query parameter or invalid filter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.read`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/recurring-posts/{id}":{"get":{"operationId":"getRecurringPost","summary":"Get a recurring post","tags":["Recurring posts"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Recurring post ID"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"The recurring post","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecurringPost"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.read`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"Recurring post not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires the `posts.read` permission."},"delete":{"operationId":"deleteRecurringPost","summary":"Delete a recurring post","description":"Stops the series and deletes its upcoming scheduled post. Posts that already went out are kept. Requires the `posts.draft` permission.","tags":["Recurring posts"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Recurring post ID"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"}}}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.draft`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"Recurring post not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/recurring-posts/{id}/pause":{"post":{"operationId":"pauseRecurringPost","summary":"Pause a recurring post","description":"Stops creating occurrences and deletes the upcoming scheduled post. Requires the `posts.draft` permission.","tags":["Recurring posts"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Recurring post ID"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"The paused recurring post","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecurringPost"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.draft`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"Recurring post not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/recurring-posts/{id}/resume":{"post":{"operationId":"resumeRecurringPost","summary":"Resume a recurring post","description":"Continues from the next occurrence after now. Occurrences missed while paused are not published. Requires the `posts.draft` permission.","tags":["Recurring posts"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Recurring post ID"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"The resumed recurring post","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecurringPost"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.draft`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"Recurring post not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/rss-feeds":{"get":{"operationId":"listRssFeeds","summary":"List RSS feeds","description":"Feeds of the workspace, newest first. A workspace holds at most 20. Requires the `posts.read` permission.","tags":["RSS feeds"],"responses":{"200":{"description":"RSS feeds","content":{"application/json":{"schema":{"type":"object","properties":{"rssFeeds":{"type":"array","items":{"$ref":"#/components/schemas/RssFeed"}}}}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.read`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}]},"post":{"operationId":"createRssFeed","summary":"Connect an RSS feed","description":"Fetches the feed and records every item already in it, so only items that appear later are posted. Set `postLatestItem` to also post the newest item on the first check. The feed is checked every `checkIntervalMinutes`, and each new item becomes a post on `targets` according to `postMode`. Requires the `posts.draft` permission.","tags":["RSS feeds"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRssFeedRequest"}}}},"responses":{"201":{"description":"The new RSS feed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RssFeed"}}}},"400":{"description":"Invalid settings, a URL that is not an RSS or Atom feed, a feed already connected, or the workspace limit reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.draft`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The feed could not be reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}]}},"/rss-feeds/preview":{"post":{"operationId":"previewRssFeed","summary":"Preview an RSS feed","description":"Fetches a feed without saving it and returns its 5 newest items with `text` rendered from `template`. Requires the `posts.draft` permission.","tags":["RSS feeds"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PreviewRssFeedRequest"}}}},"responses":{"200":{"description":"The feed preview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RssFeedPreview"}}}},"400":{"description":"The URL is not an RSS or Atom feed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.draft`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The feed could not be reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}]}},"/rss-feeds/{id}":{"get":{"operationId":"getRssFeed","summary":"Get an RSS feed","tags":["RSS feeds"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"RSS feed ID"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"The RSS feed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RssFeed"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.read`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"RSS feed not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires the `posts.read` permission."},"patch":{"operationId":"updateRssFeed","summary":"Update an RSS feed","description":"Changes only the fields sent. The URL cannot change. The feed then posts as the key's member, so the key needs the permission of the resulting post mode, plus `posts.others` when someone else set the feed up. Requires the `posts.draft` permission.","tags":["RSS feeds"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"RSS feed ID"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRssFeedRequest"}}}},"responses":{"200":{"description":"The updated RSS feed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RssFeed"}}}},"400":{"description":"Invalid settings","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.draft`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"RSS feed not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"deleteRssFeed","summary":"Delete an RSS feed","description":"Stops checking the feed. Posts it already created stay. Requires the `posts.draft` permission.","tags":["RSS feeds"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"RSS feed ID"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"}}}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.draft`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"RSS feed not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/rss-feeds/{id}/items":{"get":{"operationId":"listRssFeedItems","summary":"List the items an RSS feed has seen","description":"Newest first, leaving out items that were already in the feed when it was added. `postId` links a POSTED item to its post. Requires the `posts.read` permission.","tags":["RSS feeds"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"RSS feed ID"},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"RSS feed items","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/RssFeedItem"}}}}}}},"400":{"description":"Unknown query parameter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.read`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"RSS feed not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/rss-feeds/{id}/pause":{"post":{"operationId":"pauseRssFeed","summary":"Pause an RSS feed","tags":["RSS feeds"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"RSS feed ID"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"The paused RSS feed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RssFeed"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.draft`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"RSS feed not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires the `posts.draft` permission."}},"/rss-feeds/{id}/resume":{"post":{"operationId":"resumeRssFeed","summary":"Resume an RSS feed","description":"Clears the pause reason and checks the feed within a minute. The feed then posts as the key's member, so the key needs the permission of its post mode. Requires the `posts.draft` permission.","tags":["RSS feeds"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"RSS feed ID"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"The resumed RSS feed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RssFeed"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.draft`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"RSS feed not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/rss-feeds/{id}/check":{"post":{"operationId":"checkRssFeedNow","summary":"Check an RSS feed now","description":"Moves the next check to now; the feed is fetched within a minute. Requires the `posts.draft` permission.","tags":["RSS feeds"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"RSS feed ID"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"The RSS feed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RssFeed"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.draft`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"RSS feed not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/social-accounts":{"get":{"operationId":"listSocialAccounts","summary":"List connected social accounts","tags":["Accounts"],"responses":{"200":{"description":"Connected accounts","content":{"application/json":{"schema":{"type":"object","properties":{"accounts":{"type":"array","items":{"$ref":"#/components/schemas/SocialAccount"}}}}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `accounts.read`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires the `accounts.read` permission.","parameters":[{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}]}},"/social-accounts/{id}/check":{"post":{"operationId":"checkSocialAccount","summary":"Re-check an account with its platform now","description":"Probes the platform with the stored token and returns the resulting `status`. Facebook pages only: a rejected token marks the page `unauthorized` (and fires `account.unauthorized`), a working token clears an earlier `unauthorized` mark. Pages are also checked automatically twice a day. Accepts the account `id` or the Facebook `pageId`. Requires the `accounts.manage` permission.","tags":["Accounts"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The account `id` from /social-accounts, or the Facebook `pageId`"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"Fresh account status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SocialAccountCheckResult"}}}},"400":{"description":"The account is not a Facebook page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `accounts.manage`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"Account not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/social-accounts/{id}":{"delete":{"operationId":"removeSocialAccount","summary":"Remove a social account from the workspace","description":"Disconnects the account the same way the Connectors page does: the stored tokens are deleted, the account is taken off every pending and recurring post, and it stops counting toward the plan. Works for accounts in any `status`, so an `unauthorized` account can be cleaned up without reconnecting it. For Facebook only the named page goes; the other pages of the same login stay connected. Accepts the account `id` or the Facebook `pageId`. Connect the account again to bring it back. Requires the `accounts.manage` permission.","tags":["Accounts"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The account `id` from /social-accounts, or the Facebook `pageId`"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"Removed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SocialAccountRemovalResult"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `accounts.manage`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"Account not found in this workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/social-accounts/{id}/instagram-audio":{"get":{"operationId":"searchInstagramAudio","summary":"Search Instagram music and original sounds for a Reel","description":"Returns audio Meta has cleared for third-party publishing, which can differ from what the Instagram app shows. Leave out `searchQuery` to get what is trending. Only works for Instagram accounts with `supportsInstagramAudio: true`; pass the chosen `audioId` in `instagramConfigs[].audio`. Requires the `posts.draft` permission.","tags":["Accounts"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The Instagram account `id` from /social-accounts"},{"name":"audioType","in":"query","required":true,"schema":{"type":"string","enum":["music","original_sound"]}},{"name":"searchQuery","in":"query","required":false,"schema":{"type":"string","maxLength":100},"description":"Keyword filter. Leave out for trending audio"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"Matching audio","content":{"application/json":{"schema":{"type":"object","properties":{"audio":{"type":"array","items":{"$ref":"#/components/schemas/InstagramAudio"}}}}}}},"400":{"description":"The account is not connected through Facebook, or Instagram rejected the search","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.draft`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"Account not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/social-accounts/{id}/pinterest-boards":{"get":{"operationId":"getPinterestBoards","summary":"List the boards of a Pinterest account","description":"Returns every board the account can pin to, secret boards included. Pass the chosen `id` as `pinterestConfigs[].boardId`, or its `name` as `pinterestConfigs[].boardName`. A board belongs to one Pinterest account, so list the boards of each account you post to. Requires the `posts.draft` permission.","tags":["Accounts"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The Pinterest account `id` from /social-accounts"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"Boards of the account","content":{"application/json":{"schema":{"type":"object","properties":{"boards":{"type":"array","items":{"$ref":"#/components/schemas/PinterestBoard"}}}}}}},"400":{"description":"Pinterest refused the request, usually because the account must be reconnected","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `posts.draft`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"Account not found, or not a Pinterest account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/upload-urls":{"post":{"operationId":"getUploadUrls","summary":"Get presigned upload URLs for media files","tags":["Media"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetUploadUrlsRequest"}}}},"responses":{"201":{"description":"Presigned upload URLs","content":{"application/json":{"schema":{"type":"object","properties":{"urls":{"type":"array","items":{"type":"object","properties":{"fileName":{"type":"string"},"uploadUrl":{"type":"string","description":"PUT the file bytes to this URL"},"publicUrl":{"type":"string","description":"Public URL to reference in mediaUrls after upload. Reusable across posts; the file stays until the last post referencing it has published"},"key":{"type":"string"},"expiresAt":{"type":"string","format":"date-time"}}}}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `media.upload`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires the `media.upload` permission.","parameters":[{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}]}},"/connect-links":{"post":{"operationId":"createConnectLink","summary":"Create a white-label link for connecting social accounts","description":"Send no body for a quick link: it lasts 7 days, offers every platform, shows the client every account in the workspace and connects any number of accounts. A link with `maxAccounts` stops working once that many accounts are connected through it. A link with `expiresAt` stops working at that time instead of after the default, and one with `neverExpires: true` keeps working until it is revoked. Requires the `accounts.manage` permission.","tags":["Connect Links"],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateConnectLinkRequest"}}}},"responses":{"201":{"description":"Connect link","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"},"token":{"type":"string"},"expiresAt":{"type":"string","format":"date-time","nullable":true},"name":{"type":"string","nullable":true},"visibility":{"type":"string","enum":["PUBLIC","PRIVATE"]},"allowedPlatforms":{"type":"array","items":{"type":"string","enum":["FACEBOOK","INSTAGRAM","THREADS","TIKTOK","TWITTER","BLUESKY","LINKEDIN","PINTEREST","YOUTUBE","MASTODON","TELEGRAM","GOOGLE_BUSINESS","TUMBLR","WORDPRESS"]}},"maxAccounts":{"type":"integer","nullable":true}}}}}},"400":{"description":"Invalid configuration, or an expiry outside the allowed range","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `accounts.manage`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}]}},"/connect-links/{token}":{"delete":{"operationId":"revokeConnectLink","summary":"Revoke a connect link","tags":["Connect Links"],"parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string"}},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"Revoked","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}}}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `accounts.manage`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"Connect link not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires the `accounts.manage` permission."}},"/webhooks":{"post":{"operationId":"createWebhook","summary":"Register a webhook endpoint","description":"Registers a URL that receives ALL events (post.published, post.partially_failed, post.failed, post.scheduled, account.unauthorized, image.completed, image.failed). Deliveries are HTTP POSTs with a WebhookEventPayload body, retried up to 5 times with exponential backoff. Each request includes `x-adaptly-signature`, `x-adaptly-timestamp`, `x-adaptly-event`, and `x-adaptly-webhook-id` headers. Webhooks are auto-disabled after 20 consecutive failed deliveries. Requires the `webhooks.manage` permission.","tags":["Webhooks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookRequest"}}}},"responses":{"201":{"description":"Created webhook (the only response that includes the signing secret)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookResponse"}}}},"400":{"description":"Invalid URL or webhook limit reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `webhooks.manage`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"409":{"description":"A webhook with this URL already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}]},"get":{"operationId":"listWebhooks","summary":"List registered webhooks","tags":["Webhooks"],"responses":{"200":{"description":"Registered webhooks","content":{"application/json":{"schema":{"type":"object","properties":{"webhooks":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}}}}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `webhooks.read`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires the `webhooks.read` permission.","parameters":[{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}]}},"/webhooks/{id}":{"get":{"operationId":"getWebhook","summary":"Get a webhook by ID","tags":["Webhooks"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Webhook ID"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"The webhook","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `webhooks.read`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"Webhook not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires the `webhooks.read` permission."},"patch":{"operationId":"updateWebhook","summary":"Update a webhook (URL or active state)","tags":["Webhooks"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Webhook ID"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookRequest"}}}},"responses":{"200":{"description":"Updated webhook","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"400":{"description":"Invalid URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `webhooks.manage`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"Webhook not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A webhook with this URL already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires the `webhooks.manage` permission."},"delete":{"operationId":"deleteWebhook","summary":"Delete a webhook","tags":["Webhooks"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Webhook ID"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"}}}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `webhooks.manage`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"Webhook not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires the `webhooks.manage` permission."}},"/webhooks/{id}/test":{"post":{"operationId":"testWebhook","summary":"Send a signed webhook.test event to the endpoint","tags":["Webhooks"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Webhook ID"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"201":{"description":"Delivery attempt result","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"statusCode":{"type":"integer"},"error":{"type":"string"}}}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `webhooks.manage`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"Webhook not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires the `webhooks.manage` permission."}},"/analytics/overview":{"get":{"operationId":"getAnalyticsOverview","summary":"Workspace-wide totals for a date window, with previous-window comparison","description":"Sums views, likes, comments, shares, posts published and average views per post across the selected platforms for posts published inside the window, plus the latest follower count and engagement rate. Every metric carries `previousValue` and `deltaPercent` against the window of the same length immediately before `from`. `partialMetrics` lists metrics some selected platform cannot report, so their totals cover only the platforms that can. A metric is `null` when no selected platform reports it. Requires the `analytics.read` permission.","tags":["Analytics"],"parameters":[{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date-time"},"description":"Start of the reporting window (ISO 8601). Metrics cover posts published between `from` and `to`; comparisons use the window of the same length immediately before it"},{"name":"to","in":"query","required":true,"schema":{"type":"string","format":"date-time"},"description":"End of the reporting window (ISO 8601). Must not be earlier than `from`. Each post reports its numbers as of `to`, or its first measurement after `to` when it was first measured later"},{"name":"platforms","in":"query","schema":{"type":"array","items":{"type":"string","enum":["FACEBOOK","INSTAGRAM","THREADS","TIKTOK","TWITTER","BLUESKY","LINKEDIN","PINTEREST","YOUTUBE","MASTODON","TELEGRAM","GOOGLE_BUSINESS","TUMBLR","WORDPRESS"]}},"explode":true,"description":"Restrict to these platforms. Omit for every platform with analytics. MASTODON, TELEGRAM, TUMBLR and WORDPRESS have no analytics and are ignored"},{"name":"connectionIds","in":"query","schema":{"type":"array","items":{"type":"string"}},"explode":true,"description":"Restrict to these accounts, by the account `id` from /social-accounts. Repeat the parameter for each account. Omit for every account"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"Overview metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsOverview"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `analytics.read`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/analytics/timeseries":{"get":{"operationId":"getAnalyticsTimeseries","summary":"Metrics bucketed by day, week or month","description":"One point per bucket inside the window. `followers` is the latest known count at the end of each bucket; the other counters sum posts published inside the bucket. A metric no selected platform reports is `null`. Requires the `analytics.read` permission.","tags":["Analytics"],"parameters":[{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date-time"},"description":"Start of the reporting window (ISO 8601). Metrics cover posts published between `from` and `to`; comparisons use the window of the same length immediately before it"},{"name":"to","in":"query","required":true,"schema":{"type":"string","format":"date-time"},"description":"End of the reporting window (ISO 8601). Must not be earlier than `from`. Each post reports its numbers as of `to`, or its first measurement after `to` when it was first measured later"},{"name":"platforms","in":"query","schema":{"type":"array","items":{"type":"string","enum":["FACEBOOK","INSTAGRAM","THREADS","TIKTOK","TWITTER","BLUESKY","LINKEDIN","PINTEREST","YOUTUBE","MASTODON","TELEGRAM","GOOGLE_BUSINESS","TUMBLR","WORDPRESS"]}},"explode":true,"description":"Restrict to these platforms. Omit for every platform with analytics. MASTODON, TELEGRAM, TUMBLR and WORDPRESS have no analytics and are ignored"},{"name":"connectionIds","in":"query","schema":{"type":"array","items":{"type":"string"}},"explode":true,"description":"Restrict to these accounts, by the account `id` from /social-accounts. Repeat the parameter for each account. Omit for every account"},{"name":"granularity","in":"query","schema":{"type":"string","enum":["DAILY","WEEKLY","MONTHLY"],"default":"DAILY"}},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"Timeseries points","content":{"application/json":{"schema":{"type":"object","properties":{"points":{"type":"array","items":{"$ref":"#/components/schemas/AnalyticsTimeseriesPoint"}}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `analytics.read`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/analytics/platform-breakdown":{"get":{"operationId":"getAnalyticsPlatformBreakdown","summary":"The same metrics as the overview, one row per platform","description":"One entry per platform that has analytics data in the workspace, each with the metrics of /analytics/overview scoped to that platform and a `supportedMetrics` list naming the metrics the platform actually reports. Requires the `analytics.read` permission.","tags":["Analytics"],"parameters":[{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date-time"},"description":"Start of the reporting window (ISO 8601). Metrics cover posts published between `from` and `to`; comparisons use the window of the same length immediately before it"},{"name":"to","in":"query","required":true,"schema":{"type":"string","format":"date-time"},"description":"End of the reporting window (ISO 8601). Must not be earlier than `from`. Each post reports its numbers as of `to`, or its first measurement after `to` when it was first measured later"},{"name":"connectionIds","in":"query","schema":{"type":"array","items":{"type":"string"}},"explode":true,"description":"Restrict to these accounts, by the account `id` from /social-accounts. Repeat the parameter for each account. Omit for every account"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"Per-platform metrics","content":{"application/json":{"schema":{"type":"object","properties":{"platforms":{"type":"array","items":{"$ref":"#/components/schemas/AnalyticsPlatformBreakdownItem"}}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `analytics.read`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/analytics/posts":{"get":{"operationId":"listPostAnalytics","summary":"Per-post metrics for every tracked post published in the window, paginated","description":"Covers posts published through AdaptlyPost and posts discovered on the connected accounts; discovered posts have `postId` and `postPlatformId` set to null. Sort by any metric or by `PUBLISHED_AT` (the default). A metric the platform does not report is `null`. Requires the `analytics.read` permission.","tags":["Analytics"],"parameters":[{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date-time"},"description":"Start of the reporting window (ISO 8601). Metrics cover posts published between `from` and `to`; comparisons use the window of the same length immediately before it"},{"name":"to","in":"query","required":true,"schema":{"type":"string","format":"date-time"},"description":"End of the reporting window (ISO 8601). Must not be earlier than `from`. Each post reports its numbers as of `to`, or its first measurement after `to` when it was first measured later"},{"name":"platforms","in":"query","schema":{"type":"array","items":{"type":"string","enum":["FACEBOOK","INSTAGRAM","THREADS","TIKTOK","TWITTER","BLUESKY","LINKEDIN","PINTEREST","YOUTUBE","MASTODON","TELEGRAM","GOOGLE_BUSINESS","TUMBLR","WORDPRESS"]}},"explode":true,"description":"Restrict to these platforms. Omit for every platform with analytics. MASTODON, TELEGRAM, TUMBLR and WORDPRESS have no analytics and are ignored"},{"name":"connectionIds","in":"query","schema":{"type":"array","items":{"type":"string"}},"explode":true,"description":"Restrict to these accounts, by the account `id` from /social-accounts. Repeat the parameter for each account. Omit for every account"},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["VIEWS","LIKES","COMMENTS","SHARES","SAVES","CLICKS","IMPRESSIONS","ENGAGEMENT_RATE","PUBLISHED_AT"],"default":"PUBLISHED_AT"}},{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"Paginated post metrics","content":{"application/json":{"schema":{"type":"object","properties":{"posts":{"type":"array","items":{"$ref":"#/components/schemas/AnalyticsPost"}},"total":{"type":"integer"},"page":{"type":"integer"},"limit":{"type":"integer"},"hasMore":{"type":"boolean"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `analytics.read`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/analytics/top-posts":{"get":{"operationId":"listTopPosts","summary":"Best-performing posts in the window by one metric","description":"The top `limit` posts published inside the window, ordered by `sortBy` (default VIEWS). Same rows as /analytics/posts without pagination. Requires the `analytics.read` permission.","tags":["Analytics"],"parameters":[{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date-time"},"description":"Start of the reporting window (ISO 8601). Metrics cover posts published between `from` and `to`; comparisons use the window of the same length immediately before it"},{"name":"to","in":"query","required":true,"schema":{"type":"string","format":"date-time"},"description":"End of the reporting window (ISO 8601). Must not be earlier than `from`. Each post reports its numbers as of `to`, or its first measurement after `to` when it was first measured later"},{"name":"platforms","in":"query","schema":{"type":"array","items":{"type":"string","enum":["FACEBOOK","INSTAGRAM","THREADS","TIKTOK","TWITTER","BLUESKY","LINKEDIN","PINTEREST","YOUTUBE","MASTODON","TELEGRAM","GOOGLE_BUSINESS","TUMBLR","WORDPRESS"]}},"explode":true,"description":"Restrict to these platforms. Omit for every platform with analytics. MASTODON, TELEGRAM, TUMBLR and WORDPRESS have no analytics and are ignored"},{"name":"connectionIds","in":"query","schema":{"type":"array","items":{"type":"string"}},"explode":true,"description":"Restrict to these accounts, by the account `id` from /social-accounts. Repeat the parameter for each account. Omit for every account"},{"name":"sortBy","in":"query","schema":{"type":"string","enum":["VIEWS","LIKES","COMMENTS","SHARES","SAVES","CLICKS","IMPRESSIONS","ENGAGEMENT_RATE","PUBLISHED_AT"],"default":"VIEWS"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":50,"default":10}},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"Top posts","content":{"application/json":{"schema":{"type":"object","properties":{"posts":{"type":"array","items":{"$ref":"#/components/schemas/AnalyticsPost"}}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `analytics.read`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/analytics/discovered-posts":{"get":{"operationId":"listDiscoveredPosts","summary":"Posts found on the connected accounts that were not published through AdaptlyPost","description":"Read-only calendar entries for content published elsewhere (natively, or through another tool). Their metrics appear in /analytics/posts; this endpoint returns the post itself: text, thumbnail, permalink and publish time. Requires the `analytics.read` permission.","tags":["Analytics"],"parameters":[{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date-time"},"description":"Start of the reporting window (ISO 8601). Metrics cover posts published between `from` and `to`; comparisons use the window of the same length immediately before it"},{"name":"to","in":"query","required":true,"schema":{"type":"string","format":"date-time"},"description":"End of the reporting window (ISO 8601). Must not be earlier than `from`. Each post reports its numbers as of `to`, or its first measurement after `to` when it was first measured later"},{"name":"platforms","in":"query","schema":{"type":"array","items":{"type":"string","enum":["FACEBOOK","INSTAGRAM","THREADS","TIKTOK","TWITTER","BLUESKY","LINKEDIN","PINTEREST","YOUTUBE","MASTODON","TELEGRAM","GOOGLE_BUSINESS","TUMBLR","WORDPRESS"]}},"explode":true,"description":"Restrict to these platforms. Omit for every platform with analytics. MASTODON, TELEGRAM, TUMBLR and WORDPRESS have no analytics and are ignored"},{"name":"connectionIds","in":"query","schema":{"type":"array","items":{"type":"string"}},"explode":true,"description":"Restrict to these accounts, by the account `id` from /social-accounts. Repeat the parameter for each account. Omit for every account"},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":1000,"default":200}},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"Discovered posts","content":{"application/json":{"schema":{"type":"object","properties":{"posts":{"type":"array","items":{"$ref":"#/components/schemas/DiscoveredPost"}}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `analytics.read`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/analytics/sync-status":{"get":{"operationId":"getAnalyticsSyncStatus","summary":"Freshness of the analytics data, per connected account","description":"Tells you when each account was last synced, whether a sync is running now, how far back the data goes (`historyHorizonAt`) and whether an account must be reconnected before analytics can be read from it (`needsAnalyticsReconnect`). Accounts on platforms without analytics (Mastodon, Telegram, Tumblr and WordPress) are not listed. Requires the `analytics.read` permission.","tags":["Analytics"],"responses":{"200":{"description":"Sync status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsSyncStatus"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `analytics.read`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}]}},"/analytics/sync":{"post":{"operationId":"triggerAnalyticsSync","summary":"Ask for an analytics refresh now","description":"Queues a sync for every connected account with analytics and re-reads the last 7 days. Analytics refresh on their own every few hours, so this is for \"I just published, show me numbers\" moments. Rate limited to one run per workspace every 4 hours: inside the cooldown the response is 200 with `queued: false` and `cooldownSecondsRemaining`, never an error. Read /analytics/sync-status to see the run finish. Requires the `analytics.sync` permission.","tags":["Analytics"],"responses":{"200":{"description":"Sync request result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerAnalyticsSyncResponse"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `analytics.sync`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}]}},"/ai/captions":{"post":{"operationId":"generateCaption","summary":"Generate a caption","description":"Writes a caption from a prompt. Pass `platform` and the caption is held to that platform's character limit. Consumes one caption credit unless the workspace has its own provider key connected. Requires the `ai.generate` permission.","tags":["AI"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateCaptionRequest"}}}},"responses":{"201":{"description":"Generated caption","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaptionResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Insufficient credits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `ai.generate`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}]}},"/ai/captions/refine":{"post":{"operationId":"refineCaption","summary":"Rewrite an existing caption","description":"Rewrites `originalText` following the instruction in `prompt`. Send `partialText` to continue from a partly written caption. Costs the same as generating one. Requires the `ai.generate` permission.","tags":["AI"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefineCaptionRequest"}}}},"responses":{"201":{"description":"Rewritten caption","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaptionResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Insufficient credits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `ai.generate`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}]}},"/ai/images":{"post":{"operationId":"generateImage","summary":"Start an image generation","description":"Queues an image and returns a `jobId` right away. Poll GET /ai/images/{jobId} until `status` is `completed` or `failed`; a completed job carries the `imageUrl`. Images take roughly 10 to 40 seconds. Credits are charged when generation starts and refunded if it fails. Requires the `ai.generate` permission.","tags":["AI"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateImageRequest"}}}},"responses":{"201":{"description":"Image generation queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateImageResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `ai.generate`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}]}},"/ai/images/{jobId}":{"get":{"operationId":"getImageJob","summary":"Read an image generation job","tags":["AI"],"parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"},"description":"Job ID returned by POST /ai/images"},{"name":"X-Workspace-Id","in":"header","required":false,"schema":{"type":"string"},"description":"The workspace to act in, for OAuth sign-ins that reach several workspaces. Take the id from `GET /workspaces`. Without it the call lands in the default workspace. A workspace the caller cannot reach answers 403 with `code: workspace_access_denied`. An API key belongs to one workspace: send its own id or leave the header out"}],"responses":{"200":{"description":"Image job state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageJobResponse"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key's role does not hold `ai.generate`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PermissionDeniedError"}}}},"404":{"description":"Job not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"description":"Requires the `ai.generate` permission."}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API token from the AdaptlyPost dashboard, sent as 'Authorization: Bearer adaptly_...'. A key carries the workspace role it was created with, and can never do more than the member who created it: Admin runs the workspace and manages connected accounts and connect links, Editor creates, schedules and publishes, and manages webhooks and the post signature, Contributor creates and edits its own drafts and cannot schedule or publish, Viewer reads posts and analytics. Call `GET /me` to read the role and the exact permission list of the key in hand. An OAuth access token reaches every workspace its member belongs to: list them with `GET /workspaces` and pick one per call with the `X-Workspace-Id` header, where each workspace applies the member's own role there. An operation the role does not cover answers 403 with `code: permission_denied` and the missing `requiredPermission`; retrying or swapping keys will not change that. A key whose creator has since lost access to the workspace answers 401 with `code: token_issuer_lost_access`. An OAuth access token whose login has no AdaptlyPost account answers 401 with `code: oauth_account_not_found`. Every call answers 403 with `code: subscription_required` while the organization's plan is not active."}},"schemas":{"CaptionPlatform":{"type":"string","enum":["TWITTER","BLUESKY","MASTODON","THREADS","PINTEREST","INSTAGRAM","TIKTOK","LINKEDIN","YOUTUBE","FACEBOOK","GOOGLE_BUSINESS","TUMBLR","WORDPRESS"],"description":"Holds the caption to this platform's character limit"},"ImageAspectRatio":{"type":"string","enum":["1:1","16:9","9:16","3:2","2:3","4:5","5:4","21:9","9:21"],"default":"1:1","description":"The image comes back at exactly this ratio: 1:1 is 1024x1024, 3:2 is 1536x1024, 2:3 is 1024x1536, 5:4 is 1280x1024, 4:5 is 1024x1280, 16:9 is 1536x864, 9:16 is 864x1536, 21:9 is 1792x768 and 9:21 is 768x1792. With your own Google key Google picks the pixel size, and 9:21 comes back as 9:16"},"ImageModel":{"type":"string","enum":["standard","premium"],"default":"standard"},"ImageQuality":{"type":"string","enum":["LOW","MEDIUM","HIGH"],"description":"Used only when you generate with your own OpenAI key. On AdaptlyPost credits `model` sets the quality and this field is ignored"},"ImageJobStatus":{"type":"string","enum":["queued","processing","generating","completed","failed"]},"GenerateCaptionRequest":{"type":"object","required":["prompt"],"properties":{"prompt":{"type":"string","maxLength":2000,"description":"What the caption should say or be about"},"platform":{"$ref":"#/components/schemas/CaptionPlatform"}}},"RefineCaptionRequest":{"type":"object","required":["prompt","originalText"],"properties":{"prompt":{"type":"string","maxLength":2000,"description":"How the caption should change"},"platform":{"$ref":"#/components/schemas/CaptionPlatform"},"originalText":{"type":"string","maxLength":10000,"description":"The caption to rewrite"},"partialText":{"type":"string","maxLength":10000,"description":"A partly written caption to continue from"}}},"CaptionResponse":{"type":"object","properties":{"caption":{"type":"string"}}},"GenerateImageRequest":{"type":"object","required":["prompt"],"properties":{"prompt":{"type":"string","maxLength":2000},"aspectRatio":{"$ref":"#/components/schemas/ImageAspectRatio"},"model":{"$ref":"#/components/schemas/ImageModel"},"quality":{"$ref":"#/components/schemas/ImageQuality"},"sessionId":{"type":"string","format":"uuid","description":"Groups images together. Omit it and a new session is created, then reuse the returned sessionId to keep related images in one place."},"referenceImages":{"type":"array","maxItems":5,"items":{"type":"string"},"description":"Public image URLs to steer the result"}}},"GenerateImageResponse":{"type":"object","properties":{"jobId":{"type":"string"},"sessionId":{"type":"string","format":"uuid"},"status":{"$ref":"#/components/schemas/ImageJobStatus"}}},"ImageJobResponse":{"type":"object","properties":{"jobId":{"type":"string"},"sessionId":{"type":"string","format":"uuid"},"status":{"$ref":"#/components/schemas/ImageJobStatus"},"imageUrl":{"type":"string","nullable":true},"imageId":{"type":"string","format":"uuid","nullable":true},"error":{"type":"string","nullable":true}}},"PlatformType":{"type":"string","enum":["FACEBOOK","INSTAGRAM","THREADS","TIKTOK","TWITTER","BLUESKY","LINKEDIN","PINTEREST","YOUTUBE","MASTODON","TELEGRAM","GOOGLE_BUSINESS","TUMBLR","WORDPRESS"]},"ContentType":{"type":"string","enum":["TEXT","IMAGE","VIDEO","CAROUSEL","DOCUMENT"],"description":"`CAROUSEL` takes 2 or more items in `mediaUrls`, up to 4 on TWITTER, BLUESKY and MASTODON, 5 on PINTEREST, 10 on INSTAGRAM, FACEBOOK, THREADS and TELEGRAM, 20 on LINKEDIN and WORDPRESS, 30 on TUMBLR and 35 on TIKTOK. A TIKTOK carousel takes JPEG or WebP photos only. INSTAGRAM and THREADS accept images and videos in the same carousel; every other platform takes images only, and YOUTUBE has no carousel. `DOCUMENT` publishes one PDF, PPT, PPTX, DOC or DOCX file (max 100 MB, 300 pages) as a LinkedIn document post, and is LinkedIn only: any other platform in the same request is rejected with a 400"},"PostStatus":{"type":"string","enum":["DRAFT","SCHEDULED","PENDING","PUBLISHING","COMPLETED","PARTIAL_FAILURE","FAILED"]},"PlatformPostStatus":{"type":"string","enum":["PENDING","PUBLISHING","PUBLISHED","FAILED"]},"WebhookEventName":{"type":"string","enum":["post.published","post.partially_failed","post.failed","post.scheduled","account.unauthorized","image.completed","image.failed"]},"Error":{"type":"object","properties":{"statusCode":{"type":"integer"},"message":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"error":{"type":"string"},"code":{"type":"string","description":"Machine-readable reason. `permission_denied` (403) means the role is short of a permission, `subscription_required` (403) means the organization's plan is not active, `token_issuer_lost_access` (401) means the key is dead because its creator left the workspace, `oauth_account_not_found` (401) means the login behind an OAuth access token has no AdaptlyPost account, `insufficient_credits` (402) means the AI endpoints are out of credits for this user, `workspace_access_denied` (403) means the `X-Workspace-Id` header names a workspace the caller cannot act in, `post_validation_failed` (400) means the post was refused and `issues` lists why"},"issues":{"type":"array","items":{"$ref":"#/components/schemas/PostIssue"},"description":"Set with `code: post_validation_failed`"}}},"PostIssue":{"type":"object","required":["code","severity","message"],"properties":{"code":{"type":"string","description":"Stable machine-readable reason, such as `TEXT_TOO_LONG`, `ACCOUNT_DISCONNECTED`, `TIKTOK_POSTING_BLOCKED` or `YOUTUBE_UPLOAD_QUOTA_EXHAUSTED`"},"severity":{"type":"string","enum":["ERROR","WARNING"],"description":"`ERROR` stops the post (or that account) from going out; `WARNING` lets it through with a caveat"},"message":{"type":"string"},"platform":{"$ref":"#/components/schemas/PlatformType"},"connectionId":{"type":"string","description":"The account the issue is about, when it is about one"}}},"PostAccountCheck":{"type":"object","required":["platform","connectionId","status","issues"],"properties":{"platform":{"$ref":"#/components/schemas/PlatformType"},"connectionId":{"type":"string"},"accountName":{"type":"string"},"status":{"type":"string","enum":["READY","WARNING","BLOCKED"]},"issues":{"type":"array","items":{"$ref":"#/components/schemas/PostIssue"}}}},"PostValidationReport":{"type":"object","required":["valid","outcome","requiredPermissions","issues","accounts","notChecked"],"properties":{"valid":{"type":"boolean"},"outcome":{"type":"string","enum":["DRAFT","SCHEDULED","PUBLISH_NOW"],"description":"What creating this post would do"},"scheduledAt":{"type":"string","format":"date-time"},"requiredPermissions":{"type":"array","items":{"$ref":"#/components/schemas/WorkspacePermission"}},"issues":{"type":"array","items":{"$ref":"#/components/schemas/PostIssue"},"description":"Issues not tied to one selected account"},"accounts":{"type":"array","items":{"$ref":"#/components/schemas/PostAccountCheck"}},"notChecked":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","enum":["PLATFORM_PROCESSING","DUPLICATE_CONTENT","PLATFORM_RATE_LIMITS","LIVE_ACCOUNT_ACCESS","VIDEO_DURATION"]},"message":{"type":"string"}}}}}},"BulkPostValidationReport":{"type":"object","properties":{"valid":{"type":"boolean"},"totalValid":{"type":"integer"},"totalInvalid":{"type":"integer"},"results":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"report":{"$ref":"#/components/schemas/PostValidationReport"}}}}}},"WorkspacePermission":{"type":"string","enum":["workspace.read","workspace.manage","posts.read","posts.draft","posts.others","posts.schedule","posts.publish","posts.delete","media.upload","accounts.read","accounts.manage","analytics.read","analytics.sync","inbox.read","inbox.reply","ai.generate","members.read","members.manage","tokens.own","tokens.manage","webhooks.read","webhooks.manage","signature.manage","flowsery.write","redreplier.write","claw.use"]},"PermissionDeniedError":{"type":"object","required":["statusCode","error","code","requiredPermission","role","keyRole","issuerRole","tokenType","message"],"properties":{"statusCode":{"type":"integer","enum":[403]},"error":{"type":"string","enum":["Forbidden"]},"code":{"type":"string","enum":["permission_denied"]},"requiredPermission":{"$ref":"#/components/schemas/WorkspacePermission"},"role":{"type":"string","description":"The role the message names: the power actually in force. It never holds requiredPermission. When the key was issued by a member who has since been demoted, this is the issuer’s role, not the key’s"},"keyRole":{"type":"string","nullable":true,"description":"The workspace role recorded on the key. Null when the caller is a session"},"issuerRole":{"type":"string","nullable":true,"description":"The current workspace role of the member who issued the key, which caps what the key can do. Null when the caller is a session"},"tokenType":{"type":"string","enum":["api_token","oauth"]},"message":{"type":"string","description":"What the role cannot do, and what to do instead. Stop on this error: another key or a retry will not help"}}},"WorkspaceList":{"type":"object","required":["workspaces"],"properties":{"workspaces":{"type":"array","items":{"$ref":"#/components/schemas/Workspace"}}}},"Workspace":{"type":"object","required":["id","name","organization","role","permissions","isDefault","current","can"],"properties":{"id":{"type":"string","description":"Send it in the `X-Workspace-Id` header"},"name":{"type":"string"},"organization":{"type":"object","required":["id","name"],"properties":{"id":{"type":"string"},"name":{"type":"string"}}},"role":{"type":"object","required":["key","name"],"properties":{"key":{"type":"string"},"name":{"type":"string"}}},"permissions":{"type":"array","items":{"type":"string","enum":["workspace.read","workspace.manage","posts.read","posts.draft","posts.others","posts.schedule","posts.publish","posts.delete","media.upload","accounts.read","accounts.manage","analytics.read","analytics.sync","inbox.read","inbox.reply","ai.generate","members.read","members.manage","tokens.own","tokens.manage","webhooks.read","webhooks.manage","signature.manage","flowsery.write","redreplier.write","claw.use"]}},"isDefault":{"type":"boolean"},"current":{"type":"boolean","description":"True for the workspace this call landed in"},"can":{"type":"object","required":["draft","schedule","publish"],"properties":{"draft":{"type":"boolean"},"schedule":{"type":"boolean"},"publish":{"type":"boolean"}}}}},"Me":{"type":"object","required":["tokenType","workspace","organizationId","role","permissions","can","summary"],"properties":{"tokenType":{"type":"string","enum":["api_token","oauth"]},"tokenId":{"type":"string","nullable":true},"tokenName":{"type":"string","nullable":true},"workspace":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}},"organizationId":{"type":"string"},"role":{"type":"object","required":["key","name"],"properties":{"key":{"type":"string"},"name":{"type":"string"}}},"issuerRole":{"type":"string","nullable":true,"description":"The workspace role of the member who created the key. The key's own permissions never exceed it"},"permissions":{"type":"array","items":{"$ref":"#/components/schemas/WorkspacePermission"}},"can":{"type":"object","required":["draft","schedule","publish"],"properties":{"draft":{"type":"boolean"},"schedule":{"type":"boolean"},"publish":{"type":"boolean"}}},"summary":{"type":"string","description":"One sentence naming the role and what it can do"},"expiresAt":{"type":"string","format":"date-time","nullable":true,"description":"When the key stops working. Null means it never expires"}}},"PlatformText":{"type":"object","required":["platform","text"],"properties":{"platform":{"$ref":"#/components/schemas/PlatformType"},"text":{"type":"string","description":"On LinkedIn, mention a company page with @[Page Name](urn:li:organization:<id>)"}}},"PlatformAspectRatio":{"type":"object","required":["platform","aspectRatio"],"properties":{"platform":{"$ref":"#/components/schemas/PlatformType"},"aspectRatio":{"type":"string","enum":["SQUARE","PORTRAIT","VERTICAL","LANDSCAPE"],"description":"`SQUARE` is 1:1, `PORTRAIT` 4:5, `VERTICAL` 9:16 and `LANDSCAPE` 1.91:1"},"fit":{"type":"string","enum":["CROP","PAD"],"description":"How an image of another shape reaches the ratio. `CROP` (the default) cuts it from the center; `PAD` keeps the whole image and fills the rest with a blurred copy of it"}}},"PlatformThumbnail":{"type":"object","required":["platform"],"properties":{"platform":{"$ref":"#/components/schemas/PlatformType"},"thumbnailUrl":{"type":"string","description":"The image to use as this platform's thumbnail, an https URL or an image data URI"},"thumbnailTimestampMs":{"type":"integer","minimum":0,"description":"The video frame (ms from the start) to use as this platform's thumbnail"}}},"PlatformFirstComment":{"type":"object","required":["platform","text"],"properties":{"platform":{"$ref":"#/components/schemas/PlatformType"},"text":{"type":"string","maxLength":10000,"description":"The comment's text, trimmed. The limit depends on the platform, see `firstComments`"}}},"FirstCommentStatus":{"type":"string","enum":["PENDING","PUBLISHED","FAILED"]},"PlatformThreadReplies":{"type":"object","required":["platform","texts"],"properties":{"platform":{"$ref":"#/components/schemas/PlatformType"},"texts":{"type":"array","maxItems":25,"items":{"type":"string","maxLength":25000},"description":"The replies in order, each trimmed. The limit per reply depends on the platform, see `threadReplies`"}}},"PostThreadStatus":{"type":"string","enum":["PENDING","PUBLISHED","FAILED"]},"PinterestPostConfig":{"type":"object","required":["connectionId"],"properties":{"connectionId":{"type":"string"},"boardId":{"type":"string","description":"A board `id` from `GET /social-accounts/{id}/pinterest-boards`. Leave out both `boardId` and `boardName` to pin to a public board named AdaptlyPost, created on the account the first time it is needed"},"boardName":{"type":"string","maxLength":180,"description":"The name of one of this account's boards, instead of `boardId`. AdaptlyPost looks it up when the post is created or updated and stores the board id. An exact match wins; otherwise the match ignores case. The request fails with 400 when no board has the name, when several do (the message lists their ids), or when `boardId` is also set. It never falls back to another board"},"title":{"type":"string","maxLength":100},"link":{"type":"string","format":"uri"}}},"PinterestBoard":{"type":"object","properties":{"id":{"type":"string","description":"Pass as `pinterestConfigs[].boardId`, or pass `name` as `pinterestConfigs[].boardName`"},"name":{"type":"string"},"description":{"type":"string"},"privacy":{"type":"string","description":"`PUBLIC`, `PROTECTED` or `SECRET`, as Pinterest reports it"},"pinCount":{"type":"integer"}}},"TikTokPostConfig":{"type":"object","required":["connectionId","privacyLevel"],"properties":{"connectionId":{"type":"string"},"title":{"type":"string","maxLength":90},"caption":{"type":"string","maxLength":4000},"privacyLevel":{"type":"string","enum":["PUBLIC_TO_EVERYONE","MUTUAL_FOLLOW_FRIENDS","FOLLOWER_OF_CREATOR","SELF_ONLY"]},"allowComments":{"type":"boolean"},"allowDuet":{"type":"boolean"},"allowStitch":{"type":"boolean"},"sendAsDraft":{"type":"boolean"},"aiGenerated":{"type":"boolean"},"brandedContent":{"type":"boolean"},"brandedContentOwnBrand":{"type":"boolean"},"autoAddMusic":{"type":"boolean"}}},"InstagramPostConfig":{"type":"object","required":["connectionId"],"properties":{"connectionId":{"type":"string"},"postType":{"type":"string","enum":["FEED","REEL","STORY"],"description":"Where the post is published. `FEED` works with every content type, `REEL` needs `contentType: VIDEO`, and `STORY` needs `IMAGE`, `VIDEO` or `CAROUSEL`. A `CAROUSEL` story publishes each media item as its own story, in order. Any other combination is rejected with a 400."},"shareToStory":{"type":"boolean","description":"Also publish the same media as a story on this account, next to the `FEED` or `REEL` post. The story shows as its own entry in `platforms` with `postType: STORY`, so it succeeds, fails and retries on its own. It skips the caption, first comment, cover, collaborators, user tags, trial and audio, needs `IMAGE`, `VIDEO` or `CAROUSEL`, and a video must fit the story length limit (60 seconds). Ignored when `postType` is `STORY`."},"trialGraduation":{"type":"string","enum":["MANUAL","SS_PERFORMANCE"],"description":"Publish the reel as a trial reel: Instagram shows it to non-followers first, and it stays off your followers' feeds and your profile grid until it is shared to them. `MANUAL` means you share it to followers yourself in the Instagram app; `SS_PERFORMANCE` means Instagram shares it automatically if it performs well. Omit it for a normal reel. Needs `contentType: VIDEO` and a `postType` of `REEL`, `FEED` or none; images, carousels and stories are rejected with a 400. Instagram decides which professional accounts can post trial reels and caps how many go out through the API; a refused trial fails that platform with an error saying so."},"collaborators":{"type":"array","maxItems":3,"items":{"type":"string","pattern":"^@?[A-Za-z0-9._]{1,30}$"},"description":"Instagram usernames invited as collaborators (Instagram Collab), up to 3. A leading `@` is stripped and duplicates are dropped. Works on feed images, carousels and reels; a story or a trial reel with collaborators is rejected with a 400. Each collaborator gets an invite in Instagram and must accept it before the post shows on their profile."},"userTags":{"type":"array","maxItems":20,"items":{"$ref":"#/components/schemas/InstagramUserTag"},"description":"Public Instagram accounts tagged in the media, up to 20. Works on a single image, a single video (published as a Reel) or a single story; a carousel or several stories with tags is rejected with a 400. On a feed image every tag needs `x` and `y`. On a story they are optional, and on a video they are ignored because the person is tagged on the video as a whole. A leading `@` is stripped and a repeated username keeps its first entry. If Instagram refuses a tag because the account is private or does not exist, the post goes out without its tags and `instagramUntaggedUsernames` lists the refused usernames."},"aiGenerated":{"type":"boolean","description":"Disclose that the post was made or edited with AI. Instagram shows its \"AI info\" label on the post. Works on images, carousels, reels and stories, and a story made with `shareToStory` carries the label too. Omit it or send `false` for no label."},"audio":{"$ref":"#/components/schemas/InstagramAudioConfig"}}},"InstagramUserTag":{"type":"object","required":["username"],"properties":{"username":{"type":"string","pattern":"^@?[A-Za-z0-9._]{1,30}$","description":"The public Instagram username to tag"},"x":{"type":"number","minimum":0,"maximum":1,"description":"Horizontal position of the tag on the image, from 0 (left edge) to 1 (right edge)"},"y":{"type":"number","minimum":0,"maximum":1,"description":"Vertical position of the tag on the image, from 0 (top edge) to 1 (bottom edge)"}}},"InstagramAudioConfig":{"type":"object","required":["audioId"],"description":"Music or an original sound from Instagram's audio library, added to the Reel when it is published. Needs `contentType: VIDEO` and a `postType` other than `STORY`, and only works for accounts with `supportsInstagramAudio: true` (connected through Facebook). Find ids with `GET /social-accounts/{id}/instagram-audio`.","properties":{"audioId":{"type":"string"},"title":{"type":"string","maxLength":255,"description":"Track title, stored for display only"},"artist":{"type":"string","maxLength":255,"description":"Artist or creator, stored for display only"},"audioVolume":{"type":"integer","minimum":1,"maximum":100,"description":"Volume of the added audio. Defaults to 100"},"videoVolume":{"type":"integer","minimum":1,"maximum":100,"description":"Volume of the video's own sound. Defaults to 100"}}},"InstagramAudio":{"type":"object","properties":{"audioId":{"type":"string","description":"Pass as `instagramConfigs[].audio.audioId`"},"audioType":{"type":"string","enum":["music","original_sound"]},"title":{"type":"string"},"displayArtist":{"type":"string","description":"Music only"},"igUsername":{"type":"string","description":"Original sounds only"},"durationMs":{"type":"integer"},"coverArtworkUrl":{"type":"string"},"profilePictureUrl":{"type":"string"},"previewUrl":{"type":"string","description":"Temporary audio file URL, expires after about 1.5 days"},"instagramUrl":{"type":"string"},"isAdsEligible":{"type":"boolean"}}},"FacebookPostConfig":{"type":"object","required":["pageId"],"properties":{"pageId":{"type":"string"},"postType":{"type":"string","enum":["FEED","REEL","STORY"],"description":"Where the post is published. `FEED` works with every content type, `REEL` needs `contentType: VIDEO`, and `STORY` needs `IMAGE`, `VIDEO` or `CAROUSEL`. A `CAROUSEL` story publishes each media item as its own story, in order. Any other combination is rejected with a 400."},"shareToStory":{"type":"boolean","description":"Also publish the same media as a story on this account, next to the `FEED` or `REEL` post. The story shows as its own entry in `platforms` with `postType: STORY`, so it succeeds, fails and retries on its own. It skips the caption, video title and text background, needs `IMAGE`, `VIDEO` or `CAROUSEL`, and a video must fit the story length limit (60 seconds). Ignored when `postType` is `STORY`."},"videoTitle":{"type":"string","maxLength":255},"textFormatPresetId":{"type":"string","pattern":"^\\d{1,20}$","example":"106018623298955","description":"Facebook's id for a colored text background (for example `106018623298955` is solid purple, `249307305544279` is a red to blue gradient). Only for `contentType: TEXT` posts with no media and text up to 130 characters; anything else is rejected with a 400. Links in the text show without a preview. If Facebook refuses the background, the post goes out as plain text."},"imageLayout":{"type":"string","enum":["GRID","CAROUSEL"],"default":"GRID","description":"How a post with several images shows on Facebook. `GRID` is a photo grid. `CAROUSEL` is a swipeable carousel where each image is a card with its own link, and needs 2 to 5 images, no videos, `postType` `FEED` and one `carouselCards` entry per image; anything else is rejected with a 400."},"carouselCards":{"type":"array","maxItems":5,"description":"One card per image, in the same order as the media, used when `imageLayout` is `CAROUSEL`. Facebook only shows your image, title and description on a card whose link points to a website the Page owns; for any other link the post fails with the error Facebook returns.","items":{"$ref":"#/components/schemas/FacebookCarouselCard"}}}},"FacebookCarouselCard":{"type":"object","required":["link"],"properties":{"link":{"type":"string","format":"uri","maxLength":2048,"description":"The http or https URL the card opens"},"title":{"type":"string","maxLength":100,"description":"The card's headline. Without it Facebook uses the linked page's title"},"description":{"type":"string","maxLength":200,"description":"The line under the headline, such as a price or the domain. Without it Facebook uses the linked page"}}},"LinkedInPostConfig":{"type":"object","required":["connectionId"],"properties":{"connectionId":{"type":"string"},"documentTitle":{"type":"string","maxLength":100,"description":"Title LinkedIn shows on a `DOCUMENT` post. Defaults to the uploaded file name. Ignored for every other content type"},"reshareOf":{"type":"string","maxLength":500,"description":"Reshare this LinkedIn post from the account, with the post text as the commentary. Takes a `urn:li:share:` or `urn:li:ugcPost:` URN, such as the `platformPostId` from /social-posts/{id}/results, or a LinkedIn post link of the form `https://www.linkedin.com/feed/update/<urn>`, which is also the link inside a post's Embed code. `urn:li:activity:` links are rejected because LinkedIn cannot reshare them through its API. Media on the post is not attached on this account"}}},"YouTubePostConfig":{"type":"object","required":["connectionId"],"properties":{"connectionId":{"type":"string"},"postType":{"type":"string","enum":["VIDEO","SHORTS"]},"videoTitle":{"type":"string","maxLength":100},"tags":{"type":"array","items":{"type":"string"},"maxItems":20},"privacyStatus":{"type":"string","enum":["public","private","unlisted"]},"license":{"type":"string","enum":["youtube","creativeCommon"]},"notifySubscribers":{"type":"boolean"},"allowEmbedding":{"type":"boolean"},"madeForKids":{"type":"boolean"},"aiGenerated":{"type":"boolean","description":"Disclose altered or synthetic content, such as an AI voice, an AI avatar or realistic footage that was generated or edited. YouTube shows its \"Altered or synthetic content\" label on the video. Sets `status.containsSyntheticMedia`. Omit it or send `false` for no label."},"categoryId":{"type":"string"},"playlistId":{"type":"string"}}},"GoogleBusinessPostConfig":{"type":"object","required":["connectionId","topicType"],"description":"Options for one Google Business Profile location. Google Business Profile takes `contentType` `TEXT` or `IMAGE` with one JPEG or PNG image up to 5 MB, and text up to 1500 characters","properties":{"connectionId":{"type":"string"},"topicType":{"type":"string","enum":["STANDARD","EVENT","OFFER"],"description":"`STANDARD` is an update. `EVENT` and `OFFER` need `eventTitle`, `eventStart` and `eventEnd`"},"callToActionType":{"type":"string","enum":["BOOK","ORDER","SHOP","LEARN_MORE","SIGN_UP","CALL"],"description":"Button shown on the post. Every type except `CALL` needs `callToActionUrl`; `CALL` dials the phone number on the Business Profile"},"callToActionUrl":{"type":"string","format":"uri","description":"Ignored when `callToActionType` is `CALL`"},"eventTitle":{"type":"string"},"eventStart":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2})?$","example":"2026-10-01T18:00","description":"`YYYY-MM-DD` or `YYYY-MM-DDTHH:mm` in the business's local time, with no offset. Google reads event times in the location's time zone"},"eventEnd":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2})?$","example":"2026-10-01T21:00","description":"`YYYY-MM-DD` or `YYYY-MM-DDTHH:mm` in the business's local time, with no offset"},"offerCouponCode":{"type":"string"},"offerRedeemUrl":{"type":"string","format":"uri"},"offerTerms":{"type":"string"}}},"TumblrPostConfig":{"type":"object","required":["connectionId"],"properties":{"connectionId":{"type":"string","description":"The Tumblr account `id` from /social-accounts"},"tags":{"type":"array","maxItems":30,"items":{"type":"string","maxLength":140,"pattern":"^[^,]+$"},"description":"Tumblr tags, without commas. A leading `#` is stripped and duplicates are dropped, ignoring case"},"title":{"type":"string","maxLength":4096,"description":"Shown as a heading above the media and the text"},"sourceUrl":{"type":"string","format":"uri","maxLength":2048,"description":"Shown as the source link of the post"}}},"WordPressPostConfig":{"type":"object","required":["connectionId"],"properties":{"connectionId":{"type":"string"},"title":{"type":"string","maxLength":300,"description":"Post title. Defaults to the first line of the text, cut to 100 characters"},"excerpt":{"type":"string","maxLength":1000,"description":"Summary WordPress shows in post lists and feeds"},"categoryIds":{"type":"array","maxItems":50,"items":{"type":"integer","minimum":1},"description":"Category ids from the site's own WordPress categories. Omitted, WordPress files the post under its default category"},"tags":{"type":"array","maxItems":50,"items":{"type":"string","maxLength":100},"description":"Tag names. A tag the site does not have yet is created when the WordPress user may manage tags, and skipped otherwise"}}},"CreateSocialPostRequest":{"type":"object","required":["contentType","timezone"],"anyOf":[{"required":["platforms"]},{"required":["accountIds"]}],"properties":{"platforms":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/PlatformType"},"description":"Platforms to post to. Each one also needs its connection ids. Optional when `accountIds` is given"},"accountIds":{"type":"array","items":{"type":"string"},"minItems":1,"description":"Account `id`s (or Facebook `pageId`s) from /social-accounts to post to. AdaptlyPost adds each account's platform to `platforms` and its id to the matching connection id list, so you can send these instead of `platforms` and the per-platform lists, or alongside them. An id that is not connected to the workspace returns 400"},"contentType":{"$ref":"#/components/schemas/ContentType"},"text":{"type":"string","description":"Post text/caption for all platforms. On LinkedIn, mention a company page with @[Page Name](urn:li:organization:<id>), using the page name exactly as LinkedIn shows it"},"platformTexts":{"type":"array","items":{"$ref":"#/components/schemas/PlatformText"},"description":"Platform-specific text overrides"},"platformAspectRatios":{"type":"array","items":{"$ref":"#/components/schemas/PlatformAspectRatio"},"description":"Reframe every image of an `IMAGE` or `CAROUSEL` post to one shape on a platform, one entry per platform. INSTAGRAM takes `SQUARE`, `PORTRAIT` or `LANDSCAPE` (Instagram refuses 9:16 feed and carousel images); TIKTOK takes all four. Other platforms, video posts, Instagram stories and a second entry for the same platform are rejected with a 400. Omit a platform to keep its images as uploaded. On an update it applies to the `mediaUrls` sent in the same request"},"mediaUrls":{"type":"array","items":{"type":"string"},"description":"Public HTTPS URLs of media to attach. Use POST /upload-urls to upload files first. A `DOCUMENT` post takes exactly one PDF, PPT, PPTX, DOC or DOCX URL, and a document file is only accepted on a `DOCUMENT` post. One uploaded URL may be reused across any number of posts; the file is kept until the last post referencing it has published. After publishing, the post's `mediaUrls` may hold expiring platform CDN links, so reuse the `publicUrl` you uploaded, not a URL read back from a published post"},"mediaAltTexts":{"type":"array","items":{"type":"string"},"description":"Alt text for each image, in the same order as mediaUrls (max 1000 characters each, empty string to skip one). Sent to X, Bluesky, Mastodon, Tumblr, WordPress, LinkedIn, Facebook, Instagram, Threads and Pinterest (first image only, max 500 characters). TikTok, YouTube and Google Business Profile have no alt text field"},"thumbnailUrl":{"type":"string","description":"Video thumbnail as an https URL or an image data URI, used on every platform that takes one unless `platformThumbnails` overrides it"},"thumbnailTimestampMs":{"type":"number","description":"Video frame timestamp (ms) to use as the thumbnail, used by YOUTUBE, INSTAGRAM, PINTEREST and TIKTOK unless `platformThumbnails` overrides it"},"platformThumbnails":{"type":"array","items":{"$ref":"#/components/schemas/PlatformThumbnail"},"description":"A different thumbnail for one platform of a `VIDEO` post, one entry per platform. A platform without an entry uses the post-level `thumbnailUrl` and `thumbnailTimestampMs`. FACEBOOK, LINKEDIN and TELEGRAM take an image (`thumbnailUrl`); YOUTUBE, INSTAGRAM and PINTEREST take an image or a frame (`thumbnailTimestampMs`), the image winning when both are sent; TIKTOK takes only a frame. Other platforms, posts that are not videos, Facebook and Instagram stories, a second entry for one platform and an entry the platform cannot use are rejected with a 400. On an update, sending the array replaces every override and omitting it keeps the stored ones"},"firstComments":{"type":"array","items":{"$ref":"#/components/schemas/PlatformFirstComment"},"description":"A comment posted from the same account right after the post goes out on a platform, one entry per platform. Available on LINKEDIN (1250 characters), TWITTER (280, as a reply), THREADS (500, as a reply), BLUESKY (300, as a reply), MASTODON (500, as a reply), YOUTUBE (10000), FACEBOOK (8000) and INSTAGRAM (2200). Other platforms, a platform the post does not go to, an empty or too long comment, a second entry for one platform, a private or made for kids YouTube video and Facebook or Instagram stories are rejected with a 400. The comment is posted about 10 seconds after the platform publishes (60 on YouTube) and retried up to 3 times; on X it is not retried, and a lifetime-deal account pays for it like any X post. A Facebook Page or Instagram account connected before first comments came to them must be reconnected once; until then its comment fails and `firstCommentError` says to reconnect. A comment that fails never fails the post: read `firstCommentStatus` and `firstCommentError` on the platform. On an update, sending the array replaces every first comment and omitting it keeps the stored ones"},"threadReplies":{"type":"array","items":{"$ref":"#/components/schemas/PlatformThreadReplies"},"description":"Turns the post into a thread: the post opens it and each text is published as a reply to the one before, from the same account, one entry per platform. Available on TWITTER (280 characters per reply, or the account's own limit on X Premium), THREADS (500), BLUESKY (300) and MASTODON (500, or the instance's limit), up to 25 replies. Other platforms, a platform the post does not go to, an empty or too long reply, more than 25 replies, a second entry for one platform and a platform that also has a first comment are rejected with a 400. An entry with an empty `texts` array removes the thread. Replies start about 10 seconds after the platform publishes, 2 seconds apart. A failed run is retried up to 3 times and resumes after the last reply that went out; on X it is not retried, and a lifetime-deal account pays for each reply like any X post. A thread that fails never fails the post: read `threadStatus`, `threadReplyIds` and `threadError` on the platform. On an update, sending the array replaces every thread and omitting it keeps the stored ones"},"scheduledAt":{"type":"string","format":"date-time","description":"ISO 8601 date-time. A future date schedules the post; omit it to publish immediately. With `saveAsDraft: true` it is the draft's planned date: the post stays a draft, and `POST /social-posts/{id}/publish` without `scheduledAt` schedules it for that date"},"timezone":{"type":"string","example":"UTC"},"saveAsDraft":{"type":"boolean"},"recurrence":{"$ref":"#/components/schemas/Recurrence"},"pageIds":{"type":"array","items":{"type":"string"},"description":"Facebook pages to post to. Accepts either the account `id` or the `pageId` returned by /social-accounts"},"tiktokConnectionIds":{"type":"array","items":{"type":"string"}},"threadsConnectionIds":{"type":"array","items":{"type":"string"}},"instagramConnectionIds":{"type":"array","items":{"type":"string"}},"twitterConnectionIds":{"type":"array","items":{"type":"string"}},"blueskyConnectionIds":{"type":"array","items":{"type":"string"}},"mastodonConnectionIds":{"type":"array","items":{"type":"string"}},"googleBusinessConnectionIds":{"type":"array","items":{"type":"string"},"description":"Google Business Profile locations to post to, by the account `id` from /social-accounts. A location without an entry in `googleBusinessConfigs` gets a `STANDARD` update"},"tumblrConnectionIds":{"type":"array","items":{"type":"string"},"description":"Tumblr blogs to post to, by the account `id` from /social-accounts. A post takes `TEXT`, `IMAGE`, `VIDEO` or `CAROUSEL`: text up to 32768 characters, up to 30 JPEG, PNG or GIF images (10 MB each) or one MP4 video (500 MB, up to 10 minutes), and alt text. `tumblrConfigs` adds tags, a title and a source link. Tumblr has no first comments, threads, per-platform thumbnails, image shapes or analytics"},"wordpressConnectionIds":{"type":"array","items":{"type":"string"},"description":"WordPress sites to post to, by the account `id` from /social-accounts. The text becomes the body of a published blog post: blank lines start new paragraphs and bare links become clickable. The first image is the featured image and the other images or the video follow the text. A site without an entry in `wordpressConfigs` uses the first line of the text as the title"},"telegramConnectionIds":{"type":"array","items":{"type":"string"},"description":"Telegram channels and groups to post to, by the account `id` from /social-accounts. A post takes text up to 4096 characters, up to 10 images (JPEG, PNG or WebP, 10 MB each) or one MP4 or MOV video (50 MB). A caption over 1024 characters goes out as its own message after the media"},"linkedinConnectionIds":{"type":"array","items":{"type":"string"}},"pinterestConnectionIds":{"type":"array","items":{"type":"string"}},"youtubeConnectionIds":{"type":"array","items":{"type":"string"}},"twitterKeepLinks":{"type":"boolean","description":"Keep links in the X text clickable. X charges over 10 times more for a post with a link, so by default we break every link in X text (`example.com` becomes `example. com`). Only AppSumo lifetime deals can turn this on, and a kept link costs 20 credits instead of 2. `true` on any other plan returns a 400; it is ignored when the X text has no link"},"pinterestConfigs":{"type":"array","items":{"$ref":"#/components/schemas/PinterestPostConfig"}},"tiktokConfigs":{"type":"array","items":{"$ref":"#/components/schemas/TikTokPostConfig"}},"instagramConfigs":{"type":"array","items":{"$ref":"#/components/schemas/InstagramPostConfig"}},"facebookConfigs":{"type":"array","items":{"$ref":"#/components/schemas/FacebookPostConfig"}},"youtubeConfigs":{"type":"array","items":{"$ref":"#/components/schemas/YouTubePostConfig"}},"googleBusinessConfigs":{"type":"array","items":{"$ref":"#/components/schemas/GoogleBusinessPostConfig"}},"tumblrConfigs":{"type":"array","items":{"$ref":"#/components/schemas/TumblrPostConfig"},"description":"Tumblr per-blog options: tags, a title and a source link. `connectionId` must match an entry in `tumblrConnectionIds`"},"wordpressConfigs":{"type":"array","items":{"$ref":"#/components/schemas/WordPressPostConfig"}},"linkedinConfigs":{"type":"array","items":{"$ref":"#/components/schemas/LinkedInPostConfig"}}}},"Recurrence":{"type":"object","required":["frequency"],"description":"Repeats the post. Requires a future `scheduledAt`, which becomes the first post and sets the time of day. Cannot be combined with `saveAsDraft` or TIKTOK","properties":{"frequency":{"type":"string","enum":["DAILY","WEEKLY","MONTHLY","YEARLY"]},"interval":{"type":"integer","minimum":1,"maximum":30,"default":1,"description":"Repeat every N days, weeks, months or years"},"weekdays":{"type":"array","items":{"type":"string","enum":["MONDAY","TUESDAY","WEDNESDAY","THURSDAY","FRIDAY","SATURDAY","SUNDAY"]},"description":"WEEKLY only. The weekday of `scheduledAt` is always included"},"endsOn":{"type":"string","format":"date","description":"Last day an occurrence may go out on. Cannot be combined with `maxOccurrences`"},"maxOccurrences":{"type":"integer","minimum":2,"maximum":365,"description":"Total number of posts the series publishes"}}},"RecurringPost":{"type":"object","properties":{"id":{"type":"string"},"userId":{"type":"string"},"status":{"type":"string","enum":["ACTIVE","PAUSED","ENDED"]},"pauseReason":{"type":"string","enum":["USER","CONSECUTIVE_FAILURES","SUBSCRIPTION_INACTIVE","ACCESS_LOST","CONNECTION_REMOVED","INVALID_CONTENT"]},"lastError":{"type":"string"},"frequency":{"type":"string","enum":["DAILY","WEEKLY","MONTHLY","YEARLY"]},"interval":{"type":"integer"},"weekdays":{"type":"array","items":{"type":"string","enum":["MONDAY","TUESDAY","WEDNESDAY","THURSDAY","FRIDAY","SATURDAY","SUNDAY"]}},"startsAt":{"type":"string","format":"date-time"},"timezone":{"type":"string"},"endsOn":{"type":"string","format":"date-time"},"maxOccurrences":{"type":"integer"},"nextOccurrenceAt":{"type":"string","format":"date-time","description":"The next occurrence that does not exist as a post yet. Absent once the series has ended"},"occurrenceCount":{"type":"integer","description":"Posts created by the series so far"},"contentType":{"$ref":"#/components/schemas/ContentType"},"text":{"type":"string"},"mediaUrls":{"type":"array","items":{"type":"string"}},"mediaAltTexts":{"type":"array","items":{"type":"string"}},"thumbnailUrl":{"type":"string"},"thumbnailTimestampMs":{"type":"number","description":"Video frame timestamp (ms) used as the thumbnail"},"platformTypes":{"type":"array","items":{"$ref":"#/components/schemas/PlatformType"}},"platforms":{"type":"array","items":{"$ref":"#/components/schemas/PostPlatform"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"RssFeedTarget":{"type":"object","required":["platform","connectionId"],"properties":{"platform":{"type":"string","enum":["FACEBOOK","INSTAGRAM","THREADS","TWITTER","BLUESKY","LINKEDIN","MASTODON","TELEGRAM","GOOGLE_BUSINESS"]},"connectionId":{"type":"string","description":"Account ID from `GET /social-accounts`"},"pageId":{"type":"string","description":"Facebook page ID. Required for FACEBOOK"},"displayName":{"type":"string","readOnly":true,"description":"The account's name, filled in by AdaptlyPost. Ignored when sent"}}},"RssFeedSettings":{"type":"object","properties":{"name":{"type":"string","maxLength":120,"description":"Defaults to the feed's title"},"targets":{"type":"array","minItems":1,"maxItems":20,"items":{"$ref":"#/components/schemas/RssFeedTarget"}},"postMode":{"type":"string","enum":["DRAFT","SCHEDULE","PUBLISH"],"description":"DRAFT creates a draft and needs `posts.draft`; SCHEDULE schedules the post `publishDelayMinutes` after the item is found and needs `posts.schedule`; PUBLISH publishes it right away and needs `posts.publish`"},"publishDelayMinutes":{"type":"integer","minimum":5,"maximum":10080,"description":"Required when `postMode` is SCHEDULE"},"contentMode":{"type":"string","enum":["TEMPLATE","AI"],"description":"TEMPLATE fills `template`; AI writes one caption per platform from the article, appends the link, spends 1 AI credit per platform per item and needs `ai.generate`"},"template":{"type":"string","maxLength":2000,"default":"{title}\n\n{link}","description":"Post text with `{title}`, `{link}`, `{description}`, `{author}` and `{feed}`. The description, then the title, is shortened to fit each platform; the link is never cut"},"aiInstructions":{"type":"string","maxLength":1000,"description":"Extra instructions for AI captions"},"includeImage":{"type":"boolean","default":true,"description":"Attach the item's image, or the article's preview image"},"twitterKeepLinks":{"type":"boolean","default":false,"description":"Keep links in X posts clickable. Lifetime-deal plans only; each X post with a link then costs more credits. Without it, links on X go out as plain text"},"includeKeywords":{"type":"array","maxItems":50,"items":{"type":"string"},"description":"Post only items whose title or summary contains one of these"},"excludeKeywords":{"type":"array","maxItems":50,"items":{"type":"string"},"description":"Skip items whose title or summary contains one of these"},"maxPostsPerCheck":{"type":"integer","minimum":1,"maximum":10,"default":3,"description":"New items are posted oldest first; the rest wait for the next check"},"checkIntervalMinutes":{"type":"integer","enum":[15,30,60,180,360,720,1440],"default":60}}},"CreateRssFeedRequest":{"allOf":[{"$ref":"#/components/schemas/RssFeedSettings"},{"type":"object","required":["url","targets","postMode","contentMode"],"properties":{"url":{"type":"string","format":"uri","description":"Public http(s) URL of an RSS or Atom feed"},"postLatestItem":{"type":"boolean","default":false,"description":"Also post the newest item on the first check"}}}]},"UpdateRssFeedRequest":{"$ref":"#/components/schemas/RssFeedSettings"},"PreviewRssFeedRequest":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri"},"template":{"type":"string","maxLength":2000,"default":"{title}\n\n{link}"}}},"RssFeed":{"type":"object","properties":{"id":{"type":"string"},"userId":{"type":"string","description":"Member the feed posts as: whoever last saved it"},"accountGroupId":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"},"siteUrl":{"type":"string"},"status":{"type":"string","enum":["ACTIVE","PAUSED"]},"pauseReason":{"type":"string","enum":["USER","FETCH_FAILURES","CONSECUTIVE_FAILURES","ACCESS_LOST","SUBSCRIPTION_INACTIVE","CONNECTION_REMOVED"],"description":"Why the feed stopped: USER (paused by hand), FETCH_FAILURES (5 failed fetches in a row), CONSECUTIVE_FAILURES (3 items in a row failed to post), ACCESS_LOST (its owner lost the permission its post mode needs), SUBSCRIPTION_INACTIVE (the plan no longer covers publishing) or CONNECTION_REMOVED (every target account was disconnected)"},"lastError":{"type":"string"},"postMode":{"type":"string","enum":["DRAFT","SCHEDULE","PUBLISH"],"description":"DRAFT creates a draft and needs `posts.draft`; SCHEDULE schedules the post `publishDelayMinutes` after the item is found and needs `posts.schedule`; PUBLISH publishes it right away and needs `posts.publish`"},"publishDelayMinutes":{"type":"integer"},"contentMode":{"type":"string","enum":["TEMPLATE","AI"],"description":"TEMPLATE fills `template`; AI writes one caption per platform from the article, appends the link, spends 1 AI credit per platform per item and needs `ai.generate`"},"template":{"type":"string"},"aiInstructions":{"type":"string"},"includeImage":{"type":"boolean"},"twitterKeepLinks":{"type":"boolean"},"includeKeywords":{"type":"array","items":{"type":"string"}},"excludeKeywords":{"type":"array","items":{"type":"string"}},"maxPostsPerCheck":{"type":"integer"},"checkIntervalMinutes":{"type":"integer"},"targets":{"type":"array","items":{"$ref":"#/components/schemas/RssFeedTarget"}},"nextCheckAt":{"type":"string","format":"date-time"},"lastCheckedAt":{"type":"string","format":"date-time"},"lastPostedAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"RssFeedItem":{"type":"object","properties":{"id":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"title":{"type":"string"},"link":{"type":"string"},"publishedAt":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["BASELINE","PROCESSING","POSTED","FILTERED","SKIPPED","FAILED"],"description":"BASELINE (already in the feed when it was added), PROCESSING, POSTED, FILTERED (keyword rules), SKIPPED (published more than 14 days before the feed was added) or FAILED"},"postId":{"type":"string"},"error":{"type":"string"}}},"RssFeedPreview":{"type":"object","properties":{"url":{"type":"string"},"title":{"type":"string"},"siteUrl":{"type":"string"},"items":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"link":{"type":"string"},"summary":{"type":"string"},"publishedAt":{"type":"string","format":"date-time"},"imageUrl":{"type":"string"},"text":{"type":"string","description":"The item rendered with `template`"}}}}}},"UpdateSocialPostRequest":{"type":"object","properties":{"platforms":{"type":"array","items":{"$ref":"#/components/schemas/PlatformType"}},"contentType":{"$ref":"#/components/schemas/ContentType"},"text":{"type":"string","description":"Post text/caption for all platforms. On LinkedIn, mention a company page with @[Page Name](urn:li:organization:<id>), using the page name exactly as LinkedIn shows it"},"platformTexts":{"type":"array","items":{"$ref":"#/components/schemas/PlatformText"},"description":"Platform-specific text overrides"},"platformAspectRatios":{"type":"array","items":{"$ref":"#/components/schemas/PlatformAspectRatio"},"description":"Reframe every image of an `IMAGE` or `CAROUSEL` post to one shape on a platform, one entry per platform. INSTAGRAM takes `SQUARE`, `PORTRAIT` or `LANDSCAPE` (Instagram refuses 9:16 feed and carousel images); TIKTOK takes all four. Other platforms, video posts, Instagram stories and a second entry for the same platform are rejected with a 400. Omit a platform to keep its images as uploaded. On an update it applies to the `mediaUrls` sent in the same request"},"mediaUrls":{"type":"array","items":{"type":"string"},"description":"Public HTTPS URLs of media to attach. Use POST /upload-urls to upload files first. A `DOCUMENT` post takes exactly one PDF, PPT, PPTX, DOC or DOCX URL, and a document file is only accepted on a `DOCUMENT` post. One uploaded URL may be reused across any number of posts; the file is kept until the last post referencing it has published. After publishing, the post's `mediaUrls` may hold expiring platform CDN links, so reuse the `publicUrl` you uploaded, not a URL read back from a published post"},"mediaAltTexts":{"type":"array","items":{"type":"string"},"description":"Alt text for each image, in the same order as mediaUrls (max 1000 characters each, empty string to skip one). Sent to X, Bluesky, Mastodon, Tumblr, WordPress, LinkedIn, Facebook, Instagram, Threads and Pinterest (first image only, max 500 characters). TikTok, YouTube and Google Business Profile have no alt text field"},"thumbnailUrl":{"type":"string","description":"Video thumbnail as an https URL or an image data URI, used on every platform that takes one unless `platformThumbnails` overrides it"},"thumbnailTimestampMs":{"type":"number","description":"Video frame timestamp (ms) to use as the thumbnail, used by YOUTUBE, INSTAGRAM, PINTEREST and TIKTOK unless `platformThumbnails` overrides it"},"platformThumbnails":{"type":"array","items":{"$ref":"#/components/schemas/PlatformThumbnail"},"description":"A different thumbnail for one platform of a `VIDEO` post, one entry per platform. A platform without an entry uses the post-level `thumbnailUrl` and `thumbnailTimestampMs`. FACEBOOK, LINKEDIN and TELEGRAM take an image (`thumbnailUrl`); YOUTUBE, INSTAGRAM and PINTEREST take an image or a frame (`thumbnailTimestampMs`), the image winning when both are sent; TIKTOK takes only a frame. Other platforms, posts that are not videos, Facebook and Instagram stories, a second entry for one platform and an entry the platform cannot use are rejected with a 400. On an update, sending the array replaces every override and omitting it keeps the stored ones"},"firstComments":{"type":"array","items":{"$ref":"#/components/schemas/PlatformFirstComment"},"description":"A comment posted from the same account right after the post goes out on a platform, one entry per platform. Available on LINKEDIN (1250 characters), TWITTER (280, as a reply), THREADS (500, as a reply), BLUESKY (300, as a reply), MASTODON (500, as a reply), YOUTUBE (10000), FACEBOOK (8000) and INSTAGRAM (2200). Other platforms, a platform the post does not go to, an empty or too long comment, a second entry for one platform, a private or made for kids YouTube video and Facebook or Instagram stories are rejected with a 400. The comment is posted about 10 seconds after the platform publishes (60 on YouTube) and retried up to 3 times; on X it is not retried, and a lifetime-deal account pays for it like any X post. A Facebook Page or Instagram account connected before first comments came to them must be reconnected once; until then its comment fails and `firstCommentError` says to reconnect. A comment that fails never fails the post: read `firstCommentStatus` and `firstCommentError` on the platform. On an update, sending the array replaces every first comment and omitting it keeps the stored ones"},"threadReplies":{"type":"array","items":{"$ref":"#/components/schemas/PlatformThreadReplies"},"description":"Turns the post into a thread: the post opens it and each text is published as a reply to the one before, from the same account, one entry per platform. Available on TWITTER (280 characters per reply, or the account's own limit on X Premium), THREADS (500), BLUESKY (300) and MASTODON (500, or the instance's limit), up to 25 replies. Other platforms, a platform the post does not go to, an empty or too long reply, more than 25 replies, a second entry for one platform and a platform that also has a first comment are rejected with a 400. An entry with an empty `texts` array removes the thread. Replies start about 10 seconds after the platform publishes, 2 seconds apart. A failed run is retried up to 3 times and resumes after the last reply that went out; on X it is not retried, and a lifetime-deal account pays for each reply like any X post. A thread that fails never fails the post: read `threadStatus`, `threadReplyIds` and `threadError` on the platform. On an update, sending the array replaces every thread and omitting it keeps the stored ones"},"scheduledAt":{"type":"string","format":"date-time","description":"New schedule time (ISO 8601). Moving a SCHEDULED post to a time in the past returns 400; to publish it now, call `POST /social-posts/{id}/publish` without `scheduledAt`"},"timezone":{"type":"string"},"pageIds":{"type":"array","items":{"type":"string"},"description":"Facebook pages to post to. Accepts either the account `id` or the `pageId` returned by /social-accounts"},"tiktokConnectionIds":{"type":"array","items":{"type":"string"}},"threadsConnectionIds":{"type":"array","items":{"type":"string"}},"instagramConnectionIds":{"type":"array","items":{"type":"string"}},"twitterConnectionIds":{"type":"array","items":{"type":"string"}},"blueskyConnectionIds":{"type":"array","items":{"type":"string"}},"mastodonConnectionIds":{"type":"array","items":{"type":"string"}},"googleBusinessConnectionIds":{"type":"array","items":{"type":"string"},"description":"Google Business Profile locations to post to, by the account `id` from /social-accounts. A location without an entry in `googleBusinessConfigs` gets a `STANDARD` update"},"tumblrConnectionIds":{"type":"array","items":{"type":"string"},"description":"Tumblr blogs to post to, by the account `id` from /social-accounts. A post takes `TEXT`, `IMAGE`, `VIDEO` or `CAROUSEL`: text up to 32768 characters, up to 30 JPEG, PNG or GIF images (10 MB each) or one MP4 video (500 MB, up to 10 minutes), and alt text. `tumblrConfigs` adds tags, a title and a source link. Tumblr has no first comments, threads, per-platform thumbnails, image shapes or analytics"},"wordpressConnectionIds":{"type":"array","items":{"type":"string"},"description":"WordPress sites to post to, by the account `id` from /social-accounts. The text becomes the body of a published blog post: blank lines start new paragraphs and bare links become clickable. The first image is the featured image and the other images or the video follow the text. A site without an entry in `wordpressConfigs` uses the first line of the text as the title"},"telegramConnectionIds":{"type":"array","items":{"type":"string"},"description":"Telegram channels and groups to post to, by the account `id` from /social-accounts. A post takes text up to 4096 characters, up to 10 images (JPEG, PNG or WebP, 10 MB each) or one MP4 or MOV video (50 MB). A caption over 1024 characters goes out as its own message after the media"},"linkedinConnectionIds":{"type":"array","items":{"type":"string"}},"pinterestConnectionIds":{"type":"array","items":{"type":"string"}},"youtubeConnectionIds":{"type":"array","items":{"type":"string"}},"twitterKeepLinks":{"type":"boolean","description":"Keep links in the X text clickable. X charges over 10 times more for a post with a link, so by default we break every link in X text (`example.com` becomes `example. com`). Only AppSumo lifetime deals can turn this on, and a kept link costs 20 credits instead of 2. `true` on any other plan returns a 400; it is ignored when the X text has no link"},"pinterestConfigs":{"type":"array","items":{"$ref":"#/components/schemas/PinterestPostConfig"}},"tiktokConfigs":{"type":"array","items":{"$ref":"#/components/schemas/TikTokPostConfig"}},"instagramConfigs":{"type":"array","items":{"$ref":"#/components/schemas/InstagramPostConfig"}},"facebookConfigs":{"type":"array","items":{"$ref":"#/components/schemas/FacebookPostConfig"}},"youtubeConfigs":{"type":"array","items":{"$ref":"#/components/schemas/YouTubePostConfig"}},"googleBusinessConfigs":{"type":"array","items":{"$ref":"#/components/schemas/GoogleBusinessPostConfig"}},"tumblrConfigs":{"type":"array","items":{"$ref":"#/components/schemas/TumblrPostConfig"},"description":"Tumblr per-blog options: tags, a title and a source link. `connectionId` must match an entry in `tumblrConnectionIds`"},"wordpressConfigs":{"type":"array","items":{"$ref":"#/components/schemas/WordPressPostConfig"}},"linkedinConfigs":{"type":"array","items":{"$ref":"#/components/schemas/LinkedInPostConfig"}}}},"BulkPostItem":{"type":"object","required":["contentType","scheduledAt"],"properties":{"contentType":{"type":"string","enum":["TEXT","IMAGE","VIDEO","CAROUSEL"],"description":"`DOCUMENT` posts cannot be bulk scheduled; create them one at a time with `POST /social-posts`"},"text":{"type":"string","description":"Post text/caption for all platforms. On LinkedIn, mention a company page with @[Page Name](urn:li:organization:<id>), using the page name exactly as LinkedIn shows it"},"platformTexts":{"type":"array","items":{"$ref":"#/components/schemas/PlatformText"},"description":"Platform-specific text overrides"},"platformAspectRatios":{"type":"array","items":{"$ref":"#/components/schemas/PlatformAspectRatio"},"description":"Reframe every image of an `IMAGE` or `CAROUSEL` post to one shape on a platform, one entry per platform. INSTAGRAM takes `SQUARE`, `PORTRAIT` or `LANDSCAPE` (Instagram refuses 9:16 feed and carousel images); TIKTOK takes all four. Other platforms, video posts, Instagram stories and a second entry for the same platform are rejected with a 400. Omit a platform to keep its images as uploaded. On an update it applies to the `mediaUrls` sent in the same request"},"mediaUrls":{"type":"array","items":{"type":"string"},"description":"Public HTTPS URLs of media to attach. Use POST /upload-urls to upload files first. A `DOCUMENT` post takes exactly one PDF, PPT, PPTX, DOC or DOCX URL, and a document file is only accepted on a `DOCUMENT` post. One uploaded URL may be reused across any number of posts; the file is kept until the last post referencing it has published. After publishing, the post's `mediaUrls` may hold expiring platform CDN links, so reuse the `publicUrl` you uploaded, not a URL read back from a published post"},"mediaAltTexts":{"type":"array","items":{"type":"string"},"description":"Alt text for each image, in the same order as mediaUrls (max 1000 characters each, empty string to skip one). Sent to X, Bluesky, Mastodon, Tumblr, WordPress, LinkedIn, Facebook, Instagram, Threads and Pinterest (first image only, max 500 characters). TikTok, YouTube and Google Business Profile have no alt text field"},"thumbnailUrl":{"type":"string","description":"Video thumbnail as an https URL or an image data URI, used on every platform that takes one unless `platformThumbnails` overrides it"},"thumbnailTimestampMs":{"type":"number","description":"Video frame timestamp (ms) to use as the thumbnail, used by YOUTUBE, INSTAGRAM, PINTEREST and TIKTOK unless `platformThumbnails` overrides it"},"platformThumbnails":{"type":"array","items":{"$ref":"#/components/schemas/PlatformThumbnail"},"description":"A different thumbnail for one platform of a `VIDEO` post, one entry per platform. A platform without an entry uses the post-level `thumbnailUrl` and `thumbnailTimestampMs`. FACEBOOK, LINKEDIN and TELEGRAM take an image (`thumbnailUrl`); YOUTUBE, INSTAGRAM and PINTEREST take an image or a frame (`thumbnailTimestampMs`), the image winning when both are sent; TIKTOK takes only a frame. Other platforms, posts that are not videos, Facebook and Instagram stories, a second entry for one platform and an entry the platform cannot use are rejected with a 400. On an update, sending the array replaces every override and omitting it keeps the stored ones"},"firstComments":{"type":"array","items":{"$ref":"#/components/schemas/PlatformFirstComment"},"description":"A comment posted from the same account right after the post goes out on a platform, one entry per platform. Available on LINKEDIN (1250 characters), TWITTER (280, as a reply), THREADS (500, as a reply), BLUESKY (300, as a reply), MASTODON (500, as a reply), YOUTUBE (10000), FACEBOOK (8000) and INSTAGRAM (2200). Other platforms, a platform the post does not go to, an empty or too long comment, a second entry for one platform, a private or made for kids YouTube video and Facebook or Instagram stories are rejected with a 400. The comment is posted about 10 seconds after the platform publishes (60 on YouTube) and retried up to 3 times; on X it is not retried, and a lifetime-deal account pays for it like any X post. A Facebook Page or Instagram account connected before first comments came to them must be reconnected once; until then its comment fails and `firstCommentError` says to reconnect. A comment that fails never fails the post: read `firstCommentStatus` and `firstCommentError` on the platform. On an update, sending the array replaces every first comment and omitting it keeps the stored ones"},"threadReplies":{"type":"array","items":{"$ref":"#/components/schemas/PlatformThreadReplies"},"description":"Turns the post into a thread: the post opens it and each text is published as a reply to the one before, from the same account, one entry per platform. Available on TWITTER (280 characters per reply, or the account's own limit on X Premium), THREADS (500), BLUESKY (300) and MASTODON (500, or the instance's limit), up to 25 replies. Other platforms, a platform the post does not go to, an empty or too long reply, more than 25 replies, a second entry for one platform and a platform that also has a first comment are rejected with a 400. An entry with an empty `texts` array removes the thread. Replies start about 10 seconds after the platform publishes, 2 seconds apart. A failed run is retried up to 3 times and resumes after the last reply that went out; on X it is not retried, and a lifetime-deal account pays for each reply like any X post. A thread that fails never fails the post: read `threadStatus`, `threadReplyIds` and `threadError` on the platform. On an update, sending the array replaces every thread and omitting it keeps the stored ones"},"scheduledAt":{"type":"string","format":"date-time"},"pinterestConfigs":{"type":"array","items":{"$ref":"#/components/schemas/PinterestPostConfig"}},"tiktokConfigs":{"type":"array","items":{"$ref":"#/components/schemas/TikTokPostConfig"}},"instagramConfigs":{"type":"array","items":{"$ref":"#/components/schemas/InstagramPostConfig"}},"facebookConfigs":{"type":"array","items":{"$ref":"#/components/schemas/FacebookPostConfig"}},"youtubeConfigs":{"type":"array","items":{"$ref":"#/components/schemas/YouTubePostConfig"}},"googleBusinessConfigs":{"type":"array","items":{"$ref":"#/components/schemas/GoogleBusinessPostConfig"}},"tumblrConfigs":{"type":"array","items":{"$ref":"#/components/schemas/TumblrPostConfig"},"description":"Tumblr per-blog options: tags, a title and a source link. `connectionId` must match an entry in `tumblrConnectionIds`"},"wordpressConfigs":{"type":"array","items":{"$ref":"#/components/schemas/WordPressPostConfig"}}}},"BulkSchedulePostsRequest":{"type":"object","required":["platforms","timezone","posts"],"properties":{"platforms":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/PlatformType"},"description":"Platforms to post to. Each one also needs its connection ids"},"timezone":{"type":"string","example":"UTC"},"posts":{"type":"array","minItems":1,"maxItems":100,"items":{"$ref":"#/components/schemas/BulkPostItem"}},"pageIds":{"type":"array","items":{"type":"string"},"description":"Facebook pages to post to. Accepts either the account `id` or the `pageId` returned by /social-accounts"},"tiktokConnectionIds":{"type":"array","items":{"type":"string"}},"threadsConnectionIds":{"type":"array","items":{"type":"string"}},"instagramConnectionIds":{"type":"array","items":{"type":"string"}},"twitterConnectionIds":{"type":"array","items":{"type":"string"}},"blueskyConnectionIds":{"type":"array","items":{"type":"string"}},"mastodonConnectionIds":{"type":"array","items":{"type":"string"}},"googleBusinessConnectionIds":{"type":"array","items":{"type":"string"},"description":"Google Business Profile locations to post to, by the account `id` from /social-accounts. A location without an entry in `googleBusinessConfigs` gets a `STANDARD` update"},"tumblrConnectionIds":{"type":"array","items":{"type":"string"},"description":"Tumblr blogs to post to, by the account `id` from /social-accounts. A post takes `TEXT`, `IMAGE`, `VIDEO` or `CAROUSEL`: text up to 32768 characters, up to 30 JPEG, PNG or GIF images (10 MB each) or one MP4 video (500 MB, up to 10 minutes), and alt text. `tumblrConfigs` adds tags, a title and a source link. Tumblr has no first comments, threads, per-platform thumbnails, image shapes or analytics"},"wordpressConnectionIds":{"type":"array","items":{"type":"string"},"description":"WordPress sites to post to, by the account `id` from /social-accounts. The text becomes the body of a published blog post: blank lines start new paragraphs and bare links become clickable. The first image is the featured image and the other images or the video follow the text. A site without an entry in `wordpressConfigs` uses the first line of the text as the title"},"telegramConnectionIds":{"type":"array","items":{"type":"string"},"description":"Telegram channels and groups to post to, by the account `id` from /social-accounts. A post takes text up to 4096 characters, up to 10 images (JPEG, PNG or WebP, 10 MB each) or one MP4 or MOV video (50 MB). A caption over 1024 characters goes out as its own message after the media"},"linkedinConnectionIds":{"type":"array","items":{"type":"string"}},"pinterestConnectionIds":{"type":"array","items":{"type":"string"}},"youtubeConnectionIds":{"type":"array","items":{"type":"string"}},"pinterestConfigs":{"type":"array","items":{"$ref":"#/components/schemas/PinterestPostConfig"}},"tiktokConfigs":{"type":"array","items":{"$ref":"#/components/schemas/TikTokPostConfig"}},"instagramConfigs":{"type":"array","items":{"$ref":"#/components/schemas/InstagramPostConfig"}},"facebookConfigs":{"type":"array","items":{"$ref":"#/components/schemas/FacebookPostConfig"}},"youtubeConfigs":{"type":"array","items":{"$ref":"#/components/schemas/YouTubePostConfig"}},"googleBusinessConfigs":{"type":"array","items":{"$ref":"#/components/schemas/GoogleBusinessPostConfig"}},"tumblrConfigs":{"type":"array","items":{"$ref":"#/components/schemas/TumblrPostConfig"},"description":"Tumblr per-blog options: tags, a title and a source link. `connectionId` must match an entry in `tumblrConnectionIds`"},"wordpressConfigs":{"type":"array","items":{"$ref":"#/components/schemas/WordPressPostConfig"}}}},"PublishDraftRequest":{"type":"object","required":["timezone"],"properties":{"scheduledAt":{"type":"string","format":"date-time","description":"Schedule for this date instead of the draft's planned date. A past date publishes now"},"timezone":{"type":"string","example":"UTC"},"publishNow":{"type":"boolean","description":"Publish now even when the draft has a planned date. Sending it with `scheduledAt` returns 400"}}},"RetryFailedPlatformsRequest":{"type":"object","properties":{"platformIds":{"type":"array","items":{"type":"string"},"description":"PostPlatform ids from GET /social-posts/{id}/results, or platform names such as \"BLUESKY\" to retry every failed entry of that platform. Omit it, or send an empty array, to retry every failed entry. Unknown values are rejected with 400"}}},"GetUploadUrlsRequest":{"type":"object","required":["files"],"properties":{"files":{"type":"array","minItems":1,"maxItems":20,"items":{"type":"object","required":["fileName","mimeType"],"properties":{"fileName":{"type":"string"},"mimeType":{"type":"string","enum":["image/jpeg","image/png","image/webp","image/gif","video/mp4","video/quicktime","application/pdf","application/vnd.ms-powerpoint","application/vnd.openxmlformats-officedocument.presentationml.presentation","application/msword","application/vnd.openxmlformats-officedocument.wordprocessingml.document"],"description":"GIF images post to Facebook, X, Bluesky, Mastodon, LinkedIn and Tumblr; every other platform refuses them when the post is created. Documents (PDF, PPT, PPTX, DOC, DOCX) are for LinkedIn `DOCUMENT` posts. Keep the file extension in `fileName`: the post reads the file type from it"}}}}}},"CreatePostResponse":{"type":"object","properties":{"postId":{"type":"string"},"queuedPlatforms":{"type":"array","items":{"$ref":"#/components/schemas/PlatformType"}},"skippedPlatforms":{"type":"array","items":{"type":"object","properties":{"platform":{"$ref":"#/components/schemas/PlatformType"},"reason":{"type":"string"}}}},"isScheduled":{"type":"boolean"},"scheduledAt":{"type":"string","format":"date-time"},"recurringPostId":{"type":"string","description":"Set when the request carried `recurrence`"}}},"PostPlatform":{"type":"object","properties":{"id":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"platform":{"$ref":"#/components/schemas/PlatformType"},"status":{"$ref":"#/components/schemas/PlatformPostStatus"},"connectionId":{"type":"string"},"pageId":{"type":"string","description":"For FACEBOOK, the Facebook page id — the same value as `pageId` on /social-accounts, and identical to `facebookPageExternalId` below. Posts created before that id was recorded return the account `id` from /social-accounts instead"},"accountName":{"type":"string"},"text":{"type":"string"},"platformPostId":{"type":"string"},"postUrl":{"type":"string","description":"Public link to the published post, set once the post is published. Instagram and Facebook stories expire after 24 hours, so for them it links to the profile or page that posted them"},"errorMessage":{"type":"string"},"publishedAt":{"type":"string","format":"date-time"},"mediaUrls":{"type":"array","items":{"type":"string"},"description":"The media as submitted. After publishing, some platforms replace these with their own CDN links, which expire, and the uploaded source files are removed. Use `previewUrls` for anything you display later"},"mediaAltTexts":{"type":"array","items":{"type":"string"}},"mediaAspectRatio":{"type":"string","enum":["SQUARE","PORTRAIT","VERTICAL","LANDSCAPE"],"description":"The aspect ratio chosen for this platform through `platformAspectRatios`; absent when the images went out as uploaded"},"mediaAspectRatioFit":{"type":"string","enum":["CROP","PAD"]},"thumbnailUrl":{"type":"string","description":"The thumbnail image set for this platform through `platformThumbnails`; absent when the platform uses the post-level thumbnail"},"thumbnailTimestampMs":{"type":"integer","description":"The video frame (ms) set for this platform through `platformThumbnails`"},"previewUrls":{"type":"array","items":{"type":"string"},"description":"Preview images we host (WebP, up to 720px), a still frame for videos, filled in shortly after publishing starts. They stay available after the source files and the platform links in mediaUrls are gone. Normally one entry per media item, where an empty string means that item could not be rendered; a post recovered after its media expired carries a single cover instead"},"firstComment":{"type":"string","description":"The first comment set through `firstComments`"},"firstCommentStatus":{"allOf":[{"$ref":"#/components/schemas/FirstCommentStatus"}],"description":"PENDING until the comment is posted, PUBLISHED once it is, FAILED when it could not be. Absent when the platform has no first comment"},"firstCommentId":{"type":"string","description":"The platform's id of the published comment"},"firstCommentError":{"type":"string","description":"Why the first comment failed"},"firstCommentPublishedAt":{"type":"string","format":"date-time"},"threadReplies":{"type":"array","items":{"type":"string"},"description":"The replies set through `threadReplies`, in order. Empty when the platform has no thread"},"threadStatus":{"allOf":[{"$ref":"#/components/schemas/PostThreadStatus"}],"description":"PENDING until every reply is posted, PUBLISHED once they are, FAILED when one could not be. Absent when the platform has no thread"},"threadReplyIds":{"type":"array","items":{"type":"string"},"description":"The platform's ids of the replies published so far, in order (AT URIs on Bluesky). Fewer ids than replies means the rest did not go out"},"threadError":{"type":"string","description":"Why the thread stopped"},"threadPublishedAt":{"type":"string","format":"date-time"},"pinterestBoardId":{"type":"string"},"pinterestTitle":{"type":"string"},"pinterestLink":{"type":"string"},"tiktokTitle":{"type":"string"},"tiktokCaption":{"type":"string"},"tiktokPrivacyLevel":{"type":"string"},"tiktokAllowComments":{"type":"boolean"},"tiktokAllowDuet":{"type":"boolean"},"tiktokAllowStitch":{"type":"boolean"},"tiktokSendAsDraft":{"type":"boolean"},"tiktokAiGenerated":{"type":"boolean"},"tiktokBrandedContent":{"type":"boolean"},"tiktokBrandedOwnBrand":{"type":"boolean"},"tiktokAutoAddMusic":{"type":"boolean"},"tiktokDraftFallback":{"type":"boolean","description":"TikTok's daily active-user cap was hit, so the content was delivered to the TikTok inbox as a draft instead of published directly"},"instagramPostType":{"type":"string"},"instagramTrialGraduation":{"type":"string","enum":["MANUAL","SS_PERFORMANCE"],"description":"Set when this Instagram reel publishes as a trial reel; see `InstagramPostConfig.trialGraduation`"},"instagramCollaborators":{"type":"array","items":{"type":"string"},"description":"Instagram usernames invited as collaborators; see `InstagramPostConfig.collaborators`"},"instagramUserTags":{"type":"array","items":{"$ref":"#/components/schemas/InstagramUserTag"},"description":"Instagram accounts tagged in the media; see `InstagramPostConfig.userTags`"},"instagramUntaggedUsernames":{"type":"array","items":{"type":"string"},"description":"Tagged accounts Instagram refused because they are private or do not exist. The post went out without its tags, and this lists the refused usernames"},"instagramAiGenerated":{"type":"boolean","description":"Set when the Instagram post carries the AI info label; see `InstagramPostConfig.aiGenerated`"},"instagramUsername":{"type":"string","description":"The Instagram handle the entry was published from. Set once an INSTAGRAM entry publishes"},"instagramAudioId":{"type":"string"},"instagramAudioTitle":{"type":"string"},"instagramAudioArtist":{"type":"string"},"instagramAudioVolume":{"type":"integer"},"instagramVideoVolume":{"type":"integer"},"facebookPostType":{"type":"string"},"facebookVideoTitle":{"type":"string"},"facebookTextFormatPresetId":{"type":"string","description":"The Facebook text background sent with the post; see `FacebookPostConfig.textFormatPresetId`"},"facebookImageLayout":{"type":"string","enum":["GRID","CAROUSEL"],"description":"See `FacebookPostConfig.imageLayout`"},"facebookCarouselCards":{"type":"array","items":{"$ref":"#/components/schemas/FacebookCarouselCard"},"description":"The carousel cards, one per image; see `FacebookPostConfig.carouselCards`"},"facebookPageExternalId":{"type":"string","description":"The Facebook page id this platform entry publishes to. Always set for FACEBOOK entries created since the id was recorded"},"youtubePostType":{"type":"string"},"youtubeVideoTitle":{"type":"string"},"youtubeTags":{"type":"array","items":{"type":"string"}},"youtubePrivacyStatus":{"type":"string"},"youtubeLicense":{"type":"string"},"youtubeNotifySubscribers":{"type":"boolean"},"youtubeAllowEmbedding":{"type":"boolean"},"youtubeMadeForKids":{"type":"boolean"},"youtubeAiGenerated":{"type":"boolean","description":"Set when the YouTube video carries the altered or synthetic content label; see `YouTubePostConfig.aiGenerated`"},"youtubeCategoryId":{"type":"string"},"youtubePlaylistId":{"type":"string"},"linkedinDocumentTitle":{"type":"string","description":"The title set for a LinkedIn `DOCUMENT` post, when one was given"},"linkedinReshareOf":{"type":"string","description":"The LinkedIn post URN this account reshares, when the post is a reshare"},"twitterKeepLinks":{"type":"boolean","description":"Whether links in this X post stay clickable. Only honored for AppSumo lifetime deals"},"googleBusinessTopicType":{"type":"string"},"googleBusinessCallToActionType":{"type":"string"},"googleBusinessCallToActionUrl":{"type":"string"},"googleBusinessEventTitle":{"type":"string"},"googleBusinessEventStart":{"type":"string"},"googleBusinessEventEnd":{"type":"string"},"googleBusinessOfferCouponCode":{"type":"string"},"googleBusinessOfferRedeemUrl":{"type":"string"},"googleBusinessOfferTerms":{"type":"string"},"tumblrTags":{"type":"array","items":{"type":"string"}},"tumblrTitle":{"type":"string"},"tumblrSourceUrl":{"type":"string"},"wordpressTitle":{"type":"string"},"wordpressExcerpt":{"type":"string"},"wordpressCategoryIds":{"type":"array","items":{"type":"integer"}},"wordpressTags":{"type":"array","items":{"type":"string"}}}},"Post":{"type":"object","properties":{"id":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"userId":{"type":"string"},"contentType":{"$ref":"#/components/schemas/ContentType"},"text":{"type":"string"},"scheduledAt":{"type":"string","format":"date-time"},"timezone":{"type":"string"},"status":{"$ref":"#/components/schemas/PostStatus"},"thumbnailUrl":{"type":"string"},"thumbnailTimestampMs":{"type":"number","description":"Video frame timestamp (ms) used as the thumbnail"},"mediaUrls":{"type":"array","items":{"type":"string"},"description":"The media as submitted, shared by every platform entry. See `mediaUrls` on PostPlatform for how these change after publishing"},"mediaAltTexts":{"type":"array","items":{"type":"string"}},"platforms":{"type":"array","items":{"$ref":"#/components/schemas/PostPlatform"}},"recurringPostId":{"type":"string","description":"The recurring post this post is an occurrence of"},"occurrenceAt":{"type":"string","format":"date-time","description":"The slot of the series this post fills. Stays the same when the post is rescheduled"}}},"SocialAccount":{"type":"object","properties":{"id":{"type":"string","description":"The connection id to pass in the platform's `*ConnectionIds` array. For FACEBOOK this identifies the connected page and is not the Facebook page id — see `pageId`"},"platform":{"$ref":"#/components/schemas/PlatformType"},"displayName":{"type":"string"},"username":{"type":"string"},"avatarUrl":{"type":"string"},"status":{"$ref":"#/components/schemas/SocialAccountStatus"},"unauthorizedReason":{"type":"string","description":"The platform's own rejection message. Present only while `status` is `unauthorized`"},"pageId":{"type":"string","description":"The Facebook page id. Present for FACEBOOK page accounts — accepted in `pageIds` (as is this account `id`), and returned as `pageId` and `facebookPageExternalId` on post platforms"},"supportsInstagramAudio":{"type":"boolean","description":"INSTAGRAM only. True when the account was connected through Facebook, which Meta requires for adding Instagram audio to Reels"}}},"SocialAccountStatus":{"type":"string","enum":["active","unauthorized"],"description":"`unauthorized` means the platform rejected the stored token: posts to this account are refused with a 400 until it is reconnected in the dashboard"},"SocialAccountCheckResult":{"type":"object","properties":{"id":{"type":"string"},"platform":{"$ref":"#/components/schemas/PlatformType"},"displayName":{"type":"string"},"pageId":{"type":"string"},"status":{"$ref":"#/components/schemas/SocialAccountStatus"},"unauthorizedReason":{"type":"string","description":"The platform's own rejection message, when `status` is `unauthorized`"},"checkedAt":{"type":"string","format":"date-time"}}},"SocialAccountRemovalResult":{"type":"object","properties":{"id":{"type":"string"},"platform":{"$ref":"#/components/schemas/PlatformType"},"displayName":{"type":"string"},"pageId":{"type":"string","description":"The Facebook page id, for FACEBOOK accounts"},"removed":{"type":"boolean","enum":[true]}}},"WebhookAccount":{"type":"object","description":"The account an `account.unauthorized` delivery is about. `id` matches the account `id` on /social-accounts","properties":{"id":{"type":"string"},"platform":{"$ref":"#/components/schemas/PlatformType"},"displayName":{"type":"string"},"pageId":{"type":"string","description":"The Facebook page id, for FACEBOOK accounts"},"status":{"type":"string","enum":["unauthorized"]},"reason":{"type":"string","description":"The platform's own rejection message"}}},"WebhookImage":{"type":"object","description":"The generation job an `image.completed` or `image.failed` delivery is about. `jobId` and `sessionId` match the POST /ai/images response","required":["jobId","sessionId","prompt"],"properties":{"jobId":{"type":"string"},"sessionId":{"type":"string","format":"uuid"},"prompt":{"type":"string"},"imageUrl":{"type":"string","description":"Public URL of the generated image, on image.completed"},"imageId":{"type":"string","description":"ID of the generated image, on image.completed"},"error":{"type":"string","description":"Why generation failed, on image.failed"}}},"CreateConnectLinkRequest":{"type":"object","properties":{"name":{"type":"string","maxLength":80,"description":"Label shown in the dashboard list of links"},"visibility":{"type":"string","enum":["PUBLIC","PRIVATE"],"description":"`PRIVATE` shows the client only the accounts they connected through this link. Defaults to `PUBLIC`"},"allowedPlatforms":{"type":"array","items":{"type":"string","enum":["FACEBOOK","INSTAGRAM","THREADS","TIKTOK","TWITTER","BLUESKY","LINKEDIN","PINTEREST","YOUTUBE","MASTODON","TELEGRAM","GOOGLE_BUSINESS","TUMBLR","WORDPRESS"]},"uniqueItems":true,"description":"Platforms the client can pick. Omit or send [] for every platform"},"maxAccounts":{"type":"integer","minimum":1,"description":"Accounts the link can connect in total. Reconnecting an account it already connected does not count again"},"expiresAt":{"type":"string","format":"date-time","description":"When the link stops working, as an ISO 8601 date-time with a `Z` or `±hh:mm` offset, such as `2026-11-30T23:59:59Z`. At least 1 hour and at most 365 days from now. Defaults to 7 days from now. Leave it out when `neverExpires` is true"},"neverExpires":{"type":"boolean","description":"true keeps the link working until it is revoked or reaches `maxAccounts`. The response then has `expiresAt: null`"}}},"CreateWebhookRequest":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri","description":"Publicly reachable http(s) endpoint. Receives all events"}}},"UpdateWebhookRequest":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"active":{"type":"boolean"}}},"Webhook":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"active":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"lastSuccessAt":{"type":"string","format":"date-time","nullable":true},"lastFailureAt":{"type":"string","format":"date-time","nullable":true},"disabledAt":{"type":"string","format":"date-time","nullable":true}}},"CreateWebhookResponse":{"allOf":[{"$ref":"#/components/schemas/Webhook"},{"type":"object","properties":{"secret":{"type":"string","description":"HMAC-SHA256 signing secret (whsec_...) for the x-adaptly-signature header. Returned ONLY at creation, store it securely; if lost, delete and re-create the webhook"}}}]},"WebhookEventPayload":{"type":"object","description":"Body of webhook deliveries POSTed to registered endpoints. Verify authenticity by comparing the x-adaptly-signature header to sha256=HMAC_SHA256(secret, \"{x-adaptly-timestamp}.{rawBody}\")","properties":{"id":{"type":"string","description":"Unique delivery ID"},"event":{"description":"The event name. POST /webhooks/{id}/test sends `webhook.test`, which is never delivered otherwise","anyOf":[{"$ref":"#/components/schemas/WebhookEventName"},{"type":"string","enum":["webhook.test"]}]},"createdAt":{"type":"string","format":"date-time"},"data":{"type":"object","description":"Carries `post` for post.* events, `account` for account.* events and `image` for image.* events. A `webhook.test` delivery carries `webhookId` and `events` instead","properties":{"post":{"$ref":"#/components/schemas/Post"},"account":{"$ref":"#/components/schemas/WebhookAccount"},"image":{"$ref":"#/components/schemas/WebhookImage"},"webhookId":{"type":"string","description":"The webhook being tested, on webhook.test"},"events":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEventName"},"description":"Every event the endpoint will receive, on webhook.test"}}}}},"AnalyticsGranularity":{"type":"string","enum":["DAILY","WEEKLY","MONTHLY"]},"AnalyticsSortMetric":{"type":"string","enum":["VIEWS","LIKES","COMMENTS","SHARES","SAVES","CLICKS","IMPRESSIONS","ENGAGEMENT_RATE","PUBLISHED_AT"]},"AnalyticsSyncJobStatus":{"type":"string","enum":["IDLE","QUEUED","SYNCING","FAILED"]},"AnalyticsMetricValue":{"type":"object","description":"A metric for the requested window next to the same metric for the previous window of equal length. `null` when no selected platform reports it","properties":{"value":{"type":"number","nullable":true},"previousValue":{"type":"number","nullable":true},"deltaPercent":{"type":"number","nullable":true,"description":"Percentage change from previousValue to value. Null when previousValue is 0 or unknown"}}},"AnalyticsOverview":{"type":"object","properties":{"views":{"$ref":"#/components/schemas/AnalyticsMetricValue"},"likes":{"$ref":"#/components/schemas/AnalyticsMetricValue"},"comments":{"$ref":"#/components/schemas/AnalyticsMetricValue"},"shares":{"$ref":"#/components/schemas/AnalyticsMetricValue"},"followers":{"allOf":[{"$ref":"#/components/schemas/AnalyticsMetricValue"}],"description":"Latest follower count as of `to`, compared with the count as of the end of the previous window"},"postsCount":{"$ref":"#/components/schemas/AnalyticsMetricValue"},"avgViewsPerPost":{"$ref":"#/components/schemas/AnalyticsMetricValue"},"engagementRate":{"allOf":[{"$ref":"#/components/schemas/AnalyticsMetricValue"}],"description":"Engagements (likes + comments + shares) divided by views, as a percentage"},"partialMetrics":{"type":"array","items":{"type":"string"},"description":"Metric names that at least one selected platform cannot report; their totals cover only the platforms that can"},"lastSyncedAt":{"type":"string","format":"date-time","nullable":true,"description":"Most recent successful sync across the selected platforms. Null when nothing has synced yet"}}},"AnalyticsTimeseriesPoint":{"type":"object","properties":{"date":{"type":"string","format":"date-time","description":"Start of the bucket (UTC)"},"views":{"type":"number","nullable":true},"likes":{"type":"number","nullable":true},"comments":{"type":"number","nullable":true},"shares":{"type":"number","nullable":true},"followers":{"type":"number","nullable":true,"description":"Latest known follower count at the end of the bucket"},"postsCount":{"type":"number","nullable":true},"engagementRate":{"type":"number","nullable":true}}},"AnalyticsPostMetrics":{"type":"object","description":"Latest captured counters for one post. A metric the platform does not report is null","properties":{"views":{"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},"impressions":{"type":"number","nullable":true},"reach":{"type":"number","nullable":true},"engagementRate":{"type":"number","nullable":true},"engagedViews":{"type":"number","nullable":true,"description":"YouTube only. Views that played past the first frame, the way YouTube counted views before it began counting every start. Null on other platforms and until YouTube Analytics reports the video, which lags by a few days"},"averageViewDurationSeconds":{"type":"number","nullable":true,"description":"YouTube only. Average length of a playback, in seconds, over the video's lifetime. Null on other platforms and until YouTube Analytics reports the video"},"averageViewPercentage":{"type":"number","nullable":true,"description":"YouTube only. Average share of the video watched per playback, as a percentage (0-100, can exceed 100 when viewers rewatch). Null on other platforms and until YouTube Analytics reports the video"}}},"AnalyticsPost":{"type":"object","properties":{"id":{"type":"string","description":"Analytics record id. The only id every tracked post has, including posts discovered on the account"},"postId":{"type":"string","nullable":true,"description":"The AdaptlyPost post id (usable with /social-posts/{id}). Null for a post discovered on the account rather than published through AdaptlyPost"},"postPlatformId":{"type":"string","nullable":true,"description":"The `platformId` from /social-posts/{id}/results. Null for discovered posts"},"platform":{"$ref":"#/components/schemas/PlatformType"},"publishedAt":{"type":"string","format":"date-time"},"title":{"type":"string","nullable":true},"thumbnailUrl":{"type":"string","nullable":true},"permalink":{"type":"string","nullable":true,"description":"Public URL of the post on the platform, when known"},"connectionId":{"type":"string","description":"The account `id` from /social-accounts that the post belongs to"},"accountName":{"type":"string","nullable":true},"metrics":{"$ref":"#/components/schemas/AnalyticsPostMetrics"}}},"DiscoveredPost":{"type":"object","properties":{"id":{"type":"string","description":"Analytics record id"},"platform":{"$ref":"#/components/schemas/PlatformType"},"publishedAt":{"type":"string","format":"date-time"},"text":{"type":"string","nullable":true},"thumbnailUrl":{"type":"string","nullable":true},"permalink":{"type":"string","nullable":true},"connectionId":{"type":"string","description":"The account `id` from /social-accounts that the post belongs to"},"accountName":{"type":"string","nullable":true}}},"AnalyticsPlatformBreakdownItem":{"type":"object","properties":{"platform":{"$ref":"#/components/schemas/PlatformType"},"followers":{"$ref":"#/components/schemas/AnalyticsMetricValue"},"views":{"$ref":"#/components/schemas/AnalyticsMetricValue"},"likes":{"$ref":"#/components/schemas/AnalyticsMetricValue"},"comments":{"$ref":"#/components/schemas/AnalyticsMetricValue"},"shares":{"$ref":"#/components/schemas/AnalyticsMetricValue"},"postsCount":{"$ref":"#/components/schemas/AnalyticsMetricValue"},"avgViewsPerPost":{"$ref":"#/components/schemas/AnalyticsMetricValue"},"engagementRate":{"$ref":"#/components/schemas/AnalyticsMetricValue"},"supportedMetrics":{"type":"array","items":{"type":"string"},"description":"Metric names this platform reports"}}},"AnalyticsPlatformSyncStatus":{"type":"object","properties":{"platform":{"$ref":"#/components/schemas/PlatformType"},"connectionId":{"type":"string","description":"The account `id` from /social-accounts"},"accountName":{"type":"string","nullable":true},"status":{"$ref":"#/components/schemas/AnalyticsSyncJobStatus"},"lastSyncedAt":{"type":"string","format":"date-time","nullable":true},"lastErrorMessage":{"type":"string","nullable":true},"historyHorizonAt":{"type":"string","format":"date-time","nullable":true,"description":"Oldest publish date this account has data for. Earlier dates have no data rather than zero activity"},"lastDiscoveryAt":{"type":"string","format":"date-time","nullable":true},"needsAnalyticsReconnect":{"type":"boolean","description":"True when the account was connected before analytics permissions existed. It stays parked until the user reconnects it (a connect link works) and approves the extra permissions"}}},"AnalyticsSyncStatus":{"type":"object","properties":{"accountGroupId":{"type":"string"},"syncInProgress":{"type":"boolean","description":"True while any account is queued or syncing"},"lastSyncedAt":{"type":"string","format":"date-time","nullable":true},"historyHorizonAt":{"type":"string","format":"date-time","nullable":true,"description":"Earliest date any connected account has data for"},"platforms":{"type":"array","items":{"$ref":"#/components/schemas/AnalyticsPlatformSyncStatus"}}}},"TriggerAnalyticsSyncResponse":{"type":"object","properties":{"queued":{"type":"boolean","description":"True when a sync was queued. False inside the 4 hour cooldown, or when no connected account supports analytics"},"message":{"type":"string"},"cooldownSecondsRemaining":{"type":"integer","nullable":true,"description":"Seconds until the next sync can be requested; null when queued"}}}}}}