Posts
Publish text, image, video, and multi-image on Threads.
Publish to Threads through the shared POST /v1/posts surface.
Cross-platform flow: Media guide.
Supported formats
mediaKind | Supported | With text | Notes |
|---|---|---|---|
text | Yes | Required | No mediaUrls |
image | Yes | Yes | Single image URL |
multi-image | Yes | Yes | 2–20 image/video URLs |
video | Yes | Yes | Single video URL |
stories | No | — | Rejected (UNSUPPORTED_MEDIA_KIND) |
Features
| Feature | Supported | Notes |
|---|---|---|
| Thread | Yes | Extra segments publish as a reply chain |
| Quote | Yes | Destination quoteTweetId |
| Schedule | Yes | scheduledFor + timezone |
| Remote delete | Yes | Requires threads_delete (reconnect if missing) |
Create
curl -X POST https://api.onepostly.com/v1/posts \
-H "x-api-key: op_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "Hello from Onepostly",
"mediaKind": "text",
"destinations": [
{ "connectionId": "YOUR_THREADS_CONNECTION_ID" }
]
}'{
"text": "Hello from Onepostly",
"mediaKind": "text", // text | image | multi-image | video — stories not supported
"mediaUrls": [],
"destinations": [
{ "connectionId": "YOUR_THREADS_CONNECTION_ID" }
]
}Response: 202 with status: "queued". Poll GET /v1/posts/:id until the destination is published or failed — or use webhooks instead of polling.
Rules
- Text max 500 characters (
TEXT_TOO_LONGif exceeded) - Text-only posts require non-empty text (
TEXT_REQUIRED) - Stories are rejected
Text-only
{
"text": "Just a thought",
"mediaKind": "text",
"destinations": [{ "connectionId": "YOUR_THREADS_CONNECTION_ID" }]
}Image
{
"text": "Caption optional",
"mediaKind": "image",
"mediaUrls": ["https://cdn.example.com/photo.jpg"],
"destinations": [{ "connectionId": "YOUR_THREADS_CONNECTION_ID" }]
}Video
{
"text": "Video caption",
"mediaKind": "video",
"mediaUrls": ["https://cdn.example.com/video.mp4"],
"destinations": [{ "connectionId": "YOUR_THREADS_CONNECTION_ID" }]
}Multi-image
{
"text": "Multi-image caption",
"mediaKind": "multi-image",
"mediaUrls": [
"https://cdn.example.com/1.jpg",
"https://cdn.example.com/2.jpg",
"https://cdn.example.com/clip.mp4"
],
"destinations": [{ "connectionId": "YOUR_THREADS_CONNECTION_ID" }]
}- Requires 2–20 URLs (
INVALID_MULTI_IMAGEotherwise) - Mix of images and videos allowed
Schedule
Pass scheduledFor (timezone-naive local datetime, e.g. 2026-07-16T12:00:00) and timezone (IANA, e.g. America/New_York). Defaults to UTC when timezone is omitted. Do not send Z or a numeric offset on scheduledFor. Future times stay scheduled until publish time.
Thread (reply chain)
Pass extra segments (same shape as X). Onepostly publishes the root, then each follow-up as a reply.
Quote
Set quoteTweetId to another Threads media id.
Remote delete
curl -X DELETE "https://api.onepostly.com/v1/posts/POST_ID/destinations/DEST_ID" \
-H "x-api-key: op_YOUR_KEY"Requires threads_delete. Emits destination.deleted.
Media
POST /v1/media(multipartfile) → CDNurl- Pass that URL in
mediaUrlson create post - Threads requires a public HTTPS URL it can download
Details and limits: Media.
Publish errors (Threads)
| Code | When |
|---|---|
TEXT_REQUIRED | Text-only with empty message |
TEXT_TOO_LONG | More than 500 characters |
MEDIA_REQUIRED | Image / video without a URL |
UNSUPPORTED_MEDIA_KIND | Stories |
INVALID_MULTI_IMAGE | Fewer than 2 or more than 20 multi-image URLs |
INVALID_MEDIA | Bad parameters / character limit |
MEDIA_UNFETCHABLE | Threads could not download the URL |
CONTAINER_FAILED | Media processing failed or expired |
TOKEN_INVALID | Reconnect account |
PERMISSION_DENIED | Missing threads_content_publish → reconnect |
| Rate limit | Transient — retry later |
See also
- Overview — scopes and capabilities
- Comments
- Engagement
- Insights
- Media