Send POST https:// with a JSON body like {"text": "Hello"} and a user access token for the
account that posts. X answers 201 Created with the new post's id. Each post costs $0.015 from your prepaid X
credits, or $0.200 if it contains a link, and one account can make 100 posting requests per 15 minutes.
Checked on November 3, 2026 against X's create-post reference, its OpenAPI spec (version 2.173), its rate-limit table and its pricing page. X says its prices can change; your Developer Console shows the rates you're charged.
What you need first
- A developer app in X's Developer Console with OAuth 2.0 set up and a callback URL.
- Credits. X's API is pay per use, with no subscription and no free tier. You buy credits in the console, and each call is paid from them. X adds $20 of credits when you save your first card and make your first purchase.
- A user access token for the account that posts, with the scopes
tweet,.read tweetand.write users(add.read offlineto get a refresh token). OAuth 1.0a user tokens work too. An app-only bearer token can't post. X API OAuth 2.0 with PKCE walks through getting one..access
The examples read the token from USER_ACCESS_TOKEN. Keep it out of your code and your logs.
Post it
curl
curl -X POST https://api.x.com/2/tweets \
-H "Authorization: Bearer $USER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"text": "Hello from the X API"}'
X answers 201 Created:
{
"data": {
"id": "1985412345678901234",
"text": "Hello from the X API",
"edit_history_post_ids": ["1985412345678901234"]
}
}
Python
import os
import requests
resp = requests.post(
"https://api.x.com/2/tweets",
headers={"Authorization": f"Bearer {os.environ['USER_ACCESS_TOKEN']}"},
json={"text": "Hello from the X API"},
timeout=30,
)
resp.raise_for_status()
print(resp.json()["data"]["id"])
Node.js (18 or later)
const resp = await fetch('https://api.x.com/2/tweets', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.USER_ACCESS_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ text: 'Hello from the X API' }),
});
if (resp.status !== 201) throw new Error(`X answered ${resp.status}: ${await resp.text()}`);
const { data } = await resp.json();
console.log(data.id);
Save the id. You need it to reply to the post, to build a thread or to delete it (DELETE /).
Replies, threads, photos and polls
Everything goes through the same POST /. The body rejects fields it doesn't know, so a typo is a 400, not a
silently ignored option.
| To post | Add to the body |
|---|---|
| A reply, or the next part of a thread | "reply": {"in_reply_to_tweet_id": "<id>"} |
| Photos, a GIF or a video | "media": {"media_ids": ["<id>"]}, after uploading the file to / (up to 4 photos, 1 GIF or 1 video) |
| A poll | "poll": {"options": ["Yes", "No"], "duration_minutes": 1440}: 2 to 4 options of up to 25 characters, open 5 to 10,080 minutes |
| Limit who can reply | "reply_settings": "following" (or mentionedUsers, subscribers, verified) |
| A post in a Community | "community_id": "<id>" |
Quote posts (quote_tweet_id) need X's Enterprise plan; they aren't available on pay per use. A thread has no call of
its own: post each part as a reply to the part before.
Threads, polls and media with the X API v2 has the full upload and thread code.
Limits and cost
| Limit or price | |
|---|---|
POST /, per user |
100 requests per 15 minutes |
POST /, per app |
10,000 requests per 24 hours |
DELETE /, per user |
50 requests per 15 minutes |
| A post without a link | $0.015 |
| A post with a link | $0.200 |
| Text | 280 characters for most accounts; longer with X Premium (how X counts them) |
Every answer carries x-rate-limit-limit, x-rate-limit-remaining and x-rate-limit-reset (a Unix time in seconds).
Past a limit, X answers 429. If you set a spending limit in the console, X blocks requests once you reach it until the
next billing cycle. X API rate limits for posting covers backing off without posting
twice, and X API pricing works out monthly costs.
When it fails
- 401: the token expired or was revoked. OAuth 2.0 user tokens normally last two hours: refresh it, or sign in again.
- 403 "duplicate content": the account already posted this exact text. Change the text.
- 403 on a reply: pay-per-use apps can reply only when the original post mentions the replying account or quotes one of its posts.
- 429: wait until
x-rate-limit-reset, then check whether the post went out before you send it again.
X API posting errors, explained has each error's exact text and fix.
Do it yourself, or let an agent draft it through Flaghand
Call X's API yourself when you want a bot or script that posts on its own: a status feed, alerts, your own account. You pay X per post, you hold the tokens, and nothing waits for a person.
If an AI agent writes the posts, the risk changes: with the token above it can post anything, at once. Flaghand is a
publishing desk built for that case. Your agent connects to Flaghand's MCP server (https://) or its API, drafts
the post or thread, uploads media and checks it, and asks for approval. You approve the exact post with your passkey,
and Flaghand posts it at its time, then reads it back from X to confirm it went out as approved. No token Flaghand
issues can approve, schedule or post, so it isn't for unattended bots.
Flaghand pays X's API itself. Its plans include credits: a plain X post with its live check uses up to 4, a post with a link more (credits). Sign-up takes no card (current terms). Get started with Flaghand.
Questions
Can I post a tweet with the X API for free? No. X's API is pay per use with no free tier. A post costs $0.015, or $0.200 if it contains a link. X adds $20 of credits with your first purchase.
How many tweets can I post per day with the X API? X limits POST / to 100 requests per 15 minutes for
each user and 10,000 per 24 hours for each app. Your credits and any spending limit you set also cap it.
Can I post with an app-only bearer token? No. Posting needs a user token, from OAuth 2.0 with tweet or from
OAuth 1.0a user context, for the account that posts.
What is the endpoint to post a tweet in X API v2? POST https://, with the text in a JSON body
and a user token. The same call posts replies, polls and posts with media.
Can an AI agent post tweets for me? With your X token it can post anything, immediately. Through Flaghand it drafts and asks for approval, and only your passkey approval of the exact post makes it go out.
Sources
Checked November 3, 2026:
- X: Create or Edit Post and the OpenAPI spec, version 2.173
- X: Rate limits
- X: Pricing