Skip to main content
A bot is a programmatic X account created by and belonging to your project. It is a real account with a user id, an @handle, and a display name, but it has no password and no login. The only way to act as a bot is its bearer token. Bot accounts carry an “Automated by @owner” label pointing to the X account that owns the client app. Endpoint details are under API reference → Bots.

Authentication

All six bot endpoints use OAuth 2.0 app-only auth: authenticate with your app’s bearer token. No user context and no OAuth scopes are required to call them. Every operation is scoped to the calling app’s project. You can only list and manage bots that belong to that project.

Bot tokens

  • POST /2/bots and POST /2/bots/:id/token mint the bot’s bearer token (format xcbot_…). The token is returned once and can never be retrieved again. Store it on receipt.
  • A bot has one active token: any mint revokes the previously outstanding token(s).
  • Token scopes default to dm.read, dm.write, tweet.read, users.read, media.write. A request may narrow to a subset of that set; requesting anything outside it returns a 400. The response includes expires_at (epoch milliseconds) and scopes.
  • DELETE /2/bots/:id/token revokes without minting a replacement, as a standard OAuth2-style kill switch. It responds with {"data":{"revoked":true}}. The account survives; rotate later to re-activate.

Lifecycle

Create is idempotent on handle. Repeating a POST /2/bots whose handle already names one of the project’s bots returns that same bot with a freshly minted token; the previous one is revoked. This makes retries safe when a response was lost, since the replaced token was never seen. A converge re-applies display_name if provided but never changes DM permission.

Limits

  • Each project has a bot allowance set by its plan. meta.max_bots in the list response reports it; the default is 1. Creating past the cap returns an error.
  • Rate limits are per-app, in 15-minute windows.

Example