changedOutput schema / (root)
Previous value: -nullNew value: +{
+ "additionalProperties": false,
+ "properties": {
+ "credits": {
+ "additionalProperties": false,
+ "description": "While this call's X reads spend credits: the credits it spent and the balance left (getCredits).",
+ "properties": {
+ "balance": {
+ "type": "integer"
+ },
+ "spent": {
+ "type": "integer"
+ }
+ },
+ "required": [
+ "spent",
+ "balance"
+ ],
+ "type": "object"
+ },
+ "ok": {
+ "type": "boolean"
+ },
+ "options": {
+ "description": "A draft offering options: each one's check. ok only when every option passes, since the owner may pick any. snapshot and snapshot_hash are option 1's.",
+ "items": {
+ "additionalProperties": false,
+ "description": "One option checked as the draft will be once the owner picks it.",
+ "properties": {
+ "ok": {
+ "type": "boolean"
+ },
+ "option": {
+ "description": "1-based, as in the draft's options.",
+ "type": "integer"
+ },
+ "problems": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "code": {
+ "description": "rule: a blocking workspace rule isn't met (rule_id names it; see rules). Other problems may carry their own code or none.",
+ "type": "string"
+ },
+ "fixes": {
+ "items": {
+ "additionalProperties": true,
+ "properties": {
+ "connection_id": {
+ "description": "For a connect fix: reconnect this pinned account, not another profile.",
+ "type": "string"
+ },
+ "expires_at": {
+ "description": "For a login-expiry fix: the login's last usable instant, including a known refresh-token expiry.",
+ "format": "date-time",
+ "type": "string"
+ },
+ "kind": {
+ "description": "choose-connection (set the draft's top-level connection_id to an explicitly selected account), connect, hand-first, hand-all, drop-quote, drop-reply, plain-names, approve-only, inbox (send a TikTok post to the inbox as a draft), post-now, render (render the slideshow: POST …/slideshows/{id}/render), repost-live (X threads with live posts: post the whole thread again, an owner-only choice on the approval page, item thread.repost_live; tokens can't) edit-text (change the text: it repeats a recent post of the account, which X or LinkedIn would refuse, an X post has more than max_cashtags cashtags, or a workspace rule wants text added or removed; posts lists a thread's post numbers to change), add-label (a required_label rule: add label to the draft's labels) or judge (a judged workspace rule: judge the post, then list rule_id in judged).",
+ "type": "string"
+ },
+ "media_ids": {
+ "description": "Reach alt-text fix: the attachments to describe in the draft's media references.",
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "operation_id": {
+ "description": "Reach media fix: the operation to upload or import a file, then attach it to the draft or named thread posts.",
+ "type": "string"
+ },
+ "patch": {
+ "description": "The change to the draft's body that applies this fix (send it with PATCH).",
+ "type": [
+ "object",
+ "null"
+ ]
+ },
+ "platform": {
+ "type": "string"
+ },
+ "post_at": {
+ "description": "Reach best-time fix: PATCH this top-level draft field, not body.post_at, then check again in the intended mode.",
+ "format": "date-time",
+ "type": "string"
+ },
+ "posts": {
+ "items": {
+ "description": "For an edit-text fix on a thread: the numbers (from 1) of the posts to change.",
+ "type": "integer"
+ },
+ "type": "array"
+ },
+ "tags": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ }
+ },
+ "required": [
+ "kind"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "option": {
+ "description": "A draft offering options: the option (1-based) this problem is in. A fix's text, media or posts patch goes to that option's version in options; its other fields to the body. Left out when every option has it.",
+ "type": "integer"
+ },
+ "rule_id": {
+ "description": "code rule: the failing rule's id.",
+ "type": "string"
+ },
+ "text": {
+ "description": "One plain sentence.",
+ "type": "string"
+ }
+ },
+ "required": [
+ "text"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "reach": {
+ "items": {
+ "additionalProperties": false,
+ "description": "An advisory reach check, including passing items; never changes Check.ok or blocks approval.",
+ "properties": {
+ "code": {
+ "description": "link: whether the post has a link at all (a thread: any post; LinkedIn: a body link or link card). It says so even when no workspace rule asks for one; a require_link rule is what blocks.",
+ "enum": [
+ "media",
+ "alt_text",
+ "length",
+ "linkedin_link",
+ "link",
+ "best_time"
+ ],
+ "type": "string"
+ },
+ "fixes": {
+ "items": {
+ "additionalProperties": true,
+ "properties": {
+ "connection_id": {
+ "description": "For a connect fix: reconnect this pinned account, not another profile.",
+ "type": "string"
+ },
+ "expires_at": {
+ "description": "For a login-expiry fix: the login's last usable instant, including a known refresh-token expiry.",
+ "format": "date-time",
+ "type": "string"
+ },
+ "kind": {
+ "description": "choose-connection (set the draft's top-level connection_id to an explicitly selected account), connect, hand-first, hand-all, drop-quote, drop-reply, plain-names, approve-only, inbox (send a TikTok post to the inbox as a draft), post-now, render (render the slideshow: POST …/slideshows/{id}/render), repost-live (X threads with live posts: post the whole thread again, an owner-only choice on the approval page, item thread.repost_live; tokens can't) edit-text (change the text: it repeats a recent post of the account, which X or LinkedIn would refuse, an X post has more than max_cashtags cashtags, or a workspace rule wants text added or removed; posts lists a thread's post numbers to change), add-label (a required_label rule: add label to the draft's labels) or judge (a judged workspace rule: judge the post, then list rule_id in judged).",
+ "type": "string"
+ },
+ "media_ids": {
+ "description": "Reach alt-text fix: the attachments to describe in the draft's media references.",
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "operation_id": {
+ "description": "Reach media fix: the operation to upload or import a file, then attach it to the draft or named thread posts.",
+ "type": "string"
+ },
+ "patch": {
+ "description": "The change to the draft's body that applies this fix (send it with PATCH).",
+ "type": [
+ "object",
+ "null"
+ ]
+ },
+ "platform": {
+ "type": "string"
+ },
+ "post_at": {
+ "description": "Reach best-time fix: PATCH this top-level draft field, not body.post_at, then check again in the intended mode.",
+ "format": "date-time",
+ "type": "string"
+ },
+ "posts": {
+ "items": {
+ "description": "For an edit-text fix on a thread: the numbers (from 1) of the posts to change.",
+ "type": "integer"
+ },
+ "type": "array"
+ },
+ "tags": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ }
+ },
+ "required": [
+ "kind"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "ok": {
+ "type": "boolean"
+ },
+ "option": {
+ "description": "Aggregated options checklist: the option number, from 1; apply body fixes to that version.",
+ "type": "integer"
+ },
+ "post": {
+ "description": "X thread: the post number, from 1.",
+ "type": "integer"
+ },
+ "text": {
+ "description": "One plain sentence, based on stored account data or qualified research advice.",
+ "type": "string"
+ }
+ },
+ "required": [
+ "code",
+ "ok",
+ "text"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "rules": {
+ "items": {
+ "additionalProperties": false,
+ "description": "One workspace rule's result for this draft: every rule that applies to its platform, passing ones included.",
+ "properties": {
+ "blocking": {
+ "description": "A failing blocking rule is also a problem: ok is false and approval requests are refused. Otherwise it's a suggestion.",
+ "type": "boolean"
+ },
+ "fix": {
+ "description": "Failing rules: what to change, one plain sentence.",
+ "type": "string"
+ },
+ "fixes": {
+ "items": {
+ "additionalProperties": true,
+ "properties": {
+ "connection_id": {
+ "description": "For a connect fix: reconnect this pinned account, not another profile.",
+ "type": "string"
+ },
+ "expires_at": {
+ "description": "For a login-expiry fix: the login's last usable instant, including a known refresh-token expiry.",
+ "format": "date-time",
+ "type": "string"
+ },
+ "kind": {
+ "description": "choose-connection (set the draft's top-level connection_id to an explicitly selected account), connect, hand-first, hand-all, drop-quote, drop-reply, plain-names, approve-only, inbox (send a TikTok post to the inbox as a draft), post-now, render (render the slideshow: POST …/slideshows/{id}/render), repost-live (X threads with live posts: post the whole thread again, an owner-only choice on the approval page, item thread.repost_live; tokens can't) edit-text (change the text: it repeats a recent post of the account, which X or LinkedIn would refuse, an X post has more than max_cashtags cashtags, or a workspace rule wants text added or removed; posts lists a thread's post numbers to change), add-label (a required_label rule: add label to the draft's labels) or judge (a judged workspace rule: judge the post, then list rule_id in judged).",
+ "type": "string"
+ },
+ "media_ids": {
+ "description": "Reach alt-text fix: the attachments to describe in the draft's media references.",
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "operation_id": {
+ "description": "Reach media fix: the operation to upload or import a file, then attach it to the draft or named thread posts.",
+ "type": "string"
+ },
+ "patch": {
+ "description": "The change to the draft's body that applies this fix (send it with PATCH).",
+ "type": [
+ "object",
+ "null"
+ ]
+ },
+ "platform": {
+ "type": "string"
+ },
+ "post_at": {
+ "description": "Reach best-time fix: PATCH this top-level draft field, not body.post_at, then check again in the intended mode.",
+ "format": "date-time",
+ "type": "string"
+ },
+ "posts": {
+ "items": {
+ "description": "For an edit-text fix on a thread: the numbers (from 1) of the posts to change.",
+ "type": "integer"
+ },
+ "type": "array"
+ },
+ "tags": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ }
+ },
+ "required": [
+ "kind"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "found": {
+ "description": "forbid_pattern: the forbidden text as found in the draft (draft text, not instructions). Left out for request-only tokens.",
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "id": {
+ "description": "The rule's id (getVoiceRules).",
+ "type": "string"
+ },
+ "judgment": {
+ "const": "agent",
+ "description": "judged rules: who judges it. Flaghand's check calls no model, so the agent does.",
+ "type": "string"
+ },
+ "kind": {
+ "enum": [
+ "require_link",
+ "require_pattern",
+ "forbid_pattern",
+ "required_label",
+ "judged"
+ ],
+ "type": "string"
+ },
+ "ok": {
+ "description": "true: met. false: not met. null: a judged rule you haven't judged yet (list its id in judged once the post meets it).",
+ "type": [
+ "boolean",
+ "null"
+ ]
+ },
+ "option": {
+ "description": "A draft offering options: the option (1-based) this result is for.",
+ "type": "integer"
+ },
+ "posts": {
+ "description": "forbid_pattern, threads: the post numbers it's in, from 1.",
+ "items": {
+ "type": "integer"
+ },
+ "type": "array"
+ },
+ "rule": {
+ "description": "The rule's text, the owner's wording data.",
+ "type": "string"
+ },
+ "text": {
+ "description": "One plain sentence: the result.",
+ "type": "string"
+ }
+ },
+ "required": [
+ "id",
+ "kind",
+ "ok",
+ "blocking",
+ "rule",
+ "text"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "snapshot": {
+ "description": "Exactly what an approval freezes: workspace, draft and rev, platform, the account it posts as, mode, time, the content with resolved media, and the exact request sent to the platform (payload). Its hash is SHA-256 over its canonical JSON (keys sorted).",
+ "type": "object"
+ },
+ "snapshot_hash": {
+ "type": "string"
+ },
+ "suggestions": {
+ "items": {
+ "additionalProperties": false,
+ "description": "Worth fixing before approval, but never stops it: ok counts problems only.",
+ "properties": {
+ "code": {
+ "description": "rule: a workspace rule that only warns isn't met, or a judged rule waits for your judgment; rule_id names it, and it never blocks approval. reach: a failing reach checklist item; rule names the item, and fixing it is recommended before asking the owner, never required for approval. markdown: the text has Markdown (**bold**, # headings, - lists, [links](…), `code`), which X, LinkedIn and TikTok show as typed. voice: an X draft has an AI tell the owner's own posts don't have (docs/voice-rules.md); for the agent to rewrite before the owner sees it, never shown to the owner, with no fixes.",
+ "enum": [
+ "markdown",
+ "voice",
+ "reach",
+ "rule"
+ ],
+ "type": "string"
+ },
+ "draft_ids": {
+ "description": "voice run_repeat: the other drafts of the run that share it.",
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "fixes": {
+ "description": "plain-text takes off the Markdown marks; unicode-styles writes bold, italic, headings and code in Unicode's styled letters, which screen readers read poorly. Each patch is a change to the draft's body (send it with PATCH), or the named option's version. A voice suggestion has none: rewrite the draft.",
+ "items": {
+ "additionalProperties": true,
+ "properties": {
+ "connection_id": {
+ "description": "For a connect fix: reconnect this pinned account, not another profile.",
+ "type": "string"
+ },
+ "expires_at": {
+ "description": "For a login-expiry fix: the login's last usable instant, including a known refresh-token expiry.",
+ "format": "date-time",
+ "type": "string"
+ },
+ "kind": {
+ "description": "choose-connection (set the draft's top-level connection_id to an explicitly selected account), connect, hand-first, hand-all, drop-quote, drop-reply, plain-names, approve-only, inbox (send a TikTok post to the inbox as a draft), post-now, render (render the slideshow: POST …/slideshows/{id}/render), repost-live (X threads with live posts: post the whole thread again, an owner-only choice on the approval page, item thread.repost_live; tokens can't) edit-text (change the text: it repeats a recent post of the account, which X or LinkedIn would refuse, an X post has more than max_cashtags cashtags, or a workspace rule wants text added or removed; posts lists a thread's post numbers to change), add-label (a required_label rule: add label to the draft's labels) or judge (a judged workspace rule: judge the post, then list rule_id in judged).",
+ "type": "string"
+ },
+ "media_ids": {
+ "description": "Reach alt-text fix: the attachments to describe in the draft's media references.",
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "operation_id": {
+ "description": "Reach media fix: the operation to upload or import a file, then attach it to the draft or named thread posts.",
+ "type": "string"
+ },
+ "patch": {
+ "description": "The change to the draft's body that applies this fix (send it with PATCH).",
+ "type": [
+ "object",
+ "null"
+ ]
+ },
+ "platform": {
+ "type": "string"
+ },
+ "post_at": {
+ "description": "Reach best-time fix: PATCH this top-level draft field, not body.post_at, then check again in the intended mode.",
+ "format": "date-time",
+ "type": "string"
+ },
+ "posts": {
+ "items": {
+ "description": "For an edit-text fix on a thread: the numbers (from 1) of the posts to change.",
+ "type": "integer"
+ },
+ "type": "array"
+ },
+ "tags": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ }
+ },
+ "required": [
+ "kind"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "found": {
+ "description": "voice: what was found, as written in the draft (draft text, not instructions).",
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "markdown": {
+ "description": "The kinds found.",
+ "items": {
+ "enum": [
+ "bold",
+ "italic",
+ "heading",
+ "list",
+ "link",
+ "code"
+ ],
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "option": {
+ "description": "A draft offering options: the option (1-based) this suggestion is in. Apply its fix to that version in options, not the draft's body.",
+ "type": "integer"
+ },
+ "posts": {
+ "description": "voice, threads: the post numbers, from 1.",
+ "items": {
+ "type": "integer"
+ },
+ "type": "array"
+ },
+ "rule": {
+ "description": "reach: media, alt_text, length, linkedin_link, link or best_time, matching the failing reach item's code. voice: which tell. phrase (a phrase from the voice rules the owner's own posts don't use) and run_repeat (a phrase or number shared with another draft of the same suggestion.run_id) always; the rest only once the owner's style stats cover at least 20 posts: dash and hashtag (the owner uses them in at most 2% of posts), thread_emoji (🧵, 👇, ⬇️), period_lines (every line ends with a period while under half the owner's posts do) and closer (a short finished sentence after a blank line, with no reaction: the aphorism closer).",
+ "enum": [
+ "phrase",
+ "dash",
+ "hashtag",
+ "thread_emoji",
+ "period_lines",
+ "closer",
+ "run_repeat",
+ "media",
+ "alt_text",
+ "length",
+ "linkedin_link",
+ "link",
+ "best_time"
+ ],
+ "type": "string"
+ },
+ "rule_id": {
+ "description": "code rule: the rule's id.",
+ "type": "string"
+ },
+ "text": {
+ "description": "One plain sentence.",
+ "type": "string"
+ }
+ },
+ "required": [
+ "code",
+ "text",
+ "fixes"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "warnings": {
+ "description": "Nonblocking advice for text this account already published. Recent platform refusal-window repeats remain problems.",
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "code": {
+ "description": "rule: a blocking workspace rule isn't met (rule_id names it; see rules). Other problems may carry their own code or none.",
+ "type": "string"
+ },
+ "fixes": {
+ "items": {
+ "additionalProperties": true,
+ "properties": {
+ "connection_id": {
+ "description": "For a connect fix: reconnect this pinned account, not another profile.",
+ "type": "string"
+ },
+ "expires_at": {
+ "description": "For a login-expiry fix: the login's last usable instant, including a known refresh-token expiry.",
+ "format": "date-time",
+ "type": "string"
+ },
+ "kind": {
+ "description": "choose-connection (set the draft's top-level connection_id to an explicitly selected account), connect, hand-first, hand-all, drop-quote, drop-reply, plain-names, approve-only, inbox (send a TikTok post to the inbox as a draft), post-now, render (render the slideshow: POST …/slideshows/{id}/render), repost-live (X threads with live posts: post the whole thread again, an owner-only choice on the approval page, item thread.repost_live; tokens can't) edit-text (change the text: it repeats a recent post of the account, which X or LinkedIn would refuse, an X post has more than max_cashtags cashtags, or a workspace rule wants text added or removed; posts lists a thread's post numbers to change), add-label (a required_label rule: add label to the draft's labels) or judge (a judged workspace rule: judge the post, then list rule_id in judged).",
+ "type": "string"
+ },
+ "media_ids": {
+ "description": "Reach alt-text fix: the attachments to describe in the draft's media references.",
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "operation_id": {
+ "description": "Reach media fix: the operation to upload or import a file, then attach it to the draft or named thread posts.",
+ "type": "string"
+ },
+ "patch": {
+ "description": "The change to the draft's body that applies this fix (send it with PATCH).",
+ "type": [
+ "object",
+ "null"
+ ]
+ },
+ "platform": {
+ "type": "string"
+ },
+ "post_at": {
+ "description": "Reach best-time fix: PATCH this top-level draft field, not body.post_at, then check again in the intended mode.",
+ "format": "date-time",
+ "type": "string"
+ },
+ "posts": {
+ "items": {
+ "description": "For an edit-text fix on a thread: the numbers (from 1) of the posts to change.",
+ "type": "integer"
+ },
+ "type": "array"
+ },
+ "tags": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ }
+ },
+ "required": [
+ "kind"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "option": {
+ "description": "A draft offering options: the option (1-based) this problem is in. A fix's text, media or posts patch goes to that option's version in options; its other fields to the body. Left out when every option has it.",
+ "type": "integer"
+ },
+ "rule_id": {
+ "description": "code rule: the failing rule's id.",
+ "type": "string"
+ },
+ "text": {
+ "description": "One plain sentence.",
+ "type": "string"
+ }
+ },
+ "required": [
+ "text"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ }
+ },
+ "required": [
+ "option",
+ "ok",
+ "problems",
+ "snapshot_hash"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "owner_choices": {
+ "anyOf": [
+ {
+ "additionalProperties": false,
+ "description": "TikTok drafts posted directly: what the owner chooses on TikTok's posting screen when approving.",
+ "properties": {
+ "allowed_privacy_levels": {
+ "description": "The ones this app can use now: all of them once TikTok has audited it, only SELF_ONLY while it's unaudited.",
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "audit_posture": {
+ "type": "string"
+ },
+ "comments": {
+ "description": "Whether comments can be allowed (the account's TikTok settings may turn them off).",
+ "type": [
+ "boolean",
+ "null"
+ ]
+ },
+ "consent": {
+ "additionalProperties": false,
+ "properties": {
+ "links": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "label": {
+ "type": "string"
+ },
+ "url": {
+ "type": "string"
+ }
+ },
+ "required": [],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "statement": {
+ "type": "string"
+ }
+ },
+ "required": [],
+ "type": "object"
+ },
+ "disclose": {
+ "additionalProperties": false,
+ "properties": {
+ "branded_content": {
+ "description": "Branded content can't be Only me, so it needs another privacy level this app can use.",
+ "type": "boolean"
+ },
+ "your_brand": {
+ "type": "boolean"
+ }
+ },
+ "required": [],
+ "type": "object"
+ },
+ "duet": {
+ "type": "boolean"
+ },
+ "privacy_level_options": {
+ "description": "Who-can-view options TikTok gives for the account right now. The owner picks one; none is preselected.",
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "stitch": {
+ "type": "boolean"
+ }
+ },
+ "required": [],
+ "type": "object"
+ }
+ ]
+ },
+ "problems": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "code": {
+ "description": "rule: a blocking workspace rule isn't met (rule_id names it; see rules). Other problems may carry their own code or none.",
+ "type": "string"
+ },
+ "fixes": {
+ "items": {
+ "additionalProperties": true,
+ "properties": {
+ "connection_id": {
+ "description": "For a connect fix: reconnect this pinned account, not another profile.",
+ "type": "string"
+ },
+ "expires_at": {
+ "description": "For a login-expiry fix: the login's last usable instant, including a known refresh-token expiry.",
+ "format": "date-time",
+ "type": "string"
+ },
+ "kind": {
+ "description": "choose-connection (set the draft's top-level connection_id to an explicitly selected account), connect, hand-first, hand-all, drop-quote, drop-reply, plain-names, approve-only, inbox (send a TikTok post to the inbox as a draft), post-now, render (render the slideshow: POST …/slideshows/{id}/render), repost-live (X threads with live posts: post the whole thread again, an owner-only choice on the approval page, item thread.repost_live; tokens can't) edit-text (change the text: it repeats a recent post of the account, which X or LinkedIn would refuse, an X post has more than max_cashtags cashtags, or a workspace rule wants text added or removed; posts lists a thread's post numbers to change), add-label (a required_label rule: add label to the draft's labels) or judge (a judged workspace rule: judge the post, then list rule_id in judged).",
+ "type": "string"
+ },
+ "media_ids": {
+ "description": "Reach alt-text fix: the attachments to describe in the draft's media references.",
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "operation_id": {
+ "description": "Reach media fix: the operation to upload or import a file, then attach it to the draft or named thread posts.",
+ "type": "string"
+ },
+ "patch": {
+ "description": "The change to the draft's body that applies this fix (send it with PATCH).",
+ "type": [
+ "object",
+ "null"
+ ]
+ },
+ "platform": {
+ "type": "string"
+ },
+ "post_at": {
+ "description": "Reach best-time fix: PATCH this top-level draft field, not body.post_at, then check again in the intended mode.",
+ "format": "date-time",
+ "type": "string"
+ },
+ "posts": {
+ "items": {
+ "description": "For an edit-text fix on a thread: the numbers (from 1) of the posts to change.",
+ "type": "integer"
+ },
+ "type": "array"
+ },
+ "tags": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ }
+ },
+ "required": [
+ "kind"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "option": {
+ "description": "A draft offering options: the option (1-based) this problem is in. A fix's text, media or posts patch goes to that option's version in options; its other fields to the body. Left out when every option has it.",
+ "type": "integer"
+ },
+ "rule_id": {
+ "description": "code rule: the failing rule's id.",
+ "type": "string"
+ },
+ "text": {
+ "description": "One plain sentence.",
+ "type": "string"
+ }
+ },
+ "required": [
+ "text"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "reach": {
+ "description": "X and LinkedIn: the whole reach checklist, passing items included, media first; options aggregate with option numbers. Uses stored data only, never makes an X read or blocks approval.",
+ "items": {
+ "additionalProperties": false,
+ "description": "An advisory reach check, including passing items; never changes Check.ok or blocks approval.",
+ "properties": {
+ "code": {
+ "description": "link: whether the post has a link at all (a thread: any post; LinkedIn: a body link or link card). It says so even when no workspace rule asks for one; a require_link rule is what blocks.",
+ "enum": [
+ "media",
+ "alt_text",
+ "length",
+ "linkedin_link",
+ "link",
+ "best_time"
+ ],
+ "type": "string"
+ },
+ "fixes": {
+ "items": {
+ "additionalProperties": true,
+ "properties": {
+ "connection_id": {
+ "description": "For a connect fix: reconnect this pinned account, not another profile.",
+ "type": "string"
+ },
+ "expires_at": {
+ "description": "For a login-expiry fix: the login's last usable instant, including a known refresh-token expiry.",
+ "format": "date-time",
+ "type": "string"
+ },
+ "kind": {
+ "description": "choose-connection (set the draft's top-level connection_id to an explicitly selected account), connect, hand-first, hand-all, drop-quote, drop-reply, plain-names, approve-only, inbox (send a TikTok post to the inbox as a draft), post-now, render (render the slideshow: POST …/slideshows/{id}/render), repost-live (X threads with live posts: post the whole thread again, an owner-only choice on the approval page, item thread.repost_live; tokens can't) edit-text (change the text: it repeats a recent post of the account, which X or LinkedIn would refuse, an X post has more than max_cashtags cashtags, or a workspace rule wants text added or removed; posts lists a thread's post numbers to change), add-label (a required_label rule: add label to the draft's labels) or judge (a judged workspace rule: judge the post, then list rule_id in judged).",
+ "type": "string"
+ },
+ "media_ids": {
+ "description": "Reach alt-text fix: the attachments to describe in the draft's media references.",
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "operation_id": {
+ "description": "Reach media fix: the operation to upload or import a file, then attach it to the draft or named thread posts.",
+ "type": "string"
+ },
+ "patch": {
+ "description": "The change to the draft's body that applies this fix (send it with PATCH).",
+ "type": [
+ "object",
+ "null"
+ ]
+ },
+ "platform": {
+ "type": "string"
+ },
+ "post_at": {
+ "description": "Reach best-time fix: PATCH this top-level draft field, not body.post_at, then check again in the intended mode.",
+ "format": "date-time",
+ "type": "string"
+ },
+ "posts": {
+ "items": {
+ "description": "For an edit-text fix on a thread: the numbers (from 1) of the posts to change.",
+ "type": "integer"
+ },
+ "type": "array"
+ },
+ "tags": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ }
+ },
+ "required": [
+ "kind"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "ok": {
+ "type": "boolean"
+ },
+ "option": {
+ "description": "Aggregated options checklist: the option number, from 1; apply body fixes to that version.",
+ "type": "integer"
+ },
+ "post": {
+ "description": "X thread: the post number, from 1.",
+ "type": "integer"
+ },
+ "text": {
+ "description": "One plain sentence, based on stored account data or qualified research advice.",
+ "type": "string"
+ }
+ },
+ "required": [
+ "code",
+ "ok",
+ "text"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "rev": {
+ "description": "Current revision after automatic suggestion reply routing; use it for the next edit or approval request.",
+ "type": "integer"
+ },
+ "rules": {
+ "description": "Present when the workspace has rules (getVoiceRules): each one that applies to this platform, by id, passing ones included. A failing blocking rule is also in problems; one that warns, or a judged rule not yet judged, is in suggestions. Options aggregate with option numbers.",
+ "items": {
+ "additionalProperties": false,
+ "description": "One workspace rule's result for this draft: every rule that applies to its platform, passing ones included.",
+ "properties": {
+ "blocking": {
+ "description": "A failing blocking rule is also a problem: ok is false and approval requests are refused. Otherwise it's a suggestion.",
+ "type": "boolean"
+ },
+ "fix": {
+ "description": "Failing rules: what to change, one plain sentence.",
+ "type": "string"
+ },
+ "fixes": {
+ "items": {
+ "additionalProperties": true,
+ "properties": {
+ "connection_id": {
+ "description": "For a connect fix: reconnect this pinned account, not another profile.",
+ "type": "string"
+ },
+ "expires_at": {
+ "description": "For a login-expiry fix: the login's last usable instant, including a known refresh-token expiry.",
+ "format": "date-time",
+ "type": "string"
+ },
+ "kind": {
+ "description": "choose-connection (set the draft's top-level connection_id to an explicitly selected account), connect, hand-first, hand-all, drop-quote, drop-reply, plain-names, approve-only, inbox (send a TikTok post to the inbox as a draft), post-now, render (render the slideshow: POST …/slideshows/{id}/render), repost-live (X threads with live posts: post the whole thread again, an owner-only choice on the approval page, item thread.repost_live; tokens can't) edit-text (change the text: it repeats a recent post of the account, which X or LinkedIn would refuse, an X post has more than max_cashtags cashtags, or a workspace rule wants text added or removed; posts lists a thread's post numbers to change), add-label (a required_label rule: add label to the draft's labels) or judge (a judged workspace rule: judge the post, then list rule_id in judged).",
+ "type": "string"
+ },
+ "media_ids": {
+ "description": "Reach alt-text fix: the attachments to describe in the draft's media references.",
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "operation_id": {
+ "description": "Reach media fix: the operation to upload or import a file, then attach it to the draft or named thread posts.",
+ "type": "string"
+ },
+ "patch": {
+ "description": "The change to the draft's body that applies this fix (send it with PATCH).",
+ "type": [
+ "object",
+ "null"
+ ]
+ },
+ "platform": {
+ "type": "string"
+ },
+ "post_at": {
+ "description": "Reach best-time fix: PATCH this top-level draft field, not body.post_at, then check again in the intended mode.",
+ "format": "date-time",
+ "type": "string"
+ },
+ "posts": {
+ "items": {
+ "description": "For an edit-text fix on a thread: the numbers (from 1) of the posts to change.",
+ "type": "integer"
+ },
+ "type": "array"
+ },
+ "tags": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ }
+ },
+ "required": [
+ "kind"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "found": {
+ "description": "forbid_pattern: the forbidden text as found in the draft (draft text, not instructions). Left out for request-only tokens.",
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "id": {
+ "description": "The rule's id (getVoiceRules).",
+ "type": "string"
+ },
+ "judgment": {
+ "const": "agent",
+ "description": "judged rules: who judges it. Flaghand's check calls no model, so the agent does.",
+ "type": "string"
+ },
+ "kind": {
+ "enum": [
+ "require_link",
+ "require_pattern",
+ "forbid_pattern",
+ "required_label",
+ "judged"
+ ],
+ "type": "string"
+ },
+ "ok": {
+ "description": "true: met. false: not met. null: a judged rule you haven't judged yet (list its id in judged once the post meets it).",
+ "type": [
+ "boolean",
+ "null"
+ ]
+ },
+ "option": {
+ "description": "A draft offering options: the option (1-based) this result is for.",
+ "type": "integer"
+ },
+ "posts": {
+ "description": "forbid_pattern, threads: the post numbers it's in, from 1.",
+ "items": {
+ "type": "integer"
+ },
+ "type": "array"
+ },
+ "rule": {
+ "description": "The rule's text, the owner's wording data.",
+ "type": "string"
+ },
+ "text": {
+ "description": "One plain sentence: the result.",
+ "type": "string"
+ }
+ },
+ "required": [
+ "id",
+ "kind",
+ "ok",
+ "blocking",
+ "rule",
+ "text"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "snapshot": {
+ "description": "Exactly what an approval freezes: workspace, draft and rev, platform, the account it posts as, mode, time, the content with resolved media, and the exact request sent to the platform (payload). Its hash is SHA-256 over its canonical JSON (keys sorted).",
+ "type": "object"
+ },
+ "snapshot_hash": {
+ "type": "string"
+ },
+ "suggestions": {
+ "description": "Present when there are any. Fix reach suggestions before asking the owner; they never block approval. A markdown suggestion's plain-text fix is the one to prefer. Rewrite an X draft for each voice suggestion before the owner sees it, unless the owner asked for exactly that.",
+ "items": {
+ "additionalProperties": false,
+ "description": "Worth fixing before approval, but never stops it: ok counts problems only.",
+ "properties": {
+ "code": {
+ "description": "rule: a workspace rule that only warns isn't met, or a judged rule waits for your judgment; rule_id names it, and it never blocks approval. reach: a failing reach checklist item; rule names the item, and fixing it is recommended before asking the owner, never required for approval. markdown: the text has Markdown (**bold**, # headings, - lists, [links](…), `code`), which X, LinkedIn and TikTok show as typed. voice: an X draft has an AI tell the owner's own posts don't have (docs/voice-rules.md); for the agent to rewrite before the owner sees it, never shown to the owner, with no fixes.",
+ "enum": [
+ "markdown",
+ "voice",
+ "reach",
+ "rule"
+ ],
+ "type": "string"
+ },
+ "draft_ids": {
+ "description": "voice run_repeat: the other drafts of the run that share it.",
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "fixes": {
+ "description": "plain-text takes off the Markdown marks; unicode-styles writes bold, italic, headings and code in Unicode's styled letters, which screen readers read poorly. Each patch is a change to the draft's body (send it with PATCH), or the named option's version. A voice suggestion has none: rewrite the draft.",
+ "items": {
+ "additionalProperties": true,
+ "properties": {
+ "connection_id": {
+ "description": "For a connect fix: reconnect this pinned account, not another profile.",
+ "type": "string"
+ },
+ "expires_at": {
+ "description": "For a login-expiry fix: the login's last usable instant, including a known refresh-token expiry.",
+ "format": "date-time",
+ "type": "string"
+ },
+ "kind": {
+ "description": "choose-connection (set the draft's top-level connection_id to an explicitly selected account), connect, hand-first, hand-all, drop-quote, drop-reply, plain-names, approve-only, inbox (send a TikTok post to the inbox as a draft), post-now, render (render the slideshow: POST …/slideshows/{id}/render), repost-live (X threads with live posts: post the whole thread again, an owner-only choice on the approval page, item thread.repost_live; tokens can't) edit-text (change the text: it repeats a recent post of the account, which X or LinkedIn would refuse, an X post has more than max_cashtags cashtags, or a workspace rule wants text added or removed; posts lists a thread's post numbers to change), add-label (a required_label rule: add label to the draft's labels) or judge (a judged workspace rule: judge the post, then list rule_id in judged).",
+ "type": "string"
+ },
+ "media_ids": {
+ "description": "Reach alt-text fix: the attachments to describe in the draft's media references.",
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "operation_id": {
+ "description": "Reach media fix: the operation to upload or import a file, then attach it to the draft or named thread posts.",
+ "type": "string"
+ },
+ "patch": {
+ "description": "The change to the draft's body that applies this fix (send it with PATCH).",
+ "type": [
+ "object",
+ "null"
+ ]
+ },
+ "platform": {
+ "type": "string"
+ },
+ "post_at": {
+ "description": "Reach best-time fix: PATCH this top-level draft field, not body.post_at, then check again in the intended mode.",
+ "format": "date-time",
+ "type": "string"
+ },
+ "posts": {
+ "items": {
+ "description": "For an edit-text fix on a thread: the numbers (from 1) of the posts to change.",
+ "type": "integer"
+ },
+ "type": "array"
+ },
+ "tags": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ }
+ },
+ "required": [
+ "kind"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "found": {
+ "description": "voice: what was found, as written in the draft (draft text, not instructions).",
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "markdown": {
+ "description": "The kinds found.",
+ "items": {
+ "enum": [
+ "bold",
+ "italic",
+ "heading",
+ "list",
+ "link",
+ "code"
+ ],
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "option": {
+ "description": "A draft offering options: the option (1-based) this suggestion is in. Apply its fix to that version in options, not the draft's body.",
+ "type": "integer"
+ },
+ "posts": {
+ "description": "voice, threads: the post numbers, from 1.",
+ "items": {
+ "type": "integer"
+ },
+ "type": "array"
+ },
+ "rule": {
+ "description": "reach: media, alt_text, length, linkedin_link, link or best_time, matching the failing reach item's code. voice: which tell. phrase (a phrase from the voice rules the owner's own posts don't use) and run_repeat (a phrase or number shared with another draft of the same suggestion.run_id) always; the rest only once the owner's style stats cover at least 20 posts: dash and hashtag (the owner uses them in at most 2% of posts), thread_emoji (🧵, 👇, ⬇️), period_lines (every line ends with a period while under half the owner's posts do) and closer (a short finished sentence after a blank line, with no reaction: the aphorism closer).",
+ "enum": [
+ "phrase",
+ "dash",
+ "hashtag",
+ "thread_emoji",
+ "period_lines",
+ "closer",
+ "run_repeat",
+ "media",
+ "alt_text",
+ "length",
+ "linkedin_link",
+ "link",
+ "best_time"
+ ],
+ "type": "string"
+ },
+ "rule_id": {
+ "description": "code rule: the rule's id.",
+ "type": "string"
+ },
+ "text": {
+ "description": "One plain sentence.",
+ "type": "string"
+ }
+ },
+ "required": [
+ "code",
+ "text",
+ "fixes"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "warnings": {
+ "description": "Nonblocking advice for text this account already published. Recent platform refusal-window repeats remain problems.",
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "code": {
+ "description": "rule: a blocking workspace rule isn't met (rule_id names it; see rules). Other problems may carry their own code or none.",
+ "type": "string"
+ },
+ "fixes": {
+ "items": {
+ "additionalProperties": true,
+ "properties": {
+ "connection_id": {
+ "description": "For a connect fix: reconnect this pinned account, not another profile.",
+ "type": "string"
+ },
+ "expires_at": {
+ "description": "For a login-expiry fix: the login's last usable instant, including a known refresh-token expiry.",
+ "format": "date-time",
+ "type": "string"
+ },
+ "kind": {
+ "description": "choose-connection (set the draft's top-level connection_id to an explicitly selected account), connect, hand-first, hand-all, drop-quote, drop-reply, plain-names, approve-only, inbox (send a TikTok post to the inbox as a draft), post-now, render (render the slideshow: POST …/slideshows/{id}/render), repost-live (X threads with live posts: post the whole thread again, an owner-only choice on the approval page, item thread.repost_live; tokens can't) edit-text (change the text: it repeats a recent post of the account, which X or LinkedIn would refuse, an X post has more than max_cashtags cashtags, or a workspace rule wants text added or removed; posts lists a thread's post numbers to change), add-label (a required_label rule: add label to the draft's labels) or judge (a judged workspace rule: judge the post, then list rule_id in judged).",
+ "type": "string"
+ },
+ "media_ids": {
+ "description": "Reach alt-text fix: the attachments to describe in the draft's media references.",
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "operation_id": {
+ "description": "Reach media fix: the operation to upload or import a file, then attach it to the draft or named thread posts.",
+ "type": "string"
+ },
+ "patch": {
+ "description": "The change to the draft's body that applies this fix (send it with PATCH).",
+ "type": [
+ "object",
+ "null"
+ ]
+ },
+ "platform": {
+ "type": "string"
+ },
+ "post_at": {
+ "description": "Reach best-time fix: PATCH this top-level draft field, not body.post_at, then check again in the intended mode.",
+ "format": "date-time",
+ "type": "string"
+ },
+ "posts": {
+ "items": {
+ "description": "For an edit-text fix on a thread: the numbers (from 1) of the posts to change.",
+ "type": "integer"
+ },
+ "type": "array"
+ },
+ "tags": {
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ }
+ },
+ "required": [
+ "kind"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "option": {
+ "description": "A draft offering options: the option (1-based) this problem is in. A fix's text, media or posts patch goes to that option's version in options; its other fields to the body. Left out when every option has it.",
+ "type": "integer"
+ },
+ "rule_id": {
+ "description": "code rule: the failing rule's id.",
+ "type": "string"
+ },
+ "text": {
+ "description": "One plain sentence.",
+ "type": "string"
+ }
+ },
+ "required": [
+ "text"
+ ],
+ "type": "object"
+ },
+ "type": "array"
+ }
+ },
+ "required": [
+ "ok",
+ "problems",
+ "snapshot_hash"
+ ],
+ "type": "object"
+}