xurl
Interact with X/Twitter via xurl, the official X API CLI. Use for posting, replying, quoting, searching, timelines, mentions, likes, reposts, bookmarks, follows, DMs, media upload, and raw v2 endpoint
Interact with X/Twitter via xurl, the official X API CLI. Use for posting, replying, quoting, searching, timelines, mentions, likes, reposts, bookmarks, follows, DMs, media upload, and raw v2 endpoint
Real data. Real impact.
Emerging
Developers
Per week
Excellent
Skills give you superpowers. Install in 30 seconds.
xurl is the X developer platform's official CLI for the X API. It supports shortcut commands for common actions AND raw curl-style access to any v2 endpoint. All commands return JSON to stdout.
Use this skill for:
This skill replaces the older
xitter skill (which wrapped a third-party Python CLI). xurl is maintained by the X developer platform team, supports OAuth 2.0 PKCE with auto-refresh, and covers a substantially larger API surface.
Critical rules when operating inside an agent/LLM session:
~/.xurl to LLM context.~/.xurl with secrets manually on their own machine.--verbose / -v in agent sessions — it can expose auth headers/tokens.xurl auth status.Forbidden flags in agent commands (they accept inline secrets):
--bearer-token, --consumer-key, --consumer-secret, --access-token, --token-secret, --client-id, --client-secret
App credential registration and credential rotation must be done by the user manually, outside the agent session. After credentials are registered, the user authenticates with
xurl auth oauth2 — also outside the agent session. Tokens persist to ~/.xurl in YAML. Each app has isolated tokens. OAuth 2.0 tokens auto-refresh.
Pick ONE method. On Linux, the shell script or
go install are the easiest.
# Shell script (installs to ~/.local/bin, no sudo, works on Linux + macOS) curl -fsSL https://raw.githubusercontent.com/xdevplatform/xurl/main/install.sh | bash # Homebrew (macOS) brew install --cask xdevplatform/tap/xurl # npm npm install -g @xdevplatform/xurl # Go go install github.com/xdevplatform/xurl@latest
Verify:
xurl --help xurl auth status
If
xurl is installed but auth status shows no apps or tokens, the user needs to complete auth manually — see the next section.
These steps must be performed by the user directly, NOT by the agent, because they involve pasting secrets. Direct the user to this block; do not execute it for them.
Create or open an app at https://developer.x.com/en/portal/dashboard
Set the redirect URI to
http://localhost:8080/callback
Copy the app's Client ID and Client Secret
Register the app locally (user runs this):
xurl auth apps add my-app --client-id YOUR_CLIENT_ID --client-secret YOUR_CLIENT_SECRET
Authenticate (specify
--app to bind the token to your app):
xurl auth oauth2 --app my-app
(This opens a browser for the OAuth 2.0 PKCE flow.)
If X returns a
UsernameNotFound error or 403 on the post-OAuth /2/users/me lookup, pass your handle explicitly (xurl v1.1.0+):
xurl auth oauth2 --app my-app YOUR_USERNAME
This binds the token to your handle and skips the broken
/2/users/me call.
Set the app as default so all commands use it:
xurl auth default my-app
Verify:
xurl auth status xurl whoami
After this, the agent can use any command below without further setup. OAuth 2.0 tokens auto-refresh.
Common pitfall: If you omit
from--app my-app, the OAuth token is saved to the built-inxurl auth oauth2app profile — which has no client-id or client-secret. Commands will fail with auth errors even though the OAuth flow appeared to succeed. If you hit this, re-rundefaultandxurl auth oauth2 --app my-app.xurl auth default my-app
| Action | Command |
|---|---|
| Post | |
| Reply | |
| Quote | |
| Delete a post | |
| Read a post | |
| Search posts | |
| Who am I | |
| Look up a user | |
| Home timeline | |
| Mentions | |
| Like / Unlike | / |
| Repost / Undo | / |
| Bookmark / Remove | / |
| List bookmarks / likes | / |
| Follow / Unfollow | / |
| Following / Followers | / |
| Block / Unblock | / |
| Mute / Unmute | / |
| Send DM | |
| List DMs | |
| Upload media | |
| Media status | |
| List apps | |
| Remove app | |
| Set default app | |
| Per-request app | |
| Auth status | |
Notes:
POST_ID accepts full URLs too (e.g. https://x.com/user/status/1234567890) — xurl extracts the ID.@.xurl post "Hello world!" xurl post "Check this out" --media-id MEDIA_ID xurl post "Thread pics" --media-id 111 --media-id 222 xurl reply 1234567890 "Great point!" xurl reply https://x.com/user/status/1234567890 "Agreed!" xurl reply 1234567890 "Look at this" --media-id MEDIA_ID xurl quote 1234567890 "Adding my thoughts" xurl delete 1234567890
xurl read 1234567890 xurl read https://x.com/user/status/1234567890 xurl search "golang" xurl search "from:elonmusk" -n 20 xurl search "#buildinpublic lang:en" -n 15
xurl whoami xurl user elonmusk xurl user @XDevelopers xurl timeline -n 25 xurl mentions -n 20
xurl like 1234567890 xurl unlike 1234567890 xurl repost 1234567890 xurl unrepost 1234567890 xurl bookmark 1234567890 xurl unbookmark 1234567890 xurl bookmarks -n 20 xurl likes -n 20
xurl follow @XDevelopers xurl unfollow @XDevelopers xurl following -n 50 xurl followers -n 50 # Another user's graph xurl following --of elonmusk -n 20 xurl followers --of elonmusk -n 20 xurl block @spammer xurl unblock @spammer xurl mute @annoying xurl unmute @annoying
xurl dm @someuser "Hey, saw your post!" xurl dms -n 25
# Auto-detect type xurl media upload photo.jpg xurl media upload video.mp4 # Explicit type/category xurl media upload --media-type image/jpeg --category tweet_image photo.jpg # Videos need server-side processing — check status (or poll) xurl media status MEDIA_ID xurl media status --wait MEDIA_ID # Full workflow xurl media upload meme.png # returns media id xurl post "lol" --media-id MEDIA_ID
The shortcuts cover common operations. For anything else, use raw curl-style mode against any X API v2 endpoint:
# GET xurl /2/users/me # POST with JSON body xurl -X POST /2/tweets -d '{"text":"Hello world!"}' # DELETE / PUT / PATCH xurl -X DELETE /2/tweets/1234567890 # Custom headers xurl -H "Content-Type: application/json" /2/some/endpoint # Force streaming xurl -s /2/tweets/search/stream # Full URLs also work xurl https://api.x.com/2/users/me
| Flag | Short | Description |
|---|---|---|
| Use a specific registered app (overrides default) | |
| Force auth type: , , or | |
| | Which OAuth2 account to use (if multiple exist) |
| | Forbidden in agent sessions — leaks auth headers |
| | Add trace header |
Streaming endpoints are auto-detected. Known ones include:
/2/tweets/search/stream/2/tweets/sample/stream/2/tweets/sample10/streamForce streaming on any endpoint with
-s.
All commands return JSON to stdout. Structure mirrors X API v2:
{ "data": { "id": "1234567890", "text": "Hello world!" } }
Errors are also JSON:
{ "errors": [ { "message": "Not authorized", "code": 403 } ] }
xurl media upload photo.jpg xurl post "Check out this photo!" --media-id MEDIA_ID
xurl read https://x.com/user/status/1234567890 xurl reply 1234567890 "Here are my thoughts..."
xurl search "topic of interest" -n 10 xurl like POST_ID_FROM_RESULTS xurl reply POST_ID_FROM_RESULTS "Great point!"
xurl whoami xurl mentions -n 20 xurl timeline -n 20
xurl auth default prod alice # prod app, alice user xurl --app staging /2/users/me # one-off against staging
xurl auth oauth2 outside the agent session./2/users/me. An auth failure there surfaces as an auth error.xurl --help and xurl auth status.auth status output. The default app is marked with ▸. If the default app shows oauth2: (none) but another app has a valid oauth2 user, tell the user to run xurl auth default <that-app> to fix it. This is the most common setup mistake — the user added an app with a custom name but never set it as default, so xurl keeps trying the empty default profile.xurl whoami, xurl user @handle, xurl search ... -n 3) to confirm reachability.~/.xurl contents back into the conversation.| Symptom | Cause | Fix |
|---|---|---|
| Auth errors after successful OAuth flow | Token saved to app (no client-id/secret) instead of your named app | then |
during OAuth | App type set to "Native App" in X dashboard | Change to "Web app, automated app or bot" in User Authentication Settings |
or 403 on right after OAuth | X not returning username reliably from | Re-run (xurl v1.1.0+) to pass the handle explicitly |
| 401 on every request | Token expired or wrong default app | Check — verify points to an app with oauth2 tokens |
/ | X platform enrollment issue | Dashboard → Apps → Manage → Move to "Pay-per-use" package → Production environment |
| $0 balance on X API | Buy credits (min $5) in Developer Console → Billing |
on image upload | Default category is | Add |
| Two "Client Secret" values in X dashboard | UI bug — first is actually Client ID | Confirm on the "Keys and tokens" page; ID ends in |
xurl auth oauth2.xurl auth default or --app.-u / --username, or set a default with xurl auth default APP USER.~/.xurl is YAML. Never read or send this file to LLM context.MIT
mkdir -p ~/.hermes/skills/social-media/xurl && curl -o ~/.hermes/skills/social-media/xurl/SKILL.md https://raw.githubusercontent.com/NousResearch/hermes-agent/main/skills/social-media/xurl/SKILL.md1,500+ AI skills, agents & workflows. Install in 30 seconds. Part of the Torly.ai family.
© 2026 Torly.ai. All rights reserved.