Twitter API (X API) for posting and scheduling
Send one request and PostMCP handles Twitter API v2 for you — PKCE OAuth, the three-step chunked media upload, refresh tokens and the final tweet call.
- Endpoint
- POST /api/tools/create_post
- Platform value
- "twitter"
- Auth
- x-api-key or Bearer token
- Upstream
- Twitter API v2 /2/tweets
What the X (Twitter) API gives you
Posting to X directly means an OAuth 2.0 PKCE flow, an offline.access refresh loop, and — the moment you want an image — a chunked upload sequence of initialize, append and finalize against the v2 media endpoints before you can reference a media ID in the tweet body.
The PostMCP X API turns that into a single call. Send content, platforms: ["twitter"] and an optional mediaUrl; the engine sniffs the MIME type, runs the full chunked upload, waits for processing and posts to /2/tweets. If media upload fails, it degrades gracefully by appending the URL to the tweet text rather than dropping the post.
Text tweets
Plain posts published as the connected handle through Twitter API v2.
Native media tweets
Images and MP4 video are uploaded through the v2 chunked endpoints and attached as real media, not links.
Automatic MIME detection
The engine reads the file extension to set media_type — JPEG, PNG, GIF, WebP and MP4 are recognised.
Graceful media fallback
If the upload handshake fails the tweet still ships, with the media URL appended to the text instead of being lost.
Refresh-token sessions
offline.access is requested at connect time so long-lived automation keeps posting without re-auth.
Scheduled tweets
Queue by date and time, then update, force-publish or delete before the slot arrives.
Common uses
- Auto-tweet deploy notifications from CI with a screenshot attached.
- Let an agent thread out a product launch on a schedule you approve first.
- Mirror Bluesky posts to X without maintaining two integrations.
- Queue a month of evergreen tips from a spreadsheet in one script.
Post to X (Twitter) in three steps
Connect the account once, grab an API key, then send a single request. The same body works from a shell, a server, or an AI agent.
- 1
Connect your X (Twitter) account
Open the dashboard, choose X (Twitter) and complete the hosted connect flow. Credentials are encrypted into the user vault and never returned to your client.
- 2
Create an API key
Generate a key from the dashboard. Send it as
x-api-key, as anAuthorization: Bearerheader, or as anapikeyquery parameter on the MCP transport. - 3
Send your first post
POST to
/api/tools/create_postwithplatforms: ["twitter"]. SetpublishImmediatelyto broadcast now, or supplyscheduleDateandscheduleTimeto queue it.
curl -X POST "https://api.postmcpai.com/api/tools/create_post" \
-H "Content-Type: application/json" \
-H "x-api-key: $POSTMCPAI_API_KEY" \
-d '{"content":"Shipping something new today. Built with PostMCP AI.","platforms":["twitter"],"publishImmediately":true}'{
"success": true,
"message": "Post created and queued successfully",
"post": {
"id": "66a50c89e4b019a2b72f",
"content": "Shipping something new today. Built with PostMCP AI.",
"platforms": [
"twitter"
],
"status": "published"
}
}X (Twitter) API endpoints
Every endpoint is a POST against the base URL https://api.postmcpai.com. The same seven operations cover all connected networks — set the platform value to "twitter" to target X (Twitter).
| Operation | Endpoint | What it does |
|---|---|---|
| preflight_post | POST/api/tools/preflight_post | Dry-run copy against limits, targets and credits before publishing. |
| create_post | POST/api/tools/create_post | Schedule a post or broadcast it immediately. |
| publish_post_now | POST/api/tools/publish_post_now | Force a queued post out ahead of its slot, or retry the profiles that failed. |
| list_posts | POST/api/tools/list_posts | Read the queue — scheduled, published, draft and failed — with counts. |
| get_post | POST/api/tools/get_post | Read one post, with per-profile delivery state and live URLs. |
| get_post_analytics | POST/api/tools/get_post_analytics | Read how a post did: views, likes, comments and shares per profile. |
| get_profile_analytics | POST/api/tools/get_profile_analytics | Read a profile’s followers, post count and views from its network. |
| update_post | POST/api/tools/update_post | Edit copy, targets, schedule or status before publication. |
| reschedule_post | POST/api/tools/reschedule_post | Move a post to another slot, keeping its copy and targets. |
| reset_stuck_post | POST/api/tools/reset_stuck_post | Release a post left stuck mid-publish so it can be retried. |
| delete_post | POST/api/tools/delete_post | Remove a scheduled or draft post from the queue. |
| get_connected_accounts | POST/api/tools/get_connected_accounts | List connected profiles, handles and page IDs per platform. |
| get_account_health | POST/api/tools/get_account_health | Find connections whose token expired or is about to. |
| generate_image | POST/api/tools/generate_image | Generate a post image and get back a hosted URL for mediaUrl. |
| list_workspaces | POST/api/tools/list_workspaces | List the workspaces on this key, with the id to scope other calls to. |
| get_user_info | POST/api/tools/get_user_info | Read plan tier and credit balance. |
create_post parameters
| Field | Type | Required | Description |
|---|---|---|---|
| content | string | Yes | Text body of the post. Truncation rules are enforced by the destination network, not by PostMCP. |
| targetAccounts | array[object] | Yes | The profiles that receive the post. Each entry takes platform and profileId (from get_connected_accounts). Only the profiles listed here are posted to. |
| platforms | array[string] | Optional | Shorthand for whole networks — linkedin, twitter, facebook, instagram, threads, bluesky, youtube. Each one expands to every connected profile on it, so prefer targetAccounts unless you mean that fan-out. Optional when targetAccounts is given. |
| publishImmediately | boolean | Optional | When true the post is broadcast on receipt. Defaults to false, which queues it. |
| scheduleDate | string | Optional | Publication date as YYYY-MM-DD. Required when publishImmediately is false. |
| scheduleTime | string | Optional | Publication time as HH:MM on a 24-hour clock. Required when publishImmediately is false. |
| timezone | string | Optional | IANA zone the schedule above is written in, e.g. Asia/Kolkata. Omit it and the wall-clock slot resolves as UTC, which is rarely what "10am" meant. |
| mediaUrl | string | Optional | Publicly reachable image or video URL. PostMCP fetches it and re-uploads it in the format the network expects. Required, and must be a video, when the post targets YouTube. |
| workspaceId | string | Optional | Workspace to post from, taken from list_workspaces. Omitted, the call resolves to the default workspace on the key. |
X (Twitter) OAuth and API keys
Two layers of auth sit under every request: the X (Twitter) credential you grant once during connect, and the PostMCP API key your code sends on each call.
Open the connect URL
Send the user to /connect/twitter. PostMCP builds the authorize URL with a signed state JWT and a PKCE code challenge.
X consent screen
The user grants read, write, media and offline access on twitter.com/i/oauth2/authorize.
Code exchange
The callback code is exchanged for an access token and a refresh token, both encrypted into the user vault.
Publish with your API key
Your requests carry a PostMCP key. The X tokens stay server-side and are refreshed transparently.
Scopes requested from X (Twitter)
| Scope | Why it is needed |
|---|---|
| users.read | Reads the connected handle and account ID. |
| tweet.read | Required alongside write access by the X API. |
| tweet.write | Creates posts on the account's behalf. |
| media.write | Uploads image and video media through the v2 endpoints. |
| offline.access | Issues a refresh token so sessions survive access-token expiry. |
Sending your API key
x-api-key: pmcp_sec_…Authorization: Bearer pmcp_sec_…/mcp?apikey=pmcp_sec_…How PostMCP publishes to X (Twitter)
One request from you becomes this sequence server-side. Knowing the shape helps when you are debugging a failed broadcast.
- 1
Detect the media type
The
mediaUrlextension maps to a MIME type —.png,.gif,.webpand.mp4are detected, otherwise JPEG is assumed. - 2
Initialize the upload
Total byte length and media type are declared, and X returns a media ID to append against.
- 3
Append the segment
The buffer is posted as multipart form data at
segment_index0. - 4
Finalize and wait
The upload is closed and the engine pauses ~2s for X to finish processing the asset.
- 5
Create the tweet
A POST to
/2/tweetscarries the text and, when the upload succeeded, the media ID array. - 6
Fall back if needed
Any upload failure resets the media ID and the tweet is sent with the media URL appended to the text.
Upstream X (Twitter) calls
| Method | Endpoint | Purpose |
|---|---|---|
| POST | https://api.twitter.com/2/media/upload/initialize | Declares total byte count and media type, returns a media ID. |
| POST | https://api.twitter.com/2/media/upload/{id}/append | Uploads the binary segment as multipart form data. |
| POST | https://api.twitter.com/2/media/upload/{id}/finalize | Closes the upload and starts server-side processing. |
| POST | https://api.twitter.com/2/tweets | Creates the post, referencing `media.media_ids` when media is attached. |
Direct X (Twitter) API vs PostMCP
| Aspect | Calling X (Twitter) directly | With PostMCP |
|---|---|---|
| Auth setup | PKCE challenge, token exchange, refresh loop | One OAuth click, tokens refreshed server-side |
| Media upload | initialize → append → finalize → poll | One `mediaUrl` field |
| Image galleries | Four uploads, four media ids on the tweet | One `mediaUrls` array of up to four |
| Upload failure | Post fails or you build your own fallback | Automatic text fallback, post still ships |
| Scheduling | Not available in the API | Queue, edit, force-publish, delete |
| Cross-posting | Separate integration per network | Add values to the `platforms` array |
X (Twitter) limits and supported media
These ceilings are set by X (Twitter), not by PostMCP. Your content field is forwarded unchanged, so the network enforces them rather than silently truncating.
Common X (Twitter) API errors
Failures are recorded per platform on the post record, so a multi-network broadcast that partially succeeds tells you exactly which leg failed and why.
| Code | Message | Likely cause | Fix |
|---|---|---|---|
| 401 | Access token for twitter is missing or invalid | The refresh token was revoked or the connection was removed in X settings. | Reconnect the X account from the dashboard. |
| 403 | Twitter API v2 posting failed | The access tier does not permit writes, or duplicate content was detected. | Check the X developer plan attached to the account and vary duplicate copy. |
| 400 | Twitter Media Upload Initialization failed | Media exceeded the size ceiling for its type or the URL was unreachable. | Host smaller media on a public URL; the post still ships with the URL appended. |
| 429 | Too Many Requests | The per-app or per-user posting window was exhausted. | Schedule posts across the window instead of sending them in a burst. |
Post to X (Twitter) from an AI agent
The same seven operations are exposed as MCP tools. Point Claude Desktop, Cursor, or any MCP client at the server and your agent can publish to X (Twitter) directly.
{
"mcpServers": {
"postmcpai": {
"command": "npx",
"args": ["-y", "@postmcpai/server"],
"env": {
"POSTMCPAI_API_KEY": "pmcp_sec_YOUR_SECRET_KEY",
"POSTMCPAI_API_URL": "https://api.postmcpai.com"
}
}
}
}Prompt the agent directly
With the server connected, natural language is enough — the agent picks the tool and fills the arguments:
“Draft a X (Twitter) post about today’s release and schedule it for 9:30am tomorrow.”
X (Twitter) API questions
How do I post a tweet using the X API?
POST to https://api.postmcpai.com/api/tools/create_post with your PostMCP API key and a body of {"content": "...", "platforms": ["twitter"], "publishImmediately": true}. PostMCP calls Twitter API v2 /2/tweets on your behalf using the connected account's tokens.
Does the Twitter API support scheduled tweets?
Twitter API v2 publishes on receipt and has no scheduling endpoint for standard access. PostMCP stores the post with scheduleDate and scheduleTime and broadcasts it at that slot, so scheduling works on any access tier.
How do I upload an image with the X API?
Raw v2 requires initialize, append and finalize against the chunked media endpoints, then referencing the media ID in the tweet. With PostMCP you set mediaUrl to a public image or MP4 URL and the whole sequence runs server-side.
What happens if the media upload fails?
The engine catches the failure, clears the media ID and sends the tweet with the media URL appended to the text. You get a published post plus an error trail instead of a silent drop.
What is the tweet character limit through the API?
280 characters on standard accounts, up to 25,000 on premium tiers. PostMCP forwards content unchanged, so the limit is enforced by X.
Do I need my own X developer account?
No. PostMCP holds the app registration and requests users.read, tweet.read, tweet.write, media.write and offline.access during the connect flow.
Other social media APIs
One authenticated POST publishes to a LinkedIn profile or company page. PostMCP owns the OAuth dance, the image upload handshake and the versioned LinkedIn REST calls underneath.
Read the referencePublish text and photo posts to every Facebook Page you manage from one endpoint. PostMCP resolves page access tokens and calls Graph API v26.0 for you.
Read the referenceInstagram publishing is a two-phase asynchronous flow. PostMCP creates the media container, polls it to FINISHED and publishes it — you send a caption and a media URL.
Read the referenceThreads processes every post asynchronously, even plain text. PostMCP creates the container, polls it to FINISHED and publishes — one call from your side.
Read the referenceBluesky is not OAuth — it is a session against an AT Protocol server. PostMCP refreshes that session, uploads image blobs and writes the feed record for you.
Read the referenceYouTube is the one network here that will not take a URL. It wants the video bytes over a resumable session — PostMCP fetches, uploads and publishes them for you.
Read the referenceStart posting to X (Twitter) today
Connect the account, take an API key and send your first request in under five minutes — from a shell, your backend, or an AI agent.
