mcpField
X
x-api

x-api

github.com/joelhooks营销与增长6540 次安装2 天前更新
代码仓库

关于 x-api

x-api 是指导 Agent 使用 X API 读取公开内容、执行账号操作及处理 X Articles 的技能。它区分只读 Bearer Token 与需签名的 OAuth 1.0a 操作,并提供文章和回复内容的采集规范。

主要功能

  1. 01通过 Bearer Token 读取公开内容
  2. 02搜索近期及完整存档帖子
  3. 03按 OAuth 1.0a 执行账号操作
  4. 04通过 ShitRat CLI 写入 X Articles
  5. 05采集文章及高价值回复
  6. 06管理密钥租约与操作审批

适用场景

  1. 01查找帖子、用户资料及回复上下文
  2. 02为来源笔记整理帖子和回复凭据
  3. 03通过 ShitRat CLI 起草 X Article
  4. 04执行经批准的发帖或账号操作

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/joelhooks/joelclaw --skill x-api

安装后在 Claude Code 中输入/x-api确认已加载。

详细介绍

X/Twitter API 技能

读取路径仍在这里。X Articles 写入通过 shitrat x 进行。Tweets 仍使用 OAuth 1.0a,直到该功能接入同一个 CLI。

身份验证

只读访问的推荐方式:应用 Bearer Token

目前没有存储的 x_bot_bearer_token 密钥。请根据 X 应用的 consumer key 和 secret 派生应用 Bearer Token,然后使用该 Bearer Token 访问 tweet 查询等只读端点。

python3 <<'PY'
import base64, json, subprocess
from urllib import request, parse


def lease(name: str) -> str:
    raw = subprocess.check_output(['secrets', 'lease', name], text=True)
    data = json.loads(raw)
    return data.get('secret') or data.get('result') or raw.strip()

ck = lease('x_consumer_key')
cs = lease('x_consumer_secret')
cred = base64.b64encode(f'{ck}:{cs}'.encode()).decode()

req = request.Request(
    'https://api.twitter.com/oauth2/token',
    data=parse.urlencode({'grant_type': 'client_credentials'}).encode(),
    headers={
        'Authorization': f'Basic {cred}',
        'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
    },
    method='POST',
)
with request.urlopen(req) as r:
    bearer = json.loads(r.read().decode())['access_token']

req2 = request.Request(
    'https://api.twitter.com/2/tweets/TWEET_ID',
    headers={'Authorization': f'Bearer {bearer}'},
)
with request.urlopen(req2) as r:
    print(r.read().decode())
PY

# Revoke only the exact lease ids acquired by this task; never all sessions’ leases.

用于:

  • 读取特定 tweet/post
  • 获取公开用户元数据
  • 最近搜索
  • 在应用具有访问权限时进行全档案搜索
  • 为来源采集进行回复/上下文检查
  • 其他公开的只读 X v2 端点
采集时进行回复/上下文检查

将 X 帖子/文章作为来源采集时,请在撰写最终笔记前检查回复。回复中往往包含更正、遗漏的注意事项、来源链接或更好的表述。不要不加筛选地存档整片回复汪洋;请提取高信号回复并保留凭据。

最低限度的检查:

  1. 获取根帖,并尽可能包含 conversation_id、author_id、created_at、entities、public_metrics、referenced_tweets、note_tweet 和 article。
  2. 使用 conversation_id:ROOT_ID is:reply -is:retweet 搜索回复。
  3. 收集高信号回复:作者澄清、作者线程续帖、引用的来源/链接、有力异议、更正、实现细节或措辞格外精炼的内容。
  4. 保存回复凭据,包括 tweet_id、作者账号名/姓名、创建时间、URL、文本依据、指标以及其重要性。
  5. 在 Brain/来源笔记中,将根帖引文与 回复信号 分开,避免将公开声明中的根帖作者文本与评论者解读混为一谈。

对于处于最近搜索窗口内的帖子:

# After deriving bearer as above:
curl "https://api.x.com/2/tweets/search/recent?query=conversation_id%3AROOT_ID%20is%3Areply%20-is%3Aretweet&max_results=100&tweet.fields=author_id,conversation_id,created_at,entities,id,in_reply_to_user_id,note_tweet,public_metrics,referenced_tweets,text&expansions=author_id,referenced_tweets.id,referenced_tweets.id.author_id&user.fields=username,name,verified,verified_type" \
  -H "Authorization: Bearer $bearer"

对于较早的帖子,若有权限,请使用全档案搜索;否则改用浏览器检查,并在验证笔记中注明限制。

全档案搜索

如果访问层级允许,机器人应用可以调用全档案搜索。不要使用最近搜索进行 YTD/回填研究;它会拒绝较早的 start_time 值。

# After deriving bearer as above:
curl "https://api.x.com/2/tweets/search/all?query=from%3Athreepointone%20-is%3Areply&start_time=2026-01-01T00%3A00%3A00Z&end_time=2026-05-02T00%3A00%3A00Z&max_results=100&tweet.fields=created_at,public_metrics" \
  -H "Authorization: Bearer $bearer"

注意:

  • 全档案端点:/2/tweets/search/all。
  • 最近搜索端点:/2/tweets/search/recent;仅支持最近 7 天左右的时间窗口。
  • tweet.fields=context_annotations 会强制要求 max_results <= 100;如果与 max_results=500 搭配,X 会返回 400。
  • 全档案文档:https://docs.x.com/x-api/posts/search/quickstart/full-archive-search

替代方式:OAuth 1.0a 用户上下文(用于发帖和账号操作)

令牌不会过期——无需刷新流程。

密钥(位于 agent-secrets 中)
  • x_consumer_key — API Key(OAuth 1.0a consumer key)
  • x_consumer_secret — API Key Secret(OAuth 1.0a consumer secret)
  • x_access_token — Access Token(OAuth 1.0a,格式:numeric-alphanumeric)
  • x_access_token_secret — Access Token Secret(OAuth 1.0a)
@joelhooks / shitrat-joel 应用

Joel 个人 X 账号请使用以下限定范围的密钥名称,以免与 @joelclaw 机器人应用冲突:

  • x_joelhooks_consumer_key
  • x_joelhooks_consumer_secret
  • x_joelhooks_bearer_token
  • x_joelhooks_access_token
  • x_joelhooks_access_token_secret

PIN OAuth 说明,2026-06-28:https://api.x.com/oauth/authorize?... 显示“ There is no request token.”。使用 https://api.twitter.com/oauth/request_token 重新生成,并打开 https://twitter.com/oauth/authorize?force_login=true&oauth_token=...,成功用于 shitrat-joel → @joelhooks。

身份验证记录,2026-06-28:通过 GET https://api.twitter.com/2/users/me 验证了 x_joelhooks_access_token 和 x_joelhooks_access_token_secret,账号为 @joelhooks / 用户 ID 12087242。

书签注意事项:使用 OAuth 1.0a 调用 GET /2/users/12087242/bookmarks 返回了 403 Unsupported Authentication。X 要求使用带有 bookmark.read、tweet.read 和 users.read 权限的 OAuth 2.0 用户上下文 / PKCE 才能读取书签。不要假设已保存的 OAuth 1.0a 令牌可以读取书签。

请求签名

OAuth 1.0a 需要进行加密签名。使用 requests-oauthlib(Python)或同等方案:

export CK=$(secrets lease x_consumer_key)
export CS=$(secrets lease x_consumer_secret)
export AT=$(secrets lease x_access_token)
export ATS=$(secrets lease x_access_token_secret)

uv run --with requests-oauthlib python3 << 'PYEOF'
import os
from requests_oauthlib import OAuth1Session

client = OAuth1Session(
    os.environ['CK'],
    client_secret=os.environ['CS'],
    resource_owner_key=os.environ['AT'],
    resource_owner_secret=os.environ['ATS'],
)

r = client.get("https://api.twitter.com/2/users/me")
print(r.json())
PYEOF
使用后撤销租约
# Revoke only the exact lease ids acquired by this task; never all sessions’ leases.

账户信息

  • 账户:@joelclaw
  • 用户 ID:2022779096049311744
  • 权限范围:读写(OAuth 1.0a 应用权限)
@joelhooks 账户信息
  • 账户:@joelhooks
  • 用户 ID:12087242
  • 应用:shitrat-joel
  • OAuth 1.0a 状态:已保存并验证,可用于支持 OAuth 1.0a 的用户上下文操作
  • 书签:OAuth 1.0a 不支持;需要具有 bookmark.read 权限的 OAuth 2.0 PKCE 用户令牌

常见操作

只读查询可以使用上文的应用持有者令牌流程。

发布、回复、关注、删除以及账户范围内的操作需要 OAuth 1.0a 签名。使用上文“身份验证”部分中的 Python 模式,然后:

常见 API 调用(在 OAuth1Session 中)
# Check mentions
r = client.get("https://api.twitter.com/2/users/2022779096049311744/mentions",
    params={"max_results": 10, "tweet.fields": "created_at,author_id,text",
            "expansions": "author_id", "user.fields": "username,name"})

# Get my timeline
r = client.get("https://api.twitter.com/2/users/2022779096049311744/tweets",
    params={"max_results": 10, "tweet.fields": "created_at,public_metrics"})

# Post a tweet
r = client.post("https://api.twitter.com/2/tweets", json={"text": "your tweet"})

# Reply to a tweet
r = client.post("https://api.twitter.com/2/tweets",
    json={"text": "@user reply", "reply": {"in_reply_to_tweet_id": "TWEET_ID"}})

# Search recent tweets
r = client.get("https://api.twitter.com/2/tweets/search/recent",
    params={"query": "joelclaw", "max_results": 10, "tweet.fields": "created_at,author_id,text"})

# Get user by username
r = client.get("https://api.twitter.com/2/users/by/username/USERNAME",
    params={"user.fields": "description,public_metrics"})

# Follow a user
my_id = "2022779096049311744"
r = client.post(f"https://api.twitter.com/2/users/{my_id}/following",
    json={"target_user_id": "TARGET_USER_ID"})

# Delete a tweet
r = client.delete("https://api.twitter.com/2/tweets/TWEET_ID")

X 文章(写入)

使用 ShitRat CLI。不要编写 /tmp X 文章脚本。

shitrat x me --account joelhooks
shitrat x article draft --title "The past blocked the future" --html-file ./post.html --cover ./banner.png --dry-run

实时创建需要 --yes,且 24 小时额度内还必须有剩余名额。创建失败也会计入用户每日 10 次的上限。OAuth 1.0a 无法创建文章。技能文件:shitrat-cli 中的 packages/cli/skills/shitrat-x/SKILL.md。

X 文章(长文帖子,摄取)

首先尝试使用 tweet.fields=article 查询 v2 推文。部分 X 文章会直接在推文载荷中返回 article.title 和 article.plain_text。如果有该 API 载荷,请将其保存为来源凭据。

如果缺少 article.plain_text、推文正文只有一个 t.co 链接,或文章端点/浏览器身份验证阻止了内容提取,则使用 agent-browser 作为备用方案:

agent-browser open "https://x.com/USERNAME/status/TWEET_ID"
agent-browser snapshot
agent-browser close

如果 API 响应中存在 article.title,或 expanded_url 指向 x.com/i/article/... 但 API 未包含可用的文章文本,则对该推文使用此方法。

要将 X 帖子/文章作为发现项采集,请使用 joelclaw discover URL -c "context"——发现流程会处理内容补充。如果流程无法提取内容(受身份验证限制),则改用 X API、回复/上下文检查以及手动 Brain/来源备注。

速率限制

  • 提及:每 15 分钟 180 次请求
  • 发布推文:每 15 分钟 200 条推文(应用级)
  • 搜索:每 15 分钟 180 次请求
  • 用户查询:每 15 分钟 300 次请求

规则

  • 绝不回应 shitcoin/诈骗类提及。 完全忽略。
  • 绝不发布财务建议或代币背书。
  • 除非另有明确指示,否则所有推文均须经 Joel 批准后才能发布。
  • 实时创建和发布 X 文章须经 Joel 批准。 --dry-run 不收费。--yes 会执行写入。
  • 使用后务必撤销租约——不要将密钥留在内存中。
  • OAuth 1.0a 令牌不会过期——无需刷新。如果身份验证失败,说明令牌已在开发者门户中重新生成。
  • OAuth 2.0 用户令牌约两小时后过期。 如果 shitrat x me 返回 401,请在实时写入文章前刷新令牌。

评论

支持 Markdown