x-api について
x-apiは、Xの公開コンテンツの閲覧、アカウント操作、X Articlesの処理に関するエージェントスキルです。読み取り用Bearer Tokenと署名が必要なOAuth 1.0a操作を区別し、記事や返信の収集手順を示します。
主な機能
- 01Bearer Tokenによる公開情報の取得
- 02最近の投稿と全期間アーカイブの検索
- 03OAuth 1.0aによるアカウント操作
- 04ShitRat CLIによるX Articlesの作成
- 05記事と重要な返信の収集
- 06シークレットリースと承認の管理
活用シーン
- 01投稿、ユーザー情報、返信の文脈を調査
- 02ソースノート用の投稿・返信記録を作成
- 03ShitRat CLIでX Articleを下書き
- 04承認済みの投稿やアカウント操作を実行
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ joelhooks/ joelclaw --skill x-apiインストール後、Claude Code で/x-apiを入力して読み込まれたか確認します。
詳細
X/Twitter API スキル
読み取りパスはこのままです。X Articles への書き込みには shitrat x を使用します。ツイートには、同じ CLI に対応するまでは引き続き OAuth 1.0a を使用します。
認証
読み取り専用アクセスにはアプリベアラートークンを推奨します
現時点では、保存済みの x_bot_bearer_token シークレットはありません。X アプリのコンシューマーキーとシークレットからアプリベアラートークンを導出し、ツイートの取得など、読み取り専用エンドポイントに使用してください。
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.
以下に使用します。
- 特定のツイート/投稿の読み取り
- 公開ユーザーメタデータの取得
- 最近の検索
- アプリにアクセス権がある場合の全期間検索
- ソース取り込みのための返信/コンテキスト確認
- その他の公開読み取り専用 X v2 エンドポイント
取り込みのための返信/コンテキスト確認
X の投稿/記事をソースとして取り込む場合は、最終メモを書き込む前に返信を確認してください。返信には、訂正、不足している注意点、ソースリンク、より適切な説明が含まれていることがよくあります。返信の山全体を無差別に保存せず、重要度の高い返信を抽出し、根拠を記録してください。
最低限の確認手順:
- ルート投稿を取得します。取得項目には、利用可能な場合、
conversation_id、author_id、created_at、entities、public_metrics、referenced_tweets、note_tweet、articleを含めます。 conversation_id:ROOT_ID is:reply -is:retweetで返信を検索します。- 重要度の高い返信を記録します。対象は、投稿者による補足説明、投稿者によるスレッドの続き、引用元のソース/リンク、強い反論、訂正、実装の詳細、または特に明快な表現です。
- 返信の根拠情報として、
tweet_id、投稿者のハンドル名/表示名、投稿日時、URL、テキストの根拠、メトリクス、重要な理由を保存します。 - 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 キー(OAuth 1.0a コンシューマーキー)x_consumer_secret— API キーシークレット(OAuth 1.0a コンシューマーシークレット)x_access_token— アクセストークン(OAuth 1.0a、形式:numeric-alphanumeric)x_access_token_secret— アクセストークンシークレット(OAuth 1.0a)
@joelhooks / shitrat-joel アプリ
@joelclaw ボットアプリと競合しないよう、Joel の個人 X アカウントには以下のスコープ付きシークレット名を使用してください。
x_joelhooks_consumer_keyx_joelhooks_consumer_secretx_joelhooks_bearer_tokenx_joelhooks_access_tokenx_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:x_joelhooks_access_token と x_joelhooks_access_token_secret は、GET https://api.twitter.com/2/users/me で @joelhooks/ユーザー ID 12087242 として検証済みです。
ブックマークに関する注意:GET /2/users/12087242/bookmarks は、OAuth 1.0a で 403 Unsupported Authentication を返しました。ブックマークには、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 Articles(書き込み)
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 時間あたりの上限に空きがあることが必要です。作成に失敗した場合も、ユーザーごとの 1 日 10 件の上限にカウントされます。OAuth 1.0a では記事を作成できません。スキル:shitrat-cli 内の packages/cli/skills/shitrat-x/SKILL.md。
X Articles(長文投稿、取り込み)
まず、tweet.fields=article を指定して v2 のツイート検索を試してください。一部の X Articles では、ツイートのペイロードに 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/ソースメモに切り替えます。
レート制限
- メンション:180 リクエスト/15 分
- ツイートの投稿:200 件/15 分(アプリ単位)
- 検索:180 リクエスト/15 分
- ユーザー検索:300 リクエスト/15 分
ルール
- shitcoin/詐欺に関するメンションには絶対に反応しないでください。 完全に無視してください。
- 金融上のアドバイスやトークンの推奨を投稿しないでください。
- 明示的に指示されない限り、投稿前に Joel の承認を得てください。
- 本番環境での X Article の作成と公開には、Joel の承認が必要です。
--dry-runは無料です。--yesは書き込みを実行します。 - 使用後は必ずリースを取り消してください — シークレットをメモリに残さないでください。
- OAuth 1.0a トークンは期限切れになりません — 更新は不要です。認証に失敗する場合は、開発者ポータルでトークンが再生成されています。
- OAuth 2.0 ユーザートークンは約 2 時間で期限切れになります。
shitrat x meが 401 を返す場合は、本番環境で記事を書き込む前に更新してください。