X (Twitter) API: Posting Reference
X (formerly Twitter) is supported via the X API v2. OmniSocials posts to the account that completed the OAuth flow. Both standard and premium accounts are supported, and the character limit adjusts based on the account's subscription tier.
Channel ID: x
Supported content types
| Type | Supported |
|---|---|
| Feed post | ✅ |
| Story | - |
| Reel | - |
Minimal example
Code
Platform-specific options
| Field | Type | Description |
|---|---|---|
x.reply_settings | string | Who can reply: "" (everyone, default), following, or mentionedUsers |
x.paid_partnership | boolean | Mark as a paid partnership disclosure (default false) |
x.made_with_ai | boolean | Mark as AI-generated content (default false) |
x.thread_parts | array | Publish as a chained thread instead of a single tweet. See Posting threads. |
Code
Posting threads
To publish as a thread, pass x.thread_parts instead of relying on content.x. Each part becomes its own tweet, chained via in_reply_to_tweet_id.
Code
Rules:
-
2 to 25 parts. For a single tweet, omit
thread_partsand usecontent.x(orcontent.default) instead. -
Each
textis required, non-empty, and ≤ 280 characters. Parts that exceed the limit are rejected with a400. -
media_urlsis optional per part (max 4) and overrides any top-levelmedia_urls.xfor that specific tweet:Code -
When
content.xis provided alongsidethread_parts,thread_partswins. -
The first tweet's URL becomes
x_posted_urlon the post. The full chain is recorded onx_values.thread_tweetsfor analytics.
To convert a thread back into a single tweet on update, send x.thread_parts: null to PATCH /posts/:id.
Character limits
| Account tier | Character limit |
|---|---|
| Standard | 280 |
| Premium (Blue) | 25,000 |
| Premium+ | 25,000 |
For single tweets, OmniSocials detects the connected account's subscription tier and enforces the correct limit at validation time. Thread parts always cap at 280 chars regardless of tier; that's an X API constraint, not an OmniSocials one.
Characters are weighted the way X counts them, not by string length. Every link counts as 23 characters no matter how long the URL is, and emoji and CJK characters count as 2 each (an emoji family joined with ZWJ counts as a single 2-weight unit). A 270-character post containing a 10-character link is over the limit. OmniSocials validates with the weighted count, so a rejection at create time means X would have rejected it too; X itself returns an unhelpful generic 403 for over-length posts.
Media requirements
| Media | Requirement |
|---|---|
| Image | JPEG, PNG, GIF, or WebP. Max 5 MB. Up to 4 per post. |
| Video | MP4, H.264 codec. Free and Basic accounts: up to 2 minutes 20 seconds, max 512 MB. Premium and Premium+ accounts: up to 125 minutes, max 16 GB (in practice bounded by OmniSocials' own limits: 1 GB for media added by URL, 100 MB for direct file uploads). The tier is detected from your connected X account; reconnect X after upgrading. |
X does not support mixing image and video in the same post. Video posts allow one video. Image posts allow up to four images.
Alt text. Pass a per-image accessibility description by using an object entry instead of a bare string: { "url": "https://example.com/chart.png", "alt": "Bar chart of Q3 signups by week" } in media_urls (or { "id": "...", "alt": "..." } in media_ids, including per-part thread media). It is set via X's v2 media metadata on photos and GIFs only (X does not support alt text on video), clamped to X's 1000-character cap. An alt-text failure at X never fails the publish.
Link posts use credits
X's API bills posts whose text contains a URL at a premium ($0.20 per tweet instead of $0.015). OmniSocials passes that fee through as prepaid credits at X's rate card: 20 credits per URL-containing tweet (credits cost €0.01 each, topped up €5-500 in the dashboard), with threads billed per part that contains a link. Everything else on X stays free: posts without links, analytics, media.
URL detection matches X's own autolinker: scheme links (https://...), www. links, and bare domains with common TLDs all count; spelled-out domains ("brand dot com") don't.
When a create targets X and the text contains a URL, the 201 response includes a top-level warnings array (code x_url_post_credits) with credits_required, the current credits_balance, and the enforcement state; see Creating Posts for the full shape. Debiting has been live since 2026-08-14. If the balance can't cover it at publish time, only the X target fails (other platforms publish normally); top up at app.omnisocials.com/credits and retry with POST /posts/:id/retry. Credits are managed in the dashboard; there is no API endpoint for them.
Scheduled X link posts also reserve their cost until they publish: scheduling or publishing a new one that would push the reserved total past the balance is refused with 402 x_credits_insufficient (see Creating Posts). Drafts are never gated.
Limitations
- Polls are not supported through the X API v2 for third-party apps
- Posting to X requires approval by X for the OAuth app. Newly created X developer accounts may be subject to rate limits lower than the platform default.