X
SimplePost posts to X with OAuth 2.0 user credentials. X API access is paid by X, so make sure your developer account and app have enough API access before testing.
Content support
| Capability | Support |
|---|---|
| Text | 280 characters by default. Up to 25,000 with X Premium long-post access. |
| Media | Images and videos. |
| Media limit | Up to 4 images, or 1 video. Mixed media is not allowed. |
| Empty posts | Not allowed; provide text or media. |
| Threads | Pass replyToId to chain a reply onto an existing post. |
Set up credentials
The fastest managed path is the Scheduler app. For a local CLI account or direct SDK use, create your own X app using the steps below, export SIMPLE_POST_X_CLIENT_ID, and run simplepost account add x to complete OAuth and persist rotated tokens locally.
1. Create a developer account
- Open the X Developer Console.
- Sign in with the X account that should own the app.
- Start a new project if the console asks for one.
- Choose the use case closest to automation or bot posting.
2. Create an app
- Open Apps in the left sidebar.
- Create a new app.
- Use a development environment for personal testing.
- Open the app settings after it is created.
3. Configure OAuth
- Set App permissions to Read and write.
- Set Type of App to Web App, Automated App, or Bot.
- Add a Callback URI and Website URL. If you are only posting for yourself, placeholder HTTPS URLs are enough for manual token generation.
- Save the Client ID and Client Secret.
4. Generate user tokens
In the app's OAuth 2.0 keys area, generate an access token and refresh token for your own account. Include tweet.write. Save both tokens.
The access token is short-lived. The refresh token lasts longer, but X rotates it every time it is used — see token rotation.
Environment variables
X_CLIENT_ID=
X_CLIENT_SECRET=
X_ACCESS_TOKEN=
X_EXPIRES_AT=
X_REFRESH_TOKEN=
The SDK activates X env credentials only when X_CLIENT_ID is set together with at least one of X_ACCESS_TOKEN or X_REFRESH_TOKEN. X_CLIENT_SECRET is required only for confidential OAuth clients.
SDK options
Reply to a post:
await post({
content: { text: "This is a reply" },
platforms: ["x"],
options: {
x: { replyToId: "1234567890" },
},
});
Programmatic user credentials:
const result = await post({
content: { text: "Hello from X" },
platforms: ["x"],
options: {
x: {
credentials: {
clientId: "X_APP_CLIENT_ID",
clientSecret: "X_APP_CLIENT_SECRET",
accessToken: "USER_ACCESS_TOKEN",
expiresAt: 1234567890,
refreshToken: "USER_REFRESH_TOKEN",
},
},
},
});
const refreshed = result.get("x")?.extraData?.refreshedCredentials;
if (refreshed) {
await saveUserTokens(refreshed);
}
Refresh token rotation
X invalidates the old refresh token whenever a new one is issued. The SDK returns refreshed credentials in result.extraData.refreshedCredentials, but it does not write them to your database, .env, CLI store, or accounts.json. Persist the new token yourself. The CLI and Scheduler handle this for you when posting through their stored X accounts.
REST server account
Add this entry under accounts in the self-hosted REST server's accounts.json:
{
"id": "x-main",
"platform": "x",
"label": "Main brand X account",
"username": "yourbrand",
"platformAccountId": "1234567890",
"credentials": {
"clientId": "...",
"clientSecret": "...",
"refreshToken": "..."
}
}
Examples
await post({
content: {
text: "Posting images",
media: [
{ type: "image", path: "./image_1.jpg" },
{ type: "image", path: "./image_2.jpg" },
],
},
platforms: ["x"],
});