Twitter / X Integration
Connect your agent to an X (formerly Twitter) account to publish posts, read timelines, and reply to mentions.
Overview
The Twitter / X integration uses X API v2 with OAuth 2.0 Authorization Code Flow + PKCE.
Skills that use this integration:
int-twitterx-post— Publish posts, threads, and replies; read mentions
Agents that typically enable this integration:
- Social Manager
- Any custom agent that needs X posting
Availability
| Mode | Status | Notes |
|---|---|---|
"wiro" |
Available | One-click connect using Wiro's shared X app. |
"own" |
Available | Use your own X Developer app for custom branding. |
Prerequisites
- A Wiro API key — Authentication.
- A deployed agent — Agent Overview.
- (Own mode) An X Developer account — developer.x.com.
- An HTTPS callback URL for your backend.
Wiro Mode (Simplest)
Skip all the own-mode setup. Just call Connect without authmethod:
curl -X POST "https://api.wiro.ai/v1/UserAgentOAuth/OAuthConnect" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"useragentguid": "your-useragent-guid",
"credentialkey": "twitter",
"redirecturl": "https://your-app.com/settings/integrations"
}'
User consents on the Wiro-branded consent screen. On return parse x_connected=true&x_username=<handle>. Jump to Step 8: Verify below.
Complete Integration Walkthrough — Own Mode
Step 1: Create an X Developer App
- developer.x.com/portal → sign in.
- Apply for a developer account if needed (free tier works for testing).
- Create a Project → create an App inside it.
- Name your app — this shows on the consent screen.
Step 2: Enable OAuth 2.0 with PKCE
- User authentication settings → Set up.
- Pick OAuth 2.0, type: Web App, Automated App or Bot.
- Enable any extras you need (e.g. email).
-
Callback URI / Redirect URL:
https://api.wiro.ai/v1/UserAgentOAuth/XCallback - Set your Website URL (public product URL).
- Save.
Step 3: Note the required scopes
Wiro requests these exact scopes:
tweet.read tweet.write users.read offline.access
| Scope | Why |
|---|---|
tweet.read |
Read timeline, mentions, replies. |
tweet.write |
Publish posts and replies. |
users.read |
Get connected user's handle and display name. |
offline.access |
Issues a refresh token alongside the access token. |
Step 4: Copy Client ID and Client Secret
After enabling OAuth 2.0, X shows Client ID and Client Secret — save the secret immediately. You cannot retrieve it later, only regenerate.
Step 5: Save credentials to Wiro
curl -X POST "https://api.wiro.ai/v1/UserAgent/CredentialUpsert" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"useragentguid": "your-useragent-guid",
"fields": [
{ "credentialkey": "twitter", "fieldname": "clientid", "fieldvalue": "YOUR_X_CLIENT_ID" },
{ "credentialkey": "twitter", "fieldname": "clientsecret", "fieldvalue": "YOUR_X_CLIENT_SECRET" },
{ "credentialkey": "twitter", "fieldname": "authmethod", "fieldvalue": "own" }
]
}'
Step 6: Initiate OAuth
curl -X POST "https://api.wiro.ai/v1/UserAgentOAuth/OAuthConnect" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"useragentguid": "your-useragent-guid",
"credentialkey": "twitter",
"redirecturl": "https://your-app.com/settings/integrations",
"authmethod": "own"
}'
Response:
{
"result": true,
"authorizeUrl": "https://x.com/i/oauth2/authorize?response_type=code&client_id=...&redirect_uri=...&scope=tweet.read%20tweet.write%20users.read%20offline.access&state=...&code_challenge=...&code_challenge_method=S256",
"errors": []
}
PKCE: Twitter/X is the only Wiro integration that uses PKCE (Proof Key for Code Exchange, S256). Wiro generates the code_verifier / code_challenge automatically and stores them in the OAuth state cache. You don't need to handle PKCE yourself.
Step 7: Handle the callback
User returns with:
https://your-app.com/settings/integrations?x_connected=true&x_username=jane_doe
const params = new URLSearchParams(window.location.search);
if (params.get("x_connected") === "true") {
const handle = params.get("x_username");
showSuccess(`Connected @${handle}`);
} else if (params.get("x_error")) {
handleError(params.get("x_error"));
}
Step 8: Verify
curl -X POST "https://api.wiro.ai/v1/UserAgentOAuth/OAuthStatus" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"useragentguid": "your-useragent-guid",
"credentialkey": "twitter"
}'
Response:
{
"result": true,
"connected": true,
"accounts": [
{ "id": "jane_doe", "name": "jane_doe" }
],
"connectedat": "2026-04-17T12:00:00.000Z",
"tokenexpiresat": "2026-04-17T14:00:00.000Z",
"errors": []
}
- Access token lifetime: ~2 hours (short!). Wiro auto-refreshes.
- Refresh token lifetime: ~180 days from connection (hardcoded by Wiro, since X doesn't report one).
accounts[0].id=@-less X handle (Twitter has no picker — single-account flow).
Step 9: Start the agent
curl -X POST "https://api.wiro.ai/v1/UserAgent/Start" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{ "guid": "your-useragent-guid" }'
API Reference
POST /UserAgentOAuth/OAuthConnect
| Parameter | Type | Required | Description |
|---|---|---|---|
useragentguid |
string | Yes | Agent instance GUID. |
credentialkey |
string | Yes | "twitter". |
redirecturl |
string | Yes | HTTPS URL. |
authmethod |
string | No | "wiro" (default) or "own". |
GET /UserAgentOAuth/XCallback
Query params: x_connected=true&x_username=<handle> or x_error=<code>. The callback path is per-provider — Twitter's stays XCallback.
POST /UserAgentOAuth/OAuthStatus
Body: { useragentguid, credentialkey: "twitter" }. Response: connected, accounts: [{id, name}] (1-element with the connected handle), connectedat, tokenexpiresat (~2h).
POST /UserAgentOAuth/OAuthDisconnect
Body: { useragentguid, credentialkey: "twitter" }. Calls X's revoke endpoint (POST https://api.x.com/2/oauth2/revoke) with Basic auth, then clears credentials. X is one of the few providers where Wiro actively revokes.
Token lifecycle
Wiro maintains the X connection automatically while the agent is running. If the user revokes the app or OAuthStatus reports connected: false, reconnect through the OAuth flow.
Using the Skill
Once the X account is connected, the agent's existing scheduled tasks use the int-twitterx-post platform skill to publish. To adjust the cron of the built-in cs-cron-social-content-scanner task (Social Manager), call POST /UserAgent/CustomSkillUpsert with enabled and interval only — cron skill bodies are template-controlled and value is silently ignored for bundled crons:
curl -X POST "https://api.wiro.ai/v1/UserAgent/CustomSkillUpsert" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"useragentguid": "your-useragent-guid",
"skillkey": "cs-cron-social-content-scanner",
"enabled": true,
"interval": "0 */4 * * *"
}'
To change what the scheduled task posts (topics, tone, hashtag rules), edit the paired preference skill content-tone instead — see Agent Skills → Updating Preference Skills.
Troubleshooting
| Error code | Meaning | What to do |
|---|---|---|
missing_params |
Callback reached without state or code. |
Start a new flow from Step 6. |
authorization_denied |
User cancelled, or OAuth 2.0 not enabled in app settings. | Verify OAuth 2.0 setup (Step 2); retry. |
session_expired |
15-min state cache expired (includes PKCE verifier). | Call OAuthConnect again. |
token_exchange_failed |
Wrong Client Secret, redirect URI mismatch, or lost PKCE verifier. | Re-copy Client Secret; verify URL; start over. |
useragent_not_found |
Invalid guid. | Use POST /UserAgent/MyAgents. |
Twitter / X credentials not configured |
Returned in OAuthConnect's errors[] when authmethod: "own" but clientid / clientsecret are missing. |
UserAgent/CredentialUpsert with clientid + clientsecret. |
internal_error |
Server error. | Retry; contact support. |
Posts fail with 429 Too Many Requests
Free-tier X Developer apps have strict per-app rate limits. For production, move to Basic ($100/mo) or higher. Limits are per app, not per user — high-volume multi-tenant partners need a higher tier.
Token expires every 2 hours
Access token lifetime is unusually short, so Wiro maintains it automatically while the agent is running. If the user revokes the app in X settings or X invalidates the authorization, the next skill call can fail with a 401 and reconnection is required.
Multi-Tenant Architecture
- One X Developer app per product in own mode. Wiro-mode partners share Wiro's app.
- One Wiro agent instance per customer.
- Your app display name appears on every customer's consent screen (own mode).
- Rate limits are per app. Plan your X Developer tier around aggregate volume.