Docs
X (Twitter)

Posts

Publish, media upload, threads, quotes, schedule, and remote delete on X.

Publish to X through the shared POST /v1/posts surface.

Cross-platform flow: Media guide.

Supported formats

mediaKindSupportedWith textNotes
textYesRequiredNo mediaUrls
imageYesYesSingle image in mediaUrls (max 5 MB)
multi-imageYesYes2–4 images in mediaUrls
videoYesYesSingle video (or GIF) URL; not mixed with other media

Features

FeatureSupportedNotes
ThreadYesthread[]; media on the first tweet only
QuoteYesquoteTweetId on create, or POST …/quotes
ScheduleYesscheduledFor + timezone
Remote deleteYesDeletes the full thread chain when present

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_X_CONNECTION_ID" }
    ]
  }'
{
  "text": "Hello from Onepostly",
  "mediaKind": "text", // text | image | multi-image | video — stories not supported
  "destinations": [
    { "connectionId": "YOUR_X_CONNECTION_ID" }
  ]
}

X supports text, image, multi-image, and video/GIF (all can include caption text).

Response: 202 with status: "queued". Poll GET /v1/posts/:id until the destination is published or failed — or use webhooks instead of polling.

Rules

  • mediaKind is required (default text when omitted)
  • Text-only posts require non-empty text and mediaKind: "text"
  • Max 280 characters per segment
  • Stories (mediaKind: "stories") are rejected
  • Wallet: billed at X list prices (create; URL surcharge when applicable)

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.

{
  "text": "Scheduled hello",
  "scheduledFor": "2026-07-16T12:00:00",
  "timezone": "America/New_York",
  "destinations": [{ "connectionId": "YOUR_X_CONNECTION_ID" }]
}

Media

  1. POST /v1/media (multipart file) → CDN url
  2. Pass that URL in mediaUrls on create post with an explicit mediaKind

Limits

TypeLimit
ImagesUp to 4 per tweet; max 5 MB each
GIFSingle attachment; max 15 MB
VideoSingle attachment; max 512 MB
Mixed multi-videoRejected

Media attaches to the first tweet only when publishing a thread.

Thread

{
  "thread": ["1/3 intro", "2/3 body", "3/3 CTA"],
  "destinations": [{ "connectionId": "YOUR_X_CONNECTION_ID" }]
}
  • thread[0] is the root text (overrides top-level text when provided)
  • thread[1…] are reply-chain segments
  • Wallet cost = sum of each segment’s create cost

Quote

Option A — on create

{
  "text": "My take",
  "destinations": [
    {
      "connectionId": "YOUR_X_CONNECTION_ID",
      "quoteTweetId": "2077337724349026673"
    }
  ]
}

Some X API tiers gate quote tweets.

Option B — from an existing published post

curl -X POST https://api.onepostly.com/v1/posts/POST_ID/quotes \
  -H "x-api-key: op_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"destinationId":"DEST_ID","text":"My take"}'

Creates a new Onepostly post + destination (listable and remote-deletable), quoting the source destination’s externalPostId.

Remote delete

curl -X DELETE \
  "https://api.onepostly.com/v1/posts/POST_ID/destinations/DEST_ID" \
  -H "x-api-key: op_YOUR_KEY"

Thread delete behavior

  1. Deletes the full thread (replies then root) when applicable
  2. Already-deleted tweets count as success
  3. If the root cannot be deleted → fail
  4. If root is gone but some replies fail → THREAD_DELETE_PARTIAL

Wallet: billed at X list prices per deleted external id.

Publish errors (X)

CodeWhen
TEXT_REQUIRED / TEXT_TOO_LONGEmpty or >280 chars
UNSUPPORTED_MEDIA_KINDStories
INVALID_MEDIA / MEDIA_UNFETCHABLEBad URL or size/type
MEDIA_UPLOAD_FAILED / MEDIA_PROCESSING_FAILEDUpload or processing failed
TOKEN_INVALIDReconnect account
PERMISSION_DENIEDMissing tweet.write / media.write
INSUFFICIENT_WALLETOnepostly wallet empty
429 / 502 / 503Transient — retry later

See also