Publish a post to X (Twitter). Requires the connected account to have authorized X via https://www.eranol.com/dashboard/social-media. Example: {"text": "Hello from n8n!", "media_urls": ["https://www.eranol.com/image.png"]}
Publishes a post to X (formerly Twitter) on behalf of a connected eranol.com account. Optionally attaches up to 4 images, and can be published immediately or scheduled for a future time.
Before this endpoint can be used, the target account must have connected X via Dashboard → Social Media → Connect (OAuth 2.0). Calls for an account with no active X connection return a 400 error.
https://eranol.com/api/v1/social/x/publish
X charges us per post — about $0.015 for a plain post, or $0.20 if the post text contains a URL. Pricing here follows that split:
Posting a URL also requires the account to have purchased credits at least once — accounts running only on trial/free credits get a 403 if they try to post a link. This keeps the endpoint's economics sane: plain posts are cheap enough to be open to everyone, link posts cost us more so they're gated to paying customers.
| Field | Type | Required | Notes |
|---|---|---|---|
text | string | Yes | Post text. Max 280 characters by default. Accounts with an X Premium/Blue subscription can post up to ~25,000 characters — see Long-form posts below |
media_urls | string[] | No | Up to 4 image URLs. Each URL must be hosted on eranol.com or www.eranol.com — external URLs are rejected |
scheduled_for | string | No | ISO 8601 timestamp in the future. When set, the post is queued and published later instead of immediately — see Scheduling below |
If text is longer than 280 characters, the connected X account must have an active Premium/Blue subscription. This is checked live against X's API at request time (not cached), so a downgrade or upgrade takes effect immediately. If the account isn't eligible, the request is rejected with a 400 before anything is posted. X's own limits for its subscription tiers are the final authority — a request that passes our check can still be rejected by X itself if the account isn't entitled to post that length.
Long-form posting does not change the credit cost by itself — cost is based purely on whether text contains a URL, regardless of length.
Pass scheduled_for as a future ISO timestamp to queue the post instead of publishing it right away. Scheduled posts:
202 Accepted instead of 200, with a different response shape (see below){
"text": "Just shipped a new feature 🚀",
"media_urls": ["https://www.eranol.com/uploads/screenshot.png"]
}
{
"text": "Announcing this next week 📅",
"scheduled_for": "2026-09-01T15:00:00Z"
}
{
"success": true,
"tweet_id": "1234567890123456789",
"post_url": "https://x.com/i/web/status/1234567890123456789",
"log_id": "b7e1c2a4-..."
}
{
"success": true,
"scheduled": true,
"scheduled_post_id": "a1b2c3d4-...",
"scheduled_for": "2026-09-01T15:00:00.000Z"
}
| Status | Meaning |
|---|---|
400 | Missing/invalid text, text too long (over 25,000 characters), invalid media_urls host, invalid/past scheduled_for, the account has no connected X account, or text exceeds 280 characters without an eligible Premium/Blue subscription |
401 | X rejected the request — the connection's token may need to be refreshed by reconnecting via the dashboard |
402 | Insufficient credits |
403 | The post text contains a URL, but the account has never purchased credits (trial/free credits alone don't cover link posts) |
502 | X's API returned an error, or one of the media_urls couldn't be fetched or uploaded (e.g. duplicate post, rate limited) — no credits are charged on failure |
text is no longer capped at a flat 280 characters. Accounts with X Premium/Blue can post up to ~25,000 characters; the API checks the connected account's live subscription status (not cached) whenever text exceeds 280.scheduled_for field (new). Optional ISO timestamp to queue a post for later instead of publishing immediately. Returns 202 with a distinct response shape (scheduled_post_id, scheduled_for — no tweet_id/post_url until it actually fires). Credits are charged at scheduling time, not at publish time.403 error. Posting a URL requires the account to have purchased credits at least once; trial-only accounts get blocked with 403 instead of being silently charged more than their trial credits are worth. This gate does not apply to plain (URL-free) posts — those are open to everyone.502 scope widened. Now also covers failures fetching or uploading the media_urls themselves, not just errors from X's tweet-creation call.media_urls host restriction (eranol.com/www.eranol.com only), 4-image cap, images-only (no video/GIF support), 401/402 meanings, and the success response field names (tweet_id, post_url, log_id) for immediate posts.