X API
Updated
Read X (Twitter) data and act from X accounts you connect, through one REST API or the hosted MCP server. You don't need an X developer account.
Overview
Base URL: https://api.chatterapi.com/v1. X endpoints sit under /v1/x, and every call needs your key in the Authorization: Bearer header. The MCP server at https://api.chatterapi.com/mcp exposes the same endpoints as tools.
- Reads cost 3 credits per call or per page of about 20 rows, and need nothing but your key.
- Actions (DMs, follows, likes, retweets and tweets) run from X accounts you connect on the Accounts page. They are never sent from shared accounts.
- Test keys (
ca_test_...) return recorded samples for reads. For actions they do a dry run, so nothing is sent and nothing is charged.
curl "https://api.chatterapi.com/v1/x/users/levelsio" \
-H "Authorization: Bearer $CHATTERAPI_KEY"Endpoints at a glance
Reads
| Endpoint | Method and path | Credits |
|---|---|---|
| X User Lookup | GET /v1/x/users/{handle} | 3 credits |
| X User Search | GET /v1/x/users/search | 3 credits |
| X Follower Exporter | GET /v1/x/users/{handle}/followers | 3 credits per page (20 rows by default) |
| X Following Exporter | GET /v1/x/users/{handle}/following | 3 credits per page (20 rows by default) |
| Verified Follower Exporter | GET /v1/x/users/{handle}/verified-followers | 4 credits per 20 rows |
| X Timeline Scraper | GET /v1/x/users/{handle}/tweets | 3 credits |
| X Mentions Monitor | GET /v1/x/users/{handle}/mentions | 3 credits |
| X Tweet Search | GET /v1/x/tweets/search | 3 credits |
| X Tweet Lookup | GET /v1/x/tweets/{id} | 3 credits |
| Tweet Replies Exporter | GET /v1/x/tweets/{id}/replies | 3 credits |
| Retweeter Exporter | GET /v1/x/tweets/{id}/retweeters | 3 credits |
| X List Members | GET /v1/x/lists/{id}/members | 3 credits |
| X Lead Finder | GET /v1/x/leads | 3 credits |
Actions from connected accounts
| Endpoint | Method and path | Credits |
|---|---|---|
| Send a DM | POST /v1/x/dm/send | 10 credits |
| Follow / unfollow | POST /v1/x/actions/follow | 5 credits |
| Like / retweet | POST /v1/x/actions/like | 5 credits |
| Post a tweet | POST /v1/x/tweets | 5 credits |
You're charged for an action only when X accepts it.
How X inputs work
| Input | What to pass | Examples |
|---|---|---|
| Handle | The handle, with or without @ | levelsio, @levelsio |
| Tweet id | The numeric id or the full tweet URL | 1846312345678901234, https://x.com/user/status/1846312345678901234 |
| List id | The numeric id from the list URL | 1585430245762441216 |
Search query q | X search operators work | from:name, to:name, "exact phrase", crm OR hubspot, -giveaway, min_faves:10, filter:links |
sort | On tweet search | latest for monitoring, top for the most-engaged tweets |
Pages of about 20
Follower, following, timeline, search, reply, retweeter and list endpoints return about 20 rows a page. X decides the exact count. Pass page.nextCursor back as cursor until page.hasMore is false. Large accounts have many pages, so set a page budget in your code.
Can this account receive a DM?
User objects include canDm when X reports it, and null when it doesn't. Filter on it before you spend credits on x.dm_send.
Read endpoints
Every X read endpoint with its parameters and a request you can copy.
X User Lookup
GET /v1/x/users/{handle} · 3 credits · MCP tool x_user · returns XUser
Look up an X (Twitter) account by handle: name, bio, follower and following counts, tweet count, verification, whether it accepts DMs, location, website, avatar and join date. Costs 3 credits. Tip: canDm tells you if a cold DM can reach this account before you spend on x.dm_send.
| Parameter | Notes |
|---|---|
handle path, string, required | Handle with or without @, or a profile URL. 1-15 characters. |
curl "https://chatterapi.com/v1/x/users/levelsio" \
-H "Authorization: Bearer $CHATTERAPI_KEY"Full reference for X User Lookup: response example, every field and the errors it can return.
X User Search
GET /v1/x/users/search · 3 credits · MCP tool x_user_search · returns XUser[]
Find X accounts by keyword in their name or bio, for example 'founder saas' or 'growth marketer'. Returns profiles with follower counts and DM availability. Costs 3 credits per page of about 20. Tip: X search matches bios loosely; check bio text before treating a result as a fit.
| Parameter | Notes |
|---|---|
q query, string, required | Keywords to match in names and bios. |
limit query, integer | Max rows to return (1-100). One X page holds about 20 rows, so values above 20 still return one page. Range 1 to 100. Default 20. |
cursor query, string | Opaque cursor from the previous response's page.nextCursor. Length 1 to 2048. |
curl "https://chatterapi.com/v1/x/users/search?q=crm+founder" \
-H "Authorization: Bearer $CHATTERAPI_KEY"Full reference for X User Search: response example, every field and the errors it can return.
X Follower Exporter
GET /v1/x/users/{handle}/followers · 3 credits per page (20 rows by default) · MCP tool x_followers · returns XUser[]
Export the followers of any public X account, page by page, with each follower's bio, follower count and whether they accept DMs. Costs 3 credits per page of about 20 followers. Tip: filter by canDm and followers to build an outreach list; large accounts take many pages, so set a page budget.
| Parameter | Notes |
|---|---|
handle path, string, required | Handle with or without @, or a profile URL. 1-15 characters. |
limit query, integer | Max rows to return (1-100). One X page holds about 20 rows, so values above 20 still return one page. Range 1 to 100. Default 20. |
cursor query, string | Opaque cursor from the previous response's page.nextCursor. Length 1 to 2048. |
curl "https://chatterapi.com/v1/x/users/levelsio/followers" \
-H "Authorization: Bearer $CHATTERAPI_KEY"Full reference for X Follower Exporter: response example, every field and the errors it can return.
X Following Exporter
GET /v1/x/users/{handle}/following · 3 credits per page (20 rows by default) · MCP tool x_following · returns XUser[]
List the accounts an X user follows, page by page, with bios, follower counts and DM availability. Costs 3 credits per page of about 20. Tip: following lists reveal the tools and people an account pays attention to, useful for competitor research.
| Parameter | Notes |
|---|---|
handle path, string, required | Handle with or without @, or a profile URL. 1-15 characters. |
limit query, integer | Max rows to return (1-100). One X page holds about 20 rows, so values above 20 still return one page. Range 1 to 100. Default 20. |
cursor query, string | Opaque cursor from the previous response's page.nextCursor. Length 1 to 2048. |
curl "https://chatterapi.com/v1/x/users/levelsio/following" \
-H "Authorization: Bearer $CHATTERAPI_KEY"Full reference for X Following Exporter: response example, every field and the errors it can return.
Verified Follower Exporter
GET /v1/x/users/{handle}/verified-followers · 4 credits per 20 rows · MCP tool x_verified_followers · returns XUser[]
Export only the verified (blue check) followers of an X account, page by page. Same fields as x.followers. Costs 4 credits per page of about 20. Tip: verified followers skew toward active, paying users, so they make a higher-intent outreach list.
| Parameter | Notes |
|---|---|
handle path, string, required | Handle with or without @, or a profile URL. 1-15 characters. |
limit query, integer | Max rows to return (1-100). One X page holds about 20 rows, so values above 20 still return one page. Range 1 to 100. Default 20. |
cursor query, string | Opaque cursor from the previous response's page.nextCursor. Length 1 to 2048. |
curl "https://chatterapi.com/v1/x/users/levelsio/verified-followers" \
-H "Authorization: Bearer $CHATTERAPI_KEY"Full reference for Verified Follower Exporter: response example, every field and the errors it can return.
X Timeline Scraper
GET /v1/x/users/{handle}/tweets · 3 credits · MCP tool x_tweets · returns XTweet[]
Get an X account's recent tweets, newest first, with likes, retweets, replies, views and media. Costs 3 credits per page of about 20 tweets. Tip: set includeRetweets=false to see only what the account wrote itself.
| Parameter | Notes |
|---|---|
handle path, string, required | Handle with or without @, or a profile URL. 1-15 characters. |
includeRetweets query, boolean,string | When false, only tweets the account wrote itself. |
limit query, integer | Max rows to return (1-100). One X page holds about 20 rows, so values above 20 still return one page. Range 1 to 100. Default 20. |
cursor query, string | Opaque cursor from the previous response's page.nextCursor. Length 1 to 2048. |
curl "https://chatterapi.com/v1/x/users/levelsio/tweets" \
-H "Authorization: Bearer $CHATTERAPI_KEY"Full reference for X Timeline Scraper: response example, every field and the errors it can return.
X Mentions Monitor
GET /v1/x/users/{handle}/mentions · 3 credits · MCP tool x_mentions · returns XTweet[]
Get recent tweets that mention an X handle (@name), newest first, with author profiles and engagement. Costs 3 credits per page of about 20. Tip: to catch brand mentions without the @, use x.search with the brand name or everywhere.mentions.
| Parameter | Notes |
|---|---|
handle path, string, required | Handle with or without @, or a profile URL. 1-15 characters. |
limit query, integer | Max rows to return (1-100). One X page holds about 20 rows, so values above 20 still return one page. Range 1 to 100. Default 20. |
cursor query, string | Opaque cursor from the previous response's page.nextCursor. Length 1 to 2048. |
curl "https://chatterapi.com/v1/x/users/levelsio/mentions" \
-H "Authorization: Bearer $CHATTERAPI_KEY"Full reference for X Mentions Monitor: response example, every field and the errors it can return.
X Tweet Search
GET /v1/x/tweets/search · 3 credits · MCP tool x_search · returns XTweet[]
Search tweets by keyword with full X search operators (from:, to:, "exact phrase", OR, -word, min_faves:, filter:links). Returns tweets with author profiles and engagement. Costs 3 credits per page of about 20. Tip: sort=latest for monitoring, sort=top for the most-engaged tweets.
| Parameter | Notes |
|---|---|
q query, string, required | Keyword(s) and X operators. |
sort query, enum | latest for monitoring, top for the most engaged tweets. One of latest, top. Default latest. |
since query, string | Earliest date, YYYY-MM-DD. |
until query, string | Latest date, YYYY-MM-DD. |
lang query, string | Tweet language, 2 letters. |
includeRetweets query, boolean,string | Include retweets. |
limit query, integer | Max rows to return (1-100). One X page holds about 20 rows, so values above 20 still return one page. Range 1 to 100. Default 20. |
cursor query, string | Opaque cursor from the previous response's page.nextCursor. Length 1 to 2048. |
curl "https://chatterapi.com/v1/x/tweets/search?q=%22crm+recommendation%22" \
-H "Authorization: Bearer $CHATTERAPI_KEY"Full reference for X Tweet Search: response example, every field and the errors it can return.
X Tweet Lookup
GET /v1/x/tweets/{id} · 3 credits · MCP tool x_tweet_detail · returns XTweet
Fetch one tweet by id or URL with its full text, author profile, engagement counts, media and reply context. Costs 3 credits. Tip: use conversationId with x.replies to read the whole discussion.
| Parameter | Notes |
|---|---|
id path, string, required | Tweet id or tweet URL. |
curl "https://chatterapi.com/v1/x/tweets/2099495333231288346" \
-H "Authorization: Bearer $CHATTERAPI_KEY"Full reference for X Tweet Lookup: response example, every field and the errors it can return.
Tweet Replies Exporter
GET /v1/x/tweets/{id}/replies · 3 credits · MCP tool x_replies · returns XTweet[]
List the replies to a tweet, page by page, with each reply's text, author profile and engagement. Costs 3 credits per page of about 20. Tip: people replying to a competitor's launch tweet are warm leads; check author.canDm.
| Parameter | Notes |
|---|---|
id path, string, required | Tweet id or tweet URL. |
limit query, integer | Max rows to return (1-100). One X page holds about 20 rows, so values above 20 still return one page. Range 1 to 100. Default 20. |
cursor query, string | Opaque cursor from the previous response's page.nextCursor. Length 1 to 2048. |
curl "https://chatterapi.com/v1/x/tweets/2109949585737052316/replies" \
-H "Authorization: Bearer $CHATTERAPI_KEY"Full reference for Tweet Replies Exporter: response example, every field and the errors it can return.
Retweeter Exporter
GET /v1/x/tweets/{id}/retweeters · 3 credits · MCP tool x_retweeters · returns XUser[]
List the accounts that retweeted a tweet, page by page, with bios, follower counts and DM availability. Costs 3 credits per page of about 20. Tip: retweeters of a post in your niche are people who already care about the topic.
| Parameter | Notes |
|---|---|
id path, string, required | Tweet id or tweet URL. |
limit query, integer | Max rows to return (1-100). One X page holds about 20 rows, so values above 20 still return one page. Range 1 to 100. Default 20. |
cursor query, string | Opaque cursor from the previous response's page.nextCursor. Length 1 to 2048. |
curl "https://chatterapi.com/v1/x/tweets/2109949585737052316/retweeters" \
-H "Authorization: Bearer $CHATTERAPI_KEY"Full reference for Retweeter Exporter: response example, every field and the errors it can return.
X List Members
GET /v1/x/lists/{id}/members · 3 credits · MCP tool x_list_members · returns XUser[]
List everyone on a public X List, page by page, with profiles and DM availability. Costs 3 credits per page of about 20. Tip: curated lists (for example 'SaaS founders') are ready-made lead lists.
| Parameter | Notes |
|---|---|
id path, string, required | List id or an x.com/i/lists/<id> URL. |
limit query, integer | Max rows to return (1-100). One X page holds about 20 rows, so values above 20 still return one page. Range 1 to 100. Default 20. |
cursor query, string | Opaque cursor from the previous response's page.nextCursor. Length 1 to 2048. |
curl "https://chatterapi.com/v1/x/lists/1335924847940079620/members" \
-H "Authorization: Bearer $CHATTERAPI_KEY"Full reference for X List Members: response example, every field and the errors it can return.
X Lead Finder
GET /v1/x/leads · 3 credits · MCP tool x_leads · returns Lead[]
Find tweets where people ask for a recommendation, compare tools, or complain about a tool in your category. Returns leads ranked by an intent score (0 to 1) with the matched phrases and the author's handle. Costs 3 credits per page. Tip: pass competitors to catch people looking to switch.
| Parameter | Notes |
|---|---|
q query, string, required | Your product category or the problem it solves, e.g. crm or cold email. 1-60 characters. |
competitors query, string or array | Up to 5 tools people might switch away from, e.g. hubspot,pipedrive. |
exclude query, string or array | Up to 10 words that disqualify an item. |
time query, enum | How far back to look. One of day, week, month, year. Default month. |
minScore query, number | Minimum intent score from 0 to 1. Range 0 to 1. Default 0.3. |
intents query, string or array | Which intents to return. Default: all three. |
cursor query, string | Opaque cursor from the previous response's page.nextCursor. Length 1 to 2048. |
lang query, string | Tweet language, 2 letters. Default en. |
curl "https://chatterapi.com/v1/x/leads?q=crm&time=year&minScore=0.3" \
-H "Authorization: Bearer $CHATTERAPI_KEY"Full reference for X Lead Finder: response example, every field and the errors it can return.
Actions: connect an account first
- Open Accounts and choose Connect an account.
- Either paste the
auth_tokenandct0cookies from a browser where you're logged into that X account, or log in with its username and password (plus the 2FA setup key if it has one). We encrypt what you send before storing it and never log it. - Copy the account id shown in the table. You pass it as
accountIdon every action.
Only connect accounts you own or manage. Each plan can connect a set number of accounts:
| Plan | Connected X accounts |
|---|---|
| Free (signup credits only) | 1 |
| Starter ($19/month) | 2 |
| Growth ($49/month) | 10 |
| Scale ($149/month) | 40 |
Every action needs an Idempotency-Key
Send a unique Idempotency-Key header (a UUID works) with each action. If the same key arrives again, for example when your code retries after a timeout, you get the first response back and nothing is sent or charged twice. Reusing a key for a different request returns invalid_input. Over MCP, pass the same value as the idempotencyKey argument instead of a header.
curl -X POST "https://api.chatterapi.com/v1/x/dm/send" \
-H "Authorization: Bearer $CHATTERAPI_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"accountId":"YOUR_ACCOUNT_ID","recipientHandle":"jack","text":"Hi Jack, quick question about your API."}'Safety limits
Each connected account has one daily limit for DMs and a separate one for other actions, which keeps it inside what X tolerates. Past the limit, calls return rate_limited with a Retry-After pointing at 00:00 UTC, when the limits reset. Spread bulk work across days and don't loop on that error.
When a session ends
X ends sessions from time to time. When it does, actions from that account return x_account_needs_reconnect until you reconnect it on the Accounts page. Accounts connected by login can turn on automatic re-login. Cookie sessions always need a manual reconnect.
Timeouts
If X doesn't answer in time you get upstream_timeout and no charge. The action may still have gone through, so check (for example with x.tweets or the DM inbox) before you send a new request with a new key.
Action endpoints
These are POST endpoints with a JSON body. The samples generate a fresh Idempotency-Key on each run.
Send a DM
POST /v1/x/dm/send · 10 credits · MCP tool x_dm_send · returns XWriteResult
Send a direct message on X from an account the user connected in the dashboard. Needs accountId, a recipient (handle or user id) and text, plus an idempotencyKey so a retry never sends twice. Costs 10 credits, charged only if X accepts the message. Tip: check the recipient with x.user first; if canDm is false the send will fail.
| Parameter | Notes |
|---|---|
accountId body, string, required | Id of an X account you connected in the dashboard. |
recipientHandle body, string | Recipient handle. Pass this or recipientId. |
recipientId body, string | Recipient user id. Pass this or recipientHandle. |
text body, string, required | Message text, up to 10,000 characters. Length 1 to 10000. |
curl -X POST "https://chatterapi.com/v1/x/dm/send" \
-H "Authorization: Bearer $CHATTERAPI_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"accountId": "8b0e6a52-1f7c-4a3e-9d2b-5c1e7f0a9b11",
"recipientId": "1615394519473549312",
"text": "Hi, saw your question about CRM and Meta ads. Happy to share what worked for us."
}'Full reference for Send a DM: response example, every field and the errors it can return.
Follow / unfollow
POST /v1/x/actions/follow · 5 credits · MCP tool x_follow · returns XWriteResult
Follow or unfollow an X account from a connected account. Needs accountId, a target (handle or user id), action follow or unfollow, and an idempotencyKey. Costs 5 credits on success. Tip: following a lead before a DM makes the DM land in their main inbox more often, but pace it; accounts have a daily action limit.
| Parameter | Notes |
|---|---|
accountId body, string, required | Id of an X account you connected in the dashboard. |
action body, enum | Follow or unfollow. One of follow, unfollow. Default follow. |
targetHandle body, string | Handle to act on. Pass this or targetId. |
targetId body, string | User id to act on. Pass this or targetHandle. |
curl -X POST "https://chatterapi.com/v1/x/actions/follow" \
-H "Authorization: Bearer $CHATTERAPI_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"accountId": "8b0e6a52-1f7c-4a3e-9d2b-5c1e7f0a9b11",
"targetId": "1615394519473549312",
"action": "follow"
}'Full reference for Follow / unfollow: response example, every field and the errors it can return.
Like / retweet
POST /v1/x/actions/like · 5 credits · MCP tool x_like · returns XWriteResult
Like or retweet a tweet from a connected X account. Needs accountId, tweetId (or tweet URL), action like or retweet, and an idempotencyKey. Costs 5 credits on success. Tip: liking a lead's recent tweet before a DM is a light, low-risk warm-up.
| Parameter | Notes |
|---|---|
accountId body, string, required | Id of an X account you connected in the dashboard. |
tweetId body, string, required | Tweet id or tweet URL. |
action body, enum | Like or retweet. One of like, retweet. Default like. |
curl -X POST "https://chatterapi.com/v1/x/actions/like" \
-H "Authorization: Bearer $CHATTERAPI_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"accountId": "8b0e6a52-1f7c-4a3e-9d2b-5c1e7f0a9b11",
"tweetId": "1845201837465319425",
"action": "like"
}'Full reference for Like / retweet: response example, every field and the errors it can return.
Post a tweet
POST /v1/x/tweets · 5 credits · MCP tool x_tweet · returns XWriteResult
Post a tweet or a reply from a connected X account. Needs accountId, text (up to 280 characters) and an idempotencyKey; pass replyToTweetId to reply. Costs 5 credits on success. Tip: never post the same text twice; X rejects duplicates and that reply fails.
| Parameter | Notes |
|---|---|
accountId body, string, required | Id of an X account you connected in the dashboard. |
text body, string, required | Tweet text, up to 280 characters. |
replyToTweetId body, string | Tweet id or URL to reply to. |
curl -X POST "https://chatterapi.com/v1/x/tweets" \
-H "Authorization: Bearer $CHATTERAPI_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"accountId": "8b0e6a52-1f7c-4a3e-9d2b-5c1e7f0a9b11",
"text": "Shipping notes for this week are up."
}'Full reference for Post a tweet: response example, every field and the errors it can return.
Response objects
These are the objects inside data. Actions return XWriteResult, with dryRun: true when nothing was sent (test keys).
XUser
| Field | Type | Nullable | Description |
|---|---|---|---|
id | string | no | Platform id. |
handle | string | no | Handle without @. |
name | string | no | Name. |
bio | string | yes | Profile bio. |
followers | number | yes | Follower count. |
following | number | yes | Following count. |
tweets | number | yes | Tweet count. |
verified | boolean | yes | Legacy verification. |
blueVerified | boolean | yes | Paid blue check. |
canDm | boolean | yes | Whether the account accepts DMs from anyone. |
protected | boolean | yes | Protected (private) account. |
location | string | yes | Profile location. |
url | string | yes | Website in the profile. |
avatarUrl | string | yes | Avatar image URL. |
createdAt | string | yes | ISO 8601 UTC timestamp. |
XTweet
| Field | Type | Nullable | Description |
|---|---|---|---|
id | string | no | Platform id. |
text | string | no | Text. |
url | string | no | Full URL on the platform. |
createdAt | string | yes | ISO 8601 UTC timestamp. |
lang | string | yes | Language code. |
likes | number | yes | Likes. |
retweets | number | yes | Retweets. |
replies | number | yes | Replies. |
quotes | number | yes | Quote tweets. |
views | number | yes | Views. |
bookmarks | number | yes | Bookmarks. |
isReply | boolean | no | Is a reply. |
inReplyToId | string | yes | Tweet this replies to. |
conversationId | string | yes | Root tweet id of the conversation. |
isRetweet | boolean | no | Is a retweet. |
quotedTweetId | string | yes | Tweet this quotes. |
author | object | no | Author profile (XUser). |
media | object[] | no | Images, video or gallery URLs, or null. |
XWriteResult
| Field | Type | Nullable | Description |
|---|---|---|---|
ok | boolean | no | Always true on success. |
action | enum | no | What was done. |
accountId | string | no | Connected account that acted. |
targetId | string | yes | Target user or tweet id. |
resultId | string | yes | Id of what was created, if any. |
dryRun | boolean | no | True when nothing was sent. |
Lead
| Field | Type | Nullable | Description |
|---|---|---|---|
platform | enum | no | reddit or x. |
kind | enum | no | post, comment or tweet. |
id | string | no | Platform id. |
url | string | no | Full URL on the platform. |
text | string | no | Text. |
author | string | yes | Author username, null when deleted. |
authorUrl | string | yes | Author profile URL. |
community | string | yes | Subreddit for Reddit items, null for X. |
score | number | yes | Score (upvotes minus downvotes) as Reddit reports it. |
createdAt | string | yes | ISO 8601 UTC timestamp. |
intent | enum | no | asking_for_recommendation, comparing_tools, complaining_about_tool or other. |
intentScore | number | no | Intent score from 0 to 1. |
matchedTerms | string[] | no | Phrases that made this a lead. |
Recipes
Build an outreach list from a competitor's followers
Page through /v1/x/users/{handle}/followers (3 credits a page) and keep the rows where canDm is true and the bio fits. Then send each person a short, specific DM from a connected account, each with its own Idempotency-Key. Spread the sends over days to stay inside the safety limits.
Warm up before a DM
Like one of the person's recent tweets with /v1/x/actions/like and follow them with /v1/x/actions/follow before you send the DM. Both cost less than the DM, and a name they recognise gets read more often.
Monitor a brand on X
Call /v1/x/tweets/search?q=yourbrand&sort=latest on a schedule, then /v1/x/users/{handle}/mentions for tagged mentions. To catch Reddit too, use the cross-platform Brand Mentions endpoint.
Let an agent do it
Add the MCP server (see MCP) and ask in plain words, for example: "find people asking for a CRM on X this week and draft a DM to the three best fits". The agent sees what each action tool costs and needs your account id to act.
Errors you'll see
| Code | When | What to do |
|---|---|---|
not_found | The handle, tweet or list doesn't exist or is private. | Check the input. Don't retry. |
x_account_required | No connected account has that accountId, or it's paused. | Connect or resume the account and pass its id. |
x_account_needs_reconnect | The account's X session ended. | Reconnect it on the Accounts page. Don't retry. |
rate_limited | Your key's request rate, or the account's daily action limit. | Wait for Retry-After. |
invalid_input | A bad parameter, a missing Idempotency-Key, or X refused the action (a duplicate tweet, for example). | Read the message and fix the request. |
upstream_timeout | X didn't answer in time. | For actions, check whether it went through before you resend. |
Every code, with response bodies, is on Errors.