{"openapi":"3.1.0","info":{"title":"VIBEPOST API","version":"1.0.0","summary":"Schedule and publish social posts; let the VIBEPOST agent write versions and pick times.","description":"REST API for VIBEPOST workspaces. Authenticate with a workspace API key (`Authorization: Bearer vp_…`, Settings → Developers) or OAuth 2.1 (authorization code + PKCE; metadata at /.well-known/oauth-authorization-server). Read-only keys can call every GET plus `POST /posts/preview`. Rules (quiet hours, daily caps, link rules, platform limits) apply to every request exactly as in the app. TikTok posts made through the API always come back as `needs_approval` and wait for the creator in the app. Deleting through the API is off unless the workspace turns it on. Errors are `{ error: { code, message, details? } }`.","contact":{"name":"ANYTUTOR, INC.","url":"https://vibepost.cc"}},"servers":[{"url":"https://vibepost.cc/api/v1"}],"security":[{"bearer":[]},{"oauth2":["read","write"]}],"tags":[{"name":"Posts"},{"name":"Channels"},{"name":"Analytics"},{"name":"Webhooks"},{"name":"Auth"}],"paths":{"/me":{"get":{"tags":["Auth"],"summary":"The workspace and scope of this key","operationId":"getMe","responses":{"200":{"description":"Workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"502":{"$ref":"#/components/responses/Error"}}}},"/channels":{"get":{"tags":["Channels"],"summary":"Connected channels and their limits","operationId":"listChannels","responses":{"200":{"description":"Channels","content":{"application/json":{"schema":{"type":"object","properties":{"channels":{"type":"array","items":{"$ref":"#/components/schemas/Channel"}}},"required":["channels"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"502":{"$ref":"#/components/responses/Error"}}}},"/posts":{"get":{"tags":["Posts"],"summary":"List posts","operationId":"listPosts","parameters":[{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["draft","needs_approval","scheduled","publishing","published","failed","deleted"]}},{"name":"channel_id","in":"query","required":false,"schema":{"type":"string","maxLength":100}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"Posts","content":{"application/json":{"schema":{"type":"object","properties":{"posts":{"type":"array","items":{"$ref":"#/components/schemas/Post"}}},"required":["posts"]},"example":{"posts":[{"id":"post_8k2m4q9x7c1v3b5n6z0a","batch_id":"batch_1a2b3c4d5e6f7g8h9i0j","channel_id":"cm_x_channel","platform":"x","lang":"ja","text":"何でも学べる。何でも聞ける。","media":[],"schedule_at":"2026-10-26T12:00:00.000Z","status":"scheduled","source":"api","release_url":null,"error":null,"created_at":"2026-10-21T03:00:00.000Z","updated_at":"2026-10-21T03:00:01.000Z","published_at":null}]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"502":{"$ref":"#/components/responses/Error"}}},"post":{"tags":["Posts"],"summary":"Create posts (one per channel × language)","description":"Set `variants: \"auto\"` to let the agent write a native version per channel and language from `text`, and `schedule_at: \"auto\"` to let it pick times from your rules and best times. Each created post is `scheduled` (published by the queue at `schedule_at`) or `needs_approval` (TikTok). Follow it with GET /posts/{id} or the webhooks. Rule problems reject the whole request with `rule_violation` and create nothing. Send `Idempotency-Key` to make retries safe: a repeated key returns the first response with `Idempotent-Replayed: true`.","operationId":"createPosts","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePosts"},"examples":{"auto":{"summary":"AI writes and times it","value":{"text":"We launched AI tutoring in Japanese. https://anytutor.ai","channels":["x","linkedin"],"languages":["en","ja"],"variants":"auto","schedule_at":"auto"}},"explicit":{"summary":"Exact text, fixed time","value":{"text":"Office hours tonight at 9.","channels":["x"],"schedule_at":"2026-10-26T21:00:00+09:00"}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateResult"},"example":{"batch_id":"batch_1a2b3c4d5e6f7g8h9i0j","posts":[{"id":"post_8k2m4q9x7c1v3b5n6z0a","batch_id":"batch_1a2b3c4d5e6f7g8h9i0j","channel_id":"cm_x_channel","platform":"x","lang":"ja","text":"何でも学べる。何でも聞ける。","media":[],"schedule_at":"2026-10-26T12:00:00.000Z","status":"scheduled","source":"api","release_url":null,"error":null,"created_at":"2026-10-21T03:00:00.000Z","updated_at":"2026-10-21T03:00:01.000Z","published_at":null}]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"502":{"$ref":"#/components/responses/Error"}}}},"/posts/preview":{"post":{"tags":["Posts"],"summary":"Preview what POST /posts would create, without creating anything","description":"Same body as `POST /posts`. Returns the texts, times and any rule problems. Allowed for read-only keys (MCP `generate_variants`).","operationId":"previewPosts","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePosts"}}}},"responses":{"200":{"description":"Preview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Preview"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"502":{"$ref":"#/components/responses/Error"}}}},"/posts/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"tags":["Posts"],"summary":"Get a post","operationId":"getPost","responses":{"200":{"description":"Post","content":{"application/json":{"schema":{"type":"object","properties":{"post":{"$ref":"#/components/schemas/Post"}}}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"502":{"$ref":"#/components/responses/Error"}}},"patch":{"tags":["Posts"],"summary":"Change text, time or media","operationId":"updatePost","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string","minLength":1,"maxLength":40000},"schedule_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"media":{"maxItems":10,"type":"array","items":{"type":"object","properties":{"url":{"type":"string","maxLength":2000,"format":"uri"},"id":{"type":"string","maxLength":100}},"required":["url"]}},"settings":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"first_comment":{"anyOf":[{"type":"string","maxLength":5000},{"type":"null"}]},"tags":{"maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":40}}}},"example":{"schedule_at":"2026-10-27T10:00:00+09:00"}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"type":"object","properties":{"post":{"$ref":"#/components/schemas/Post"}}}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"502":{"$ref":"#/components/responses/Error"}}},"delete":{"tags":["Posts"],"summary":"Delete a post (off unless enabled in Settings)","operationId":"deletePost","responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"post":{"$ref":"#/components/schemas/Post"}}}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"502":{"$ref":"#/components/responses/Error"}}}},"/posts/{id}/schedule":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"post":{"tags":["Posts"],"summary":"Schedule a draft","operationId":"scheduleDraft","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"schedule_at":{"type":"string","description":"ISO 8601, \"now\" or \"auto\""}},"required":["schedule_at"]}}}},"responses":{"200":{"description":"Scheduled","content":{"application/json":{"schema":{"type":"object","properties":{"post":{"$ref":"#/components/schemas/Post"}}}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"502":{"$ref":"#/components/responses/Error"}}}},"/posts/{id}/retry":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"post":{"tags":["Posts"],"summary":"Retry a failed post","description":"Checks whether the earlier attempt reached the publishing service before sending again, so a post is never published twice.","operationId":"retryPost","responses":{"200":{"description":"Retried","content":{"application/json":{"schema":{"type":"object","properties":{"post":{"$ref":"#/components/schemas/Post"}}}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"502":{"$ref":"#/components/responses/Error"}}}},"/media":{"post":{"tags":["Posts"],"summary":"Upload an image or video","description":"multipart/form-data with a `file` field (PNG, JPEG, GIF, WebP, MP4, MOV, WebM; up to 512 MB). Use the returned `{ id, url }` as an item of `media` when creating posts.","operationId":"uploadMedia","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"201":{"description":"Uploaded","content":{"application/json":{"schema":{"type":"object","properties":{"media":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"},"size":{"type":"integer"}}}}}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"502":{"$ref":"#/components/responses/Error"}}}},"/analytics":{"get":{"tags":["Analytics"],"summary":"Platform metrics and publishing counts","operationId":"getAnalytics","parameters":[{"name":"days","in":"query","schema":{"type":"integer","minimum":1,"maximum":90,"default":7}},{"name":"channel_id","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Analytics"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"502":{"$ref":"#/components/responses/Error"}}}},"/webhooks":{"get":{"tags":["Webhooks"],"summary":"List webhooks","operationId":"listWebhooks","responses":{"200":{"description":"Webhooks","content":{"application/json":{"schema":{"type":"object","properties":{"webhooks":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}}}}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"502":{"$ref":"#/components/responses/Error"}}},"post":{"tags":["Webhooks"],"summary":"Add a webhook (the signing secret is returned once)","operationId":"createWebhook","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["post.published","post.failed","post.needs_approval"]}}},"required":["url"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"webhook":{"allOf":[{"$ref":"#/components/schemas/Webhook"},{"type":"object","properties":{"secret":{"type":"string"}}}]}}}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"502":{"$ref":"#/components/responses/Error"}}}},"/webhooks/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"delete":{"tags":["Webhooks"],"summary":"Delete a webhook","operationId":"deleteWebhook","responses":{"204":{"description":"Deleted"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"502":{"$ref":"#/components/responses/Error"}}}},"/webhooks/{id}/test":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"post":{"tags":["Webhooks"],"summary":"Send a signed ping","operationId":"testWebhook","responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"integer"},"error":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"502":{"$ref":"#/components/responses/Error"}}}},"/triggers/{token}":{"parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string"}}],"post":{"tags":["Posts"],"summary":"Fire a webhook automation","description":"The token is the credential (shown in the app's Automations). Creates posts on the automation's channels: scheduled (auto), waiting for approval (confirm) or drafts (suggest).","security":[],"operationId":"fireTrigger","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string"},"title":{"type":"string"},"url":{"type":"string"},"media":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"}}}}}}}}},"responses":{"201":{"description":"Fired","content":{"application/json":{"schema":{"type":"object","properties":{"run_id":{"type":"string"},"posts":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"502":{"$ref":"#/components/responses/Error"}}}},"/auth/device":{"post":{"tags":["Auth"],"summary":"Start a device sign-in (CLI)","security":[],"operationId":"startDevice","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"client_name":{"type":"string"},"scope":{"type":"string","enum":["read","write"]}}}}}},"responses":{"200":{"description":"Device code","content":{"application/json":{"schema":{"type":"object","properties":{"device_code":{"type":"string"},"user_code":{"type":"string"},"verification_uri":{"type":"string"},"verification_uri_complete":{"type":"string"},"expires_in":{"type":"integer"},"interval":{"type":"integer"}}}}}}}}},"/auth/device/token":{"post":{"tags":["Auth"],"summary":"Poll for the API key after approval","security":[],"operationId":"pollDevice","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"device_code":{"type":"string"}},"required":["device_code"]}}}},"responses":{"200":{"description":"Approved","content":{"application/json":{"schema":{"type":"object","properties":{"access_token":{"type":"string"},"token_type":{"type":"string"},"scope":{"type":"string"},"workspace_id":{"type":"string"}}}}}},"400":{"description":"Not yet","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["authorization_pending","slow_down","access_denied","expired_token","invalid_grant"]}}}}}}}}}},"webhooks":{"post.published":{"post":{"summary":"post.published event","description":"Verify `VibePost-Signature: t=<unix>,v1=<hex>`: compute HMAC-SHA256 of `<t>.<raw body>` with the endpoint secret and compare; reject timestamps older than 5 minutes. Respond 2xx; other answers are retried with backoff.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Received"}}}},"post.failed":{"post":{"summary":"post.failed event","description":"Verify `VibePost-Signature: t=<unix>,v1=<hex>`: compute HMAC-SHA256 of `<t>.<raw body>` with the endpoint secret and compare; reject timestamps older than 5 minutes. Respond 2xx; other answers are retried with backoff.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Received"}}}},"post.needs_approval":{"post":{"summary":"post.needs_approval event","description":"Verify `VibePost-Signature: t=<unix>,v1=<hex>`: compute HMAC-SHA256 of `<t>.<raw body>` with the endpoint secret and compare; reject timestamps older than 5 minutes. Respond 2xx; other answers are retried with backoff.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Received"}}}}},"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"Workspace API key (vp_…) or OAuth access token (vpo_…)"},"oauth2":{"type":"oauth2","description":"Authorization code with PKCE (S256). Clients can register themselves at /api/oauth2/register (RFC 7591); for a ChatGPT GPT, create a client in Settings → Developers and use its id and secret.","flows":{"authorizationCode":{"authorizationUrl":"https://vibepost.cc/oauth/authorize","tokenUrl":"https://vibepost.cc/api/oauth2/token","refreshUrl":"https://vibepost.cc/api/oauth2/token","scopes":{"read":"See channels, calendar, posts and results","write":"Write, schedule and change posts"}}}}},"responses":{"Error":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"rule_violation","message":"Nothing was created: X post is 312 characters; X allows 280."}}}}}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["unauthorized","forbidden","read_only_key","not_found","invalid_request","conflict","idempotency_mismatch","rule_violation","needs_confirmation","delete_disabled","platform_rejected","ai_unavailable","rate_limited","payment_required","internal"]},"message":{"type":"string"},"details":{}},"required":["code","message"]}},"required":["error"]},"Me":{"type":"object","properties":{"workspace":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"time_zone":{"type":"string"},"api_delete_enabled":{"type":"boolean"}}},"key":{"type":"object","properties":{"id":{"type":"string"},"scope":{"type":"string","enum":["read","write"]}}}}},"Channel":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"platform":{"type":"string","examples":["x","linkedin","threads","tiktok","instagram","facebook","youtube","bluesky","mastodon","telegram","discord"]},"handle":{"type":["string","null"]},"status":{"type":"string","enum":["active","needs_reconnect","disabled"]},"last_error":{"type":["string","null"]},"platform_name":{"type":"string"},"provider":{"type":"string"},"picture":{"type":["string","null"]},"disabled":{"type":"boolean"},"max_chars":{"type":"integer"},"requires_approval":{"type":"boolean","description":"TikTok: posts from the API wait for approval in the app"}}},"Post":{"type":"object","properties":{"id":{"type":"string"},"batch_id":{"type":"string"},"channel_id":{"type":"string"},"platform":{"type":"string"},"lang":{"type":["string","null"]},"text":{"type":"string"},"media":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"}}}},"schedule_at":{"type":["string","null"],"format":"date-time"},"status":{"type":"string","enum":["draft","needs_approval","scheduled","publishing","published","failed","deleted"]},"settings":{"type":"object","description":"Platform options (e.g. subreddit, who_can_reply); for TikTok also the creator's approval choices"},"platform_post_id":{"type":["string","null"]},"attempts":{"type":"integer","description":"Publishing attempts so far (up to 5 on rate limits and server errors)"},"next_attempt_at":{"type":["string","null"],"format":"date-time","description":"When a scheduled post is next tried"},"first_comment":{"type":["string","null"],"description":"Posted as a reply/comment right after publishing where the platform allows"},"first_comment_error":{"type":["string","null"]},"repeat":{"type":["object","null"],"properties":{"every":{"type":"string","enum":["day","week","month"]},"count":{"type":"integer"}}},"tags":{"type":"array","items":{"type":"string"}},"metrics":{"type":["object","null"],"description":"As the platform reports them (X, Bluesky, Mastodon, Threads, YouTube), refreshed every few hours","properties":{"impressions":{"type":"integer"},"views":{"type":"integer"},"likes":{"type":"integer"},"replies":{"type":"integer"},"reposts":{"type":"integer"}}},"needs_review":{"type":"boolean","description":"Waiting for an owner or admin (editor posts, automations set to confirm)"},"source":{"type":"string","enum":["app","api","cli","mcp"]},"release_url":{"type":["string","null"]},"error":{"type":["string","null"]},"approve_url":{"type":"string","description":"Only when status is needs_approval"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"published_at":{"type":["string","null"],"format":"date-time"}},"example":{"id":"post_8k2m4q9x7c1v3b5n6z0a","batch_id":"batch_1a2b3c4d5e6f7g8h9i0j","channel_id":"cm_x_channel","platform":"x","lang":"ja","text":"何でも学べる。何でも聞ける。","media":[],"schedule_at":"2026-10-26T12:00:00.000Z","status":"scheduled","source":"api","release_url":null,"error":null,"created_at":"2026-10-21T03:00:00.000Z","updated_at":"2026-10-21T03:00:01.000Z","published_at":null}},"CreatePosts":{"type":"object","properties":{"text":{"description":"The post text, or the brief/source the AI writes from when variants is \"auto\".","type":"string","maxLength":40000},"channels":{"description":"Channel ids, or platform names (\"x\", \"linkedin\", \"bluesky\", …) meaning every connected channel on that platform.","minItems":1,"maxItems":30,"type":"array","items":{"type":"string","minLength":1,"maxLength":100}},"languages":{"description":"One post per channel per language.","maxItems":10,"type":"array","items":{"type":"string","pattern":"^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{2,8})?$"}},"variants":{"description":"\"auto\" lets the AI write each channel x language version; or give the text per channel.","anyOf":[{"type":"string","const":"auto"},{"minItems":1,"maxItems":60,"type":"array","items":{"type":"object","properties":{"channel":{"type":"string","minLength":1,"maxLength":100},"lang":{"type":"string","pattern":"^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{2,8})?$"},"text":{"type":"string","minLength":1,"maxLength":40000},"schedule_at":{"description":"This version's own time; overrides the top-level schedule_at.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"first_comment":{"description":"This version's own first comment.","type":"string","maxLength":5000}},"required":["channel","text"]}}]},"schedule_at":{"description":"ISO 8601 time with offset, \"now\", or \"auto\" to let the AI pick the best times.","anyOf":[{"type":"string","const":"auto"},{"type":"string","const":"now"},{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}]},"schedule_after":{"description":"With schedule_at \"auto\": pick times after this moment (e.g. next Monday for \"next week\").","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"draft":{"description":"Save as drafts; nothing is scheduled.","type":"boolean"},"first_comment":{"description":"Posted as a reply/comment right after each post where the platform allows (X, Bluesky, Mastodon, Threads, LinkedIn, Facebook, Instagram, Reddit, Telegram, Discord).","type":"string","maxLength":5000},"shorten_links":{"description":"Replace links with short links (<host>/l/<code>) that count clicks.","type":"boolean"},"repeat":{"description":"Publish each post again: count occurrences in total, every day, week or month, at the same local time.","type":"object","properties":{"every":{"type":"string","enum":["day","week","month"]},"count":{"type":"integer","minimum":2,"maximum":52}},"required":["every","count"]},"tags":{"maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":40}},"media":{"description":"Images or videos: public https URLs, or { id, url } from POST /media. TikTok and YouTube need a video.","maxItems":10,"type":"array","items":{"type":"object","properties":{"url":{"type":"string","maxLength":2000,"format":"uri"},"id":{"type":"string","maxLength":100}},"required":["url"]}},"settings":{"description":"Platform options per channel id or platform name, e.g. { \"reddit\": { \"subreddit\": \"learnjapanese\" }, \"x\": { \"who_can_reply\": \"following\" } }. TikTok privacy is chosen in the app, never here.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}}}},"CreateResult":{"type":"object","properties":{"batch_id":{"type":"string"},"posts":{"type":"array","items":{"$ref":"#/components/schemas/Post"}}}},"Preview":{"type":"object","properties":{"time_zone":{"type":"string"},"posts":{"type":"array","items":{"type":"object","properties":{"channel_id":{"type":"string"},"channel_name":{"type":"string"},"platform":{"type":"string"},"lang":{"type":["string","null"]},"text":{"type":"string"},"schedule_at":{"type":["string","null"]},"requires_approval":{"type":"boolean"},"problems":{"type":"array","items":{"type":"string"}}}}}}},"Analytics":{"type":"object","properties":{"as_of":{"type":"string"},"days":{"type":"integer"},"time_zone":{"type":"string"},"dates":{"type":"array","items":{"type":"string"},"description":"Local dates; the x axis of every series"},"totals":{"type":"object","properties":{"impressions":{"type":["integer","null"]},"engagement":{"type":["integer","null"]}}},"channels":{"type":"array","items":{"type":"object","properties":{"channel_id":{"type":"string"},"name":{"type":"string"},"platform":{"type":"string"},"published":{"type":"integer"},"failed":{"type":"integer"},"scheduled":{"type":"integer"},"metrics_source":{"type":"string","enum":["platform","counts"],"description":"counts: the platform reports no metrics; only publishing counts are known"},"metrics":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"total":{"type":"integer"},"change_percent":{"type":["number","null"]},"series":{"type":"array","items":{"type":"integer"}}}}},"series":{"type":"object","properties":{"published":{"type":"array","items":{"type":"integer"}},"impressions":{"type":"array","items":{"type":"integer"}},"engagement":{"type":"array","items":{"type":"integer"}}}},"note":{"type":"string"}}}},"posts":{"type":"object","properties":{"published":{"type":"integer"},"failed":{"type":"integer"},"scheduled":{"type":"integer"},"needs_approval":{"type":"integer"}}},"top_posts":{"type":"array","items":{"type":"object"}}}},"Webhook":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"events":{"type":"array","items":{"type":"string"}},"active":{"type":"boolean"},"created_at":{"type":"string"}}},"Event":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["post.published","post.failed","post.needs_approval"]},"created_at":{"type":"string"},"workspace_id":{"type":"string"},"data":{"type":"object","properties":{"post":{"$ref":"#/components/schemas/Post"}}}}},"Approval":{"type":"object","properties":{"privacy_level":{"type":"string","enum":["PUBLIC_TO_EVERYONE","MUTUAL_FOLLOW_FRIENDS","FOLLOWER_OF_CREATOR","SELF_ONLY"]},"comment":{"default":false,"type":"boolean"},"duet":{"default":false,"type":"boolean"},"stitch":{"default":false,"type":"boolean"},"brand_content_toggle":{"default":false,"type":"boolean"},"brand_organic_toggle":{"default":false,"type":"boolean"}},"required":["privacy_level"]}}}}