xurl
X/Twitter via xurl CLI: post, search, DM, media, v2 API.
X/Twitter via xurl CLI: post, search, DM, media, v2 API.
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.