Docs
Threads

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

mediaKindSupportedWith textNotes
textYesRequiredNo mediaUrls
imageYesYesSingle image URL
multi-imageYesYes2–20 image/video URLs
videoYesYesSingle video URL
storiesNoRejected (UNSUPPORTED_MEDIA_KIND)

Features

FeatureSupportedNotes
ThreadYesExtra segments publish as a reply chain
QuoteYesDestination quoteTweetId
ScheduleYesscheduledFor + timezone
Remote deleteYesRequires 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_LONG if 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_IMAGE otherwise)
  • 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

  1. POST /v1/media (multipart file) → CDN url
  2. Pass that URL in mediaUrls on create post
  3. Threads requires a public HTTPS URL it can download

Details and limits: Media.

Publish errors (Threads)

CodeWhen
TEXT_REQUIREDText-only with empty message
TEXT_TOO_LONGMore than 500 characters
MEDIA_REQUIREDImage / video without a URL
UNSUPPORTED_MEDIA_KINDStories
INVALID_MULTI_IMAGEFewer than 2 or more than 20 multi-image URLs
INVALID_MEDIABad parameters / character limit
MEDIA_UNFETCHABLEThreads could not download the URL
CONTAINER_FAILEDMedia processing failed or expired
TOKEN_INVALIDReconnect account
PERMISSION_DENIEDMissing threads_content_publish → reconnect
Rate limitTransient — retry later

See also