Platforms
Publish text, image, video and carousel posts and multi-post threads to Threads, set topic tags, manage replies and read post metrics.
Publish text posts, images, videos, carousels and chains of connected posts to Threads, with a topic tag and a first reply. The same account reads post metrics and manages the replies people leave. The platform id is threads.
#What you can do
| Capability | Supported | Where |
|---|---|---|
| Publish | Text, one image, one video, carousels of up to 10 images, thread sequences | Create a post |
| Schedule | Yes | Scheduling |
| Delete after publishing | Yes, with Unpublish | Edit and unpublish |
| Analytics | Views, likes, replies, reposts and quotes | Platform insights |
| Replies | List, reply, hide, unhide, delete | Comments |
| DMs | No. Threads has no messaging API. | |
| Automations | Public reply to keyword replies | Comment to DM |
#Connect
Threads profiles belong to Instagram accounts, so the user signs in with the Instagram Business or Creator account that owns the Threads profile. Start with GET /v1/connect/threads and a profileId, then send the user to authUrl.
Because Threads depends on Instagram, an Instagram account that is restricted or loses access also stops publishing to Threads. If a Threads post fails with "Instagram account is restricted", fix the Instagram account first.
#Post types
Threads accepts text with no media, which makes it one of the easiest places to cross-post short updates.
curl -X POST https://api.pozy.ai/v1/posts \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Small teams ship faster when the default answer to a meeting is no.",
"platforms": [{
"platform": "threads",
"accountId": "6720c1a94f3b2e0018d4a7f7",
"platformSpecificData": { "topic_tag": "Startups" }
}],
"publishNow": true
}'const res = await fetch("https://api.pozy.ai/v1/posts", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.POZY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
content: "Small teams ship faster when the default answer to a meeting is no.",
platforms: [{
platform: "threads",
accountId: "6720c1a94f3b2e0018d4a7f7",
platformSpecificData: { topic_tag: "Startups" },
}],
publishNow: true,
}),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
console.log(data.post.platforms[0].platformPostUrl);import os, requests
resp = requests.post(
"https://api.pozy.ai/v1/posts",
headers={"Authorization": f"Bearer {os.environ['POZY_API_KEY']}"},
json={
"content": "Small teams ship faster when the default answer to a meeting is no.",
"platforms": [{
"platform": "threads",
"accountId": "6720c1a94f3b2e0018d4a7f7",
"platformSpecificData": {"topic_tag": "Startups"},
}],
"publishNow": True,
},
)
print(resp.json()["post"]["platforms"][0]["platformPostUrl"])| Post type | How to send it |
|---|---|
| Text | content, up to 500 characters |
| Image | One image in mediaItems |
| Video | One video, up to 5 minutes |
| Carousel | 2 to 10 images |
| Thread sequence | platformSpecificData.threadItems |
Threads posts stop at 500 characters. A caption cross-posted from LinkedIn, Facebook or Instagram usually runs longer and fails with "Param text must be at most 500 characters long". Give the Threads entry its own customContent.
#Thread sequence
threadItems publishes a chain: item 0 is the first post and each later item replies to the one before. Every item can carry text, media or both (text is optional when there is media). When threadItems is set, the top-level content is stored in Pozy for display and search but not published.
{
"platform": "threads",
"accountId": "6720c1a94f3b2e0018d4a7f7",
"platformSpecificData": {
"threadItems": [
{ "content": "What we learned shipping a mobile app with two engineers.", "mediaItems": [{ "type": "image", "url": "https://cdn.example.com/app-cover.jpg" }] },
{ "content": "1. One codebase. We never regretted it." },
{ "content": "2. A weekly release train, even when the train was half empty." },
{ "content": "3. Support tickets in the team channel, not a separate tool." }
]
}
}#Platform fields
Schema: ThreadsPlatformData.
| Field | Notes |
|---|---|
topic_tag |
1 to 50 characters, no periods or ampersands. Overrides the topic Threads would take from hashtags in the text. |
threadItems |
The whole sequence, first post first. Each item: content, mediaItems. |
firstComment |
A reply to your own post right after publishing (to the first post when using threadItems). Up to 500 characters. It is a post in its own right, so it counts toward the daily limit. |
#Media requirements
Threads fetches media the same way Instagram does. Media URLs must return the file itself (cloud-drive sharing links fail), and WebP images can fail, so send JPEG or PNG. Images over 8 MB are compressed automatically.
| Images | Video | |
|---|---|---|
| Formats | JPEG, PNG | MP4 (H.264, AAC) |
| Max size | 8 MB each | 1 GB |
| Count | 1, or up to 10 in a carousel | 1 |
| Duration | Up to 5 minutes | |
| Aspect ratio | 4:5 (1080 x 1350) recommended; 1:1 and 16:9 work | 9:16, 16:9 or 1:1 |
| Other | 1080p, 30 fps, AAC 128 kbps recommended |
#Limits
| Limit | Value |
|---|---|
| Post text | 500 characters |
| First reply | 500 characters |
| Topic tag | 50 characters |
| Posts per account | 250 per 24 hours, including first replies and each post in a sequence |
| Carousel | 10 images |
The API cannot create polls or quote posts, search GIFs, edit a published post, show who liked or reposted, or like replies.
#Analytics
GET /v1/analytics?platform=threads returns views, likes, comments (replies) and shares per post. Threads has no impressions metric, so use views as the reach figure. shares adds reposts and quotes together.
#Inbox
Threads has no DMs. Replies to your posts show up as comments. A comment on Threads is itself a reply to the post, so calling Reply to comment without a commentId replies to the post itself, and with one it answers that reply. You can delete replies, and hide or unhide them. Liking replies is not supported.
New replies are picked up by polling, so automated replies can lag by a few minutes.
#Errors you may see
| Message | Cause | Fix |
|---|---|---|
| Param text must be at most 500 characters long | Text over the limit | Shorten it or set customContent for Threads. |
| Media download has failed. The media URI doesn't meet our requirements. | Threads could not fetch the file | Use a direct file URL; switch WebP to JPEG or PNG. |
| Instagram account is restricted | The linked Instagram account has a restriction | Resolve it in Instagram, then retry. |
| Publishing failed due to max retries reached | Temporary failure on Threads' side | Wait a few minutes and retry. |
A rejected publishNow: true post returns 207 with post.status: "failed" and the reason in platforms[].errorMessage.
#Endpoints
| Endpoint | What it does |
|---|---|
POST /v1/posts |
Create post |
POST /v1/posts/{postId}/unpublish |
Unpublish post |
GET /v1/inbox/comments/{postId} |
Get post comments |
POST /v1/inbox/comments/{postId} |
Reply to comment |
POST /v1/inbox/comments/{postId}/{commentId}/hide |
Hide comment |
DELETE /v1/inbox/comments/{postId}/{commentId}/hide |
Unhide comment |
DELETE /v1/inbox/comments/{postId} |
Delete comment |
GET /v1/analytics |
Get post analytics |
#Webhook events
| Event | When it fires |
|---|---|
post.published |
Post published. |
post.failed |
Post failed. |
post.platform.published |
Post platform published. |
post.platform.failed |
Post platform failed. |
post.platform.deleted |
Post platform deleted. |
account.disconnected |
Account disconnected. |
comment.received |
Comment received. |