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 path is the CLI bundled OAuth client (simplepost account add x) or the Scheduler app, both of which take care of token generation and rotation for you. Use the steps below only when you want to drive the SDK directly with your own X app.
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"],
});