Post to Instagram / Threads
antix_compose_social_postBook a post on the user's own connected Instagram and/or Threads channels (one post per channel). Set confirm: true ONLY after the user explicitly said to post — without it the post waits for approval (antix_approve_post). Nothing is live when this returns: the publisher posts within about a minute of the post's time — confirm with antix_get_post and say it is live only once it reports published with a permalink. FREE. Each request is checked first (caption length, hashtags, carousel size, video length); Instagram photos outside 4:5…1.91:1 are cropped and the response says so. Media: historyIds of AIGE generations, photos and/or videos (1 image = photo post, 1 video = Reel / Threads video, 2 or more = carousel that can mix photos and up to 4 videos — Instagram takes up to 10 items, Threads up to 20, and the server caps a post at 10), or a carousel deckId; neither = a Threads text post (Instagram needs media). when: "now", "queue" (each channel's own next free posting time from the schedule saved on it — see queueSlots / nextQueueSlot in antix_list_channels; a channel with no posting times, or none left in the next 90 days, is refused as VALIDATION_ERROR), "draft", or an ISO-8601 time WITH a timezone. LIMIT_REACHED ("limit reached on @handle") is a different thing: that channel already holds all the waiting posts it is allowed. Instagram Stories: instagram: { format: "story" } with exactly ONE image or video (a video of 3–60 seconds) — the caption isn't posted. Instagram lets apps post Stories only for Business accounts (accountType in antix_list_channels), so on any other Instagram channel (or with instagram.reminder: true, for stickers and links) the Story is a reminder: AIGE notifies the user at its time to post it themselves and never posts it — its status ends at handoff_ready, never published, so promise no permalink; the booking reply says which channels got a reminder. First comment: instagram: { firstComment } (up to 2,200 characters; Instagram channels only — a request without one is refused; not with a Story) is posted under each Instagram post once it is live; the channel needs instagram_business_manage_comments in grantedScopes, otherwise the booking is refused and the user reconnects in the browser. Threads thread: the Threads text is threads.text when set, else the caption. A Threads text over 500 characters (Threads' count: an emoji counts as several) is split into a thread automatically (at paragraph, then sentence breaks; up to 10 posts — the response says so), unless threads: { chain: [{ text, historyId?, altText? }] } is given — up to 9 replies of up to 500 characters each, posted one under another once the post is live, each with at most one IMAGE (a historyId) and its alt text; with a chain the Threads text itself must fit in 500. A thread (written or split) needs threads_manage_replies in the channel's grantedScopes, otherwise the booking is refused and the user reconnects in the browser. Threads topic tag, who can reply, poll: threads: { topicTag, replyControl, poll } — topicTag is the post's one topic tag (1–50 characters, no periods or &; without it the first usable entry of hashtags is used and the response says so, since Threads has no hashtag list), replyControl is who can reply ("everyone", "accounts_you_follow", "mentioned_only", "followers_only" or "parent_post_author_only"; omit it for Threads' default), and poll: { options } is a poll of 2–4 different options of up to 25 characters on a text post only — no historyIds or deckId, the caption is the question. All three apply to the post itself (a thread's first post), never to its replies, and need a Threads channel in the request. Threads extras: threads: { extras: { linkAttachment, quotePostId, ghost, spoilerMedia, spoilerRanges, replyApprovals, countries } }, each optional and on the post itself only — linkAttachment is an https:// link shown as a preview card (text posts only; Threads allows 5 links per post, counting the caption's), quotePostId quotes a Threads post (for the user's own live Threads post use its providerPostId from antix_get_post), ghost:true makes a text-only post that disappears after 24 hours (no media, thread, poll, link preview, quote or reply approvals), spoilerMedia:true hides the photos or videos behind a spoiler, spoilerRanges hides up to 10 parts of the Threads text ({ offset, length } counted as JavaScript counts — an emoji is 2 — from the start of threads.text, else the caption; inside that text, and for a long text split into a thread inside the first post; not overlapping), replyApprovals:true makes the user approve replies in the Threads app (AIGE has no inbox for them yet), and country limits (countries) are set in the AIGE app for now — a booking that sets them here is refused, so tell the user to set them in the app. Alt text: altTexts — one per historyIds item, same order ("" for an item with none), up to 1,000 characters each; Instagram sends it on photos only (a single photo or a carousel photo — never a Reel or a Story, and the response says when it isn't sent), Threads on photos and videos; not with a deckId. Collaborators: instagram: { collaborators: ["anna", "ben"] } invites up to 3 Instagram accounts to co-author the post (a photo, Reel or carousel; not a Story, not the channel's own account) — only while antix_list_channels reports features.instagramCollaborators: true; otherwise the booking is refused. Tagging people: userTags — one list per historyIds item, same order ([] for an item with none), up to 20 per item, each { username, x, y }; on a photo x and y (0–1 from the top-left corner of the photo as posted) are required, a Reel or a Story takes the username alone; a carousel is cropped to the shape of its FIRST item (a photo or a video), and a carousel video takes no tags (they aren't sent for it, and the response warns). Instagram only — a request with tags and no Instagram channel is refused; not with a deckId; and only while antix_list_channels reports features.instagramUserTags: true — otherwise the booking is refused. Reel options: instagram: { reel: { coverHistoryId, thumbOffsetMs, shareToFeed, audioName, trial } } — only when historyIds is exactly ONE video (no Story, no deck, no photo or carousel; anything else is refused): coverHistoryId is an IMAGE of the user's to use as the cover (Instagram crops it to 9:16, and the response warns when it isn't close), thumbOffsetMs picks a moment of the video as the cover instead (ignored when there is a cover; must be inside the video), shareToFeed:false keeps the Reel out of the main feed (default true), audioName renames the Reel's original audio (up to 100 characters; Instagram allows ONE rename in total, so it can't be changed later), and trial ("MANUAL" or "SS_PERFORMANCE") posts it as a Trial Reel shown to non-followers first. A different text per platform: the top-level caption goes to every picked channel unless instagram: { caption } and/or threads: { text } give that platform its own (a blank one means the caption; instagram: { caption } is refused without an Instagram channel) — e.g. a long Instagram caption beside a short Threads post; the Threads text is the one that is split into a thread when it is over 500, and spoilerRanges count from its start.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| when | Yes | "now", "queue" (each channel's next free posting time from the schedule the user saved on it — antix_list_channels shows `queueSlots` and `nextQueueSlot`; a channel without posting times, or with none left in the next 90 days, is refused as a VALIDATION_ERROR — not LIMIT_REACHED, which is the cap on waiting posts), "draft" (book it for approval later), or an ISO-8601 date-time WITH a timezone, e.g. "2026-10-16T09:00:00+03:00". | |
| deckId | No | A carousel deck to post instead of historyIds. Never both. | |
| caption | Yes | The post text, shared by every picked channel unless instagram.caption or threads.text gives that platform its own. Instagram: the caption (hashtags are appended). Threads: 500 characters per post (an emoji counts as several) — a longer text is split into a thread automatically (at paragraph, then sentence breaks; up to 10 posts) unless threads.chain is given, which needs the Threads text (threads.text when set, else this caption) to be at most 500. | |
| confirm | No | true only after the user explicitly said to post. Without it the post waits for approval (antix_approve_post) — except a timed post on a channel the user put on autopilot, which posts on its own at its time. Posting "now" always needs confirm:true. | |
| threads | No | Threads-only options: the Threads post's own text, a thread of several posts, a topic tag, who can reply, a poll and extras (link preview, quote, ghost post, spoilers, reply approvals). A Threads text over 500 characters is split into a thread automatically unless chain is given. A request with no Threads channel can't carry them. Instagram channels in the same request ignore them. | |
| altTexts | No | Alt text (accessibility descriptions), one per historyIds item, same order — use "" for an item with none. Up to 1,000 characters each; never more texts than items, and not with deckId. Instagram uses it on photos (a single photo or a carousel photo) and not on Reels or Stories — the response says so; Threads uses it on photos and videos. | |
| hashtags | No | Hashtags, with or without #. Instagram appends them to the caption. Threads has no hashtag list: the first one that can be a topic tag becomes the post's topic tag (unless threads.topicTag is given) and the rest are left off — the response says so. | |
| userTags | No | People to tag on the Instagram post — one list per historyIds item, same order ([] for an item with none), up to 20 per item; not with deckId. Each tag is { username (with or without @), x, y }: on a PHOTO (a single photo or a carousel photo) x and y are required — send both, 0–1 from the top-left corner of the photo AS POSTED (x across, y down; 0.5/0.5 is the middle) — a feed photo outside 4:5 … 1.91:1 is cropped from the middle first, and every photo of a carousel takes the shape of the FIRST item (a photo or a video); a Reel or a Story takes the username alone (x and y are ignored), and a video in a carousel takes no tags — they aren't sent for it, and the response warns. Instagram only: a request with tags and no Instagram channel is refused (a Threads channel in the same request just doesn't get them). Only while antix_list_channels reports features.instagramUserTags: true — until then Instagram doesn't take photo tags from AIGE and the booking is refused, so don't offer it. | |
| No | Instagram-only options. Threads channels in the same request ignore them. | ||
| channelIds | Yes | Channel ids from antix_list_channels — one post is booked per channel. | |
| historyIds | No | AIGE generations to post (ids from antix_get_history), photos and/or videos: 1 image = photo post, 1 video = Reel / Threads video, 2 or more = carousel (photos and videos can be mixed, up to 4 videos; Instagram takes up to 10 items, Threads up to 20 — the server caps a post at 10). Omit for a Threads text post. |