X (Twitter) channel guide
X Activity access required. Confirm webhook access, OAuth scopes, and current usage costs in your X developer account before connecting. See X Activity documentation.
Prerequisites
- An X developer account at developer.x.com
- An X app with X Activity API webhook access; confirm current access and usage costs in your developer account.
- OAuth 2.0 User Authentication configured with
dm.read,dm.write,tweet.read,tweet.write,users.readscopes - Consumer secret from your app's "Keys and tokens" page
- Either a user access token (OAuth 2.0 Bearer), OR a client ID + refresh token for managed refresh —
client_secretis optional (required only for confidential OAuth 2.0 apps); includeoffline.accessscope when generating the refresh token
1. Create an X app
- Go to developer.x.com/en/portal/dashboard and create a new project and app.
- Under "User authentication settings", enable OAuth 2.0 and set the callback URL (the HTTPS redirect URL used by your OAuth authorization flow; this is separate from the webhook URL).
- From "Keys and tokens", copy the consumer secret (also called "API secret key").
- Generate a user access token (OAuth 2.0 Bearer) with the scopes above, OR configure OAuth 2.0 PKCE and note the client ID and a refresh token with
offline.accessscope (the client secret is optional — only required for confidential apps).
2. Register a channel app
curl -s -X POST "https://api.agentsky.dev/v1/channels/apps" \
-H "Authorization: Bearer $AST_TOKEN" -H 'content-type: application/json' \
-d '{
"platform": "x",
"label": "My X bot",
"credentials": {
"consumer_secret": "<consumer-secret>",
"user_access_token": "<user-access-token>"
}
}'
# -> {
# "id": "app_...",
# "setup": {
# "webhook_url": "https://.../webhooks/x/app_...",
# "console_url": "https://console.x.com",
# "required_subscriptions": "post.mention.create,dm.received,dm.sent"
# }
# }The API validates your token against GET /2/users/me and stores the verified user ID and username. If you supply client_id + refresh_token instead of user_access_token, the adapter manages token refresh automatically.
If X rejects the credentials, token refresh becomes uncertain, or the provider is temporarily unavailable after the app is saved, the API returns HTTP 202 with status: PENDING_VERIFICATION and the saved app ID. Messages stay disabled. Open the app and choose Retry verification, or send PATCH /channels/apps/{id} with {"retry_registration":true}. This retries the saved credentials; do not create another app to reuse an already-consumed refresh token. If the refresh result is uncertain, replace the credentials with fresh OAuth credentials. Unexpected internal failures return an error instead of being represented as recoverable verification state.
3. Register the webhook
Register the URL returned in setup.webhook_url using X’s webhook setup guide. This channel API returns the setup URL; it does not create the X webhook or subscription for you:
- Open your X developer account and follow the current X Activity webhook setup.
- Register the webhook URL under your app.
- X sends a CRC GET challenge to the URL — the service responds automatically using your consumer secret.
- Create a subscription for your bot account: subscribe to
post.mention.create,dm.received, anddm.sent.
Alternatively use console.x.com if it is available in your account.
4. Connect a session
# Connect the channel app to an agent session
curl -s -X POST "https://api.agentsky.dev/v1/channels/connections" \
-H "Authorization: Bearer $AST_TOKEN" -H 'content-type: application/json' \
-d '{"platform": "x", "app": "app_...", "destination": {"session": "sess-..."}}'The response is PENDING, with connect.url, connect.code and an expiry. Open the hosted URL, then use its X button to send the exact code to the bot and connect that DM. The page also shows the exact @YourBot LINK:... post for connecting the account’s public-mention surface. Avoid surrounding prose. A valid claim changes the connection to CONNECTED and confirms the selected agent. The page polls that status and, when the request supplied callback_url, redirects there with the connection ID, status, and original metadata. The code expires after 15 minutes.
DM connections are separate from the public-mention connection. Replies use the app’s credentials and target the corresponding DM or post conversation. A later agent switch sends a notice to the place where the connection was linked.
Thread model
- Public mentions: one default agent handles the app's public-mention surface; each root post conversation retains its own reply thread. Long replies are split into consecutive posts within X's weighted limit, preserving URLs and graphemes.
- Direct messages: each correspondent has a separate connection. The adapter supports legacy
dm.received/dm.sentevents; encrypted XChatchat.*events are a different protocol and are not supported by this adapter. - Uncertain or partial sends: the API reports accepted post IDs when available. Check the conversation before retrying, to avoid publishing duplicates.
Troubleshooting
- CRC challenge fails — confirm the consumer secret is the exact string from "Keys and tokens → API secret key"; do not confuse it with the client secret.
- Events not arriving — check the webhook subscription status in the X Developer Portal; the subscription must be active and the URL must match exactly.
- Token expired — user access tokens expire in approximately 2 hours. Switch to
client_id+refresh_tokenfor automatic refresh, or rotate theuser_access_tokencredential viaPATCH /v1/channels/apps/{id}. - Access and rate limits — check the current X Activity documentation and your developer account. This integration does not purchase access or credits.
AgentSky