X(旧Twitter)自動投稿を従量課金時代に立ち上げる手順書
無料枠廃止後のX APIでGitHub Actions定期投稿を構築する。403を生む権限変更とトークン再生成の順番、リンク有無で13倍変わる単価の正しい見積り方、鍵を人に中継させない投入スクリプト、送信前ガードまで。
約4.2万トークンの節約 (API料金換算で約62円分)。 要件定義・技術調査・試行錯誤ぶんのトークンがまるごと不要になります。※ 出品者申告とレビューに基づく推定値。モデル・タスク内容により変動します。
この巻物について
「X(旧Twitter)自動投稿を従量課金時代に立ち上げる手順書」は、SNS運用カテゴリのAI指示書(MDファイル)です。無料枠廃止後のX APIでGitHub Actions定期投稿を構築する。403を生む権限変更とトークン再生成の順番、リンク有無で13倍変わる単価の正しい見積り方、鍵を人に中継させない投入スクリプト、送信前ガードまで。この巻物をAIに読み込ませると、ゼロから設計・調査する場合に比べて 約4.2万トークン(API料金換算で約62円)・86%のトークンを節約できます。
- カテゴリ
- SNS運用
- 対応AI
- claude-code、cursor、codex-cli
- ライセンス
- 商用利用可 (再販不可)
- 価格
- 無料
- ゼロから開発時
- 約4.8万トークン
- この巻物使用時
- 約6,500トークン
- 節約量
- 約4.2万トークン (約62円)
- 更新日
- 2026-09-16
使い方 (AIに渡す3つの方法)
いちばん簡単なのはワンライナー。Claude Code のターミナルに貼るだけです。
claude "https://makimono-md.vercel.app/api/v1/files/x-twitter/raw を読み込んで、この指示書どおりに実装して"
中身
X(旧Twitter) 自動投稿を従量課金時代に立ち上げる手順書
X API は 2026-02 に無料の書き込み枠が廃止され、新規開発者は PPU(従量課金)のみになった。 この文書は「GitHub Actions の cron から X へ定期投稿する仕組み」を、 課金事故と 403 地獄を踏まずに立ち上げるための手順書。
AI に読ませればそのまま実行できる粒度で書いてある。
0. 先に知っておくべき前提(ここを外すと後で必ず詰む)
単価はリンクの有無で13倍違う
| 種別 | 単価 |
|---|---|
| 通常の投稿 | $0.015 |
| URL を含む投稿 | $0.20 |
| 読み取り | $0.005 |
投稿本文に URL を入れるか、プロフィール欄のリンクに集約するかで月額が一桁変わる。 着手前に依頼主へ選ばせること。遷移率を取るなら本文URL、コストを取るなら bio 集約。
見積りは「キューの件数」ではなく「実際に発行されるツイート数」で数える
長文は自動でスレッド分割される。1件のキューが2ツイートになれば課金も2回。 しかも分割後の「URLを含むチャンク」だけが $0.20 になる。 必ず本番と同じ分割関数を通してから数えること。件数で見積もると2〜3割ずれる。
# 見積りスクリプトの例(本番の chunk() をそのまま import して数える)
import json, poster
items = json.load(open('queue.json', encoding='utf-8'))
tot = link = plain = 0
for it in items:
for c in poster.chunk(it['text']):
tot += 1
if 'http' in c: link += 1
else: plain += 1
print('total tweets:', tot)
print('cost to drain queue: $', round(link*0.20 + plain*0.015, 2))
鍵の発行に API は存在しない
Developer Console の画面操作でしか鍵は作れない。CLI も MCP も代行できない。 自動化の設計時に「ここだけは人が1回やる」と割り切って、その1回を最短にする。
1. 最大の罠 — 権限変更とトークン再生成の順番
App permissions を Read and Write に保存した「後」に、Access Token を再生成する。
この順番を逆にすると、発行されたトークンは Write 権限を持たず、投稿が 403 で失敗する。 画面上は全く同じに見えるので気づけない。
正しい順番:
- Developer Console → 対象アプリ → 「User authentication settings」→ Set up
- App permissions = Read and Write / Type of App = Automated App or Bot / Callback URL と Website URL に自社サイトの URL を入れて 保存
- 保存後、「Keys and tokens」に戻り、Access Token の行の表示が
Read and Write(日本語UIでは「読み取りと書き込み」)になったことを目視確認 - そこで初めて Access Token / Access Token Secret を Regenerate
- Consumer Key / Consumer Secret は伏字なので、これも Regenerate して控える
取得する4点:
- API Key(= Consumer Key)
- API Key Secret(= Consumer Secret)
- Access Token
- Access Token Secret
⚠️ 値を表示するダイアログは閉じると二度と出ない。閉じてしまったら Regenerate をやり直す(何度でも可)。 ⚠️ 「Revoke(取り消す)」と「Regenerate(再生成)」は隣り合っている。Revoke を押すとトークンが消える。
2. 鍵を人の手で中継させない投入ツール
依頼主に鍵をチャットへ貼らせると、会話ログ・スクリーンショット・転送先に残り続ける。 値を画面に出さずに Secrets へ流し込むスクリプトを先に用意して渡すのが正解。
inject-secrets.ps1(Windows / PowerShell):
$repo = "<オーナー>/<リポジトリ>"
# 0) ログイン確認
$who = & gh api user --jq .login 2>$null
if (-not $who) { Write-Host "[NG] gh auth login を実行してください" -ForegroundColor Red; Read-Host; exit 1 }
# 1) admin 権限確認(無ければ届いている招待を自動受諾)
$perm = & gh api "repos/$repo" --jq ".permissions.admin" 2>$null
if ($perm -ne "true") {
$inv = & gh api user/repository_invitations --jq ".[] | select(.repository.full_name==`"$repo`") | .id" 2>$null
if ($inv) { & gh api -X PATCH "user/repository_invitations/$inv" | Out-Null
$perm = & gh api "repos/$repo" --jq ".permissions.admin" 2>$null }
if ($perm -ne "true") { Write-Host "[NG] $who に admin 権限がありません" -ForegroundColor Red; Read-Host; exit 1 }
}
# 2) 画面非表示で入力
$pairs = [ordered]@{
"X_API_KEY" = "API Key (Consumer Key)"
"X_API_SECRET" = "API Key Secret"
"X_ACCESS_TOKEN" = "Access Token"
"X_ACCESS_SECRET" = "Access Token Secret"
}
$vals = @{}
foreach ($k in $pairs.Keys) {
$sec = Read-Host -Prompt " $($pairs[$k])" -AsSecureString
$bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($sec)
$vals[$k] = [Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr).Trim()
[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)
}
# 3) 投入して検証
foreach ($k in $pairs.Keys) { & gh secret set $k --repo $repo --body $vals[$k] }
$vals.Clear()
& gh secret list --repo $repo
Read-Host "Enter で終了"
日本語入りの .ps1 は UTF-8 BOM 付きで保存する。 BOM 無しだと Windows PowerShell 5.1 が Shift-JIS と誤読して構文エラーになる。 変数の直後に日本語を続けない(
$repo に権限がありませんは$repo に権限がありません全体を 変数名と解釈して空文字になる)。"$repo" + " に権限がありません"のように分ける。
3. GitHub Actions 側
.github/workflows/post.yml:
name: post-to-x
on:
schedule:
- cron: "0 23 * * *" # 08:00 JST(Actions は UTC)
- cron: "30 3 * * *" # 12:30 JST
- cron: "0 11 * * *" # 20:00 JST
workflow_dispatch:
permissions:
contents: write # 投稿済みフラグを queue.json に書き戻すため
concurrency:
group: post-to-x
cancel-in-progress: false
jobs:
post:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: pip install -r requirements.txt
- name: post next queued tweet
env:
X_API_KEY: ${{ secrets.X_API_KEY }}
X_API_SECRET: ${{ secrets.X_API_SECRET }}
X_ACCESS_TOKEN: ${{ secrets.X_ACCESS_TOKEN }}
X_ACCESS_SECRET: ${{ secrets.X_ACCESS_SECRET }}
run: python poster.py
- name: save posted state
run: |
git config user.name "post-bot"
git config user.email "<ボット用メールアドレス>"
git add queue.json
git diff --staged --quiet || git commit -m "chore: mark posted [skip ci]"
git push
投稿側は OAuth 1.0a を使う(OAuth 2.0 のクライアントID/シークレットでは投稿しない):
client = tweepy.Client(
consumer_key=os.environ["X_API_KEY"],
consumer_secret=os.environ["X_API_SECRET"],
access_token=os.environ["X_ACCESS_TOKEN"],
access_token_secret=os.environ["X_ACCESS_SECRET"],
)
4. 送信前ガードを必ず入れる(従量課金では必須)
壊れた本文をそのまま「買ってしまう」事故を防ぐ。1投稿 $0.20 の世界では無視できない。
import re
X_MAX_WEIGHTED_LEN = 280
PLACEHOLDER_RE = re.compile(r"(XX+|TODO|TBD|FIXME|<[A-Za-z_ ]{2,}>|<[^>]*>|\{\{)")
def guard_parts(parts):
"""問題の説明リストを返す。空なら投稿してよい。"""
if not parts:
return ["本文が空です"]
problems = []
for i, part in enumerate(parts, 1):
label = f"part {i}/{len(parts)}"
if not part.strip():
problems.append(f"{label}: 本文が空です"); continue
if wlen(part) > X_MAX_WEIGHTED_LEN:
problems.append(f"{label}: 長すぎます")
if PLACEHOLDER_RE.search(part):
problems.append(f"{label}: プレースホルダが残っています")
# 文字化け検出: 日本語0文字なのに Latin-1 補助域が多い=エンコーディング取り違え
jp = sum(1 for ch in part if 0x3040 <= ord(ch) <= 0x30FF or 0x4E00 <= ord(ch) <= 0x9FFF)
latin1 = sum(1 for ch in part if 0x0080 <= ord(ch) <= 0x00FF)
if jp == 0 and latin1 >= 5:
problems.append(f"{label}: 文字化けの疑い")
return problems
main() で分割直後・DRY_RUN 判定より前に呼び、問題があれば stderr に出して sys.exit(1)。
投稿も queue.json の更新もしないこと。
5. クレジットと自動チャージ
- 開発者登録自体は $0。課金はクレジット購入時のみ
- 残高切れは 402 Payment Required で静かに止まる。気づくまで数日空く
- 自動チャージは ON にする(cron が固定回数なら暴走しようがない)。 目安: 月額見積りの1.5〜2ヶ月分をチャージ額、発動しきい値は少額に
- 購入画面は左メニューから開く。URL を直打ちすると 404 になることがある
6. 立ち上げ後の検証手順
# 手動で1本流す
gh workflow run post.yml --repo <オーナー>/<リポジトリ>
# 結果を見る(成功なら投稿URLがログに出る)
gh run list --repo <オーナー>/<リポジトリ> --limit 1
gh run view <RUN_ID> --repo <オーナー>/<リポジトリ> --log | grep -iE "posted|error|40[0-9]"
エラーの切り分け:
| 症状 | 原因 | 対処 |
|---|---|---|
| 401 Unauthorized | secrets が空 or 値の取り違え | gh secret list で4件あるか確認 → 再投入 |
| 403 Forbidden | 権限変更前に発行したトークン | Read and Write 保存 → その後 Regenerate → 再投入 |
| 402 Payment Required | クレジット残高切れ | チャージ。自動チャージ ON にする |
| 投稿されるが別アカウントに出る | 鍵発行時に別アカウントでログインしていた | 正しいアカウントでログインし直して再発行 |
ログに
X_API_KEY:の右が空で並んでいたら、secrets が渡っていない(登録漏れ or リポジトリ違い)。
7. リポジトリを移設したときの落とし穴
「同じ名前で作り直した」リポジトリは、元のリポジトリと merge-base を持たない別履歴であることが多い。
git diff HEAD <新remote>/main が全ファイル差分になったら、それは移設ではなく作り直し。
git merge-base HEAD <新remote>/mainが空 → 別履歴- force push で上書きしない。新しい方を正本と決め、旧版は退避ブランチに残す
git branch legacy-<短縮SHA> # 旧版を退避
git remote set-url origin <新リポジトリのURL>
git fetch origin
git checkout -B main origin/main # 新しい正本に乗り換え
チェックリスト
- 本文に URL を入れるか bio 集約かを依頼主に選ばせた(月額が13倍変わる)
- 本番の分割関数を通してツイート数で見積もった(件数で数えていない)
- App permissions を Read and Write で保存してから Access Token を Regenerate した
- トークンの行が
Read and Write表示になっているのを目視確認した - 鍵はチャットに貼らせず、画面非表示のスクリプトで Secrets に投入した
- 送信前ガードを入れた(文字化け・長さ超過・プレースホルダ・空文)
- 自動チャージを ON にした
-
workflow_dispatchで1本流し、投稿URLがログに出ることを確認した
よくある質問
+「X(旧Twitter)自動投稿を従量課金時代に立ち上げる手順書」とは何ですか?
無料枠廃止後のX APIでGitHub Actions定期投稿を構築する。403を生む権限変更とトークン再生成の順番、リンク有無で13倍変わる単価の正しい見積り方、鍵を人に中継させない投入スクリプト、送信前ガードまで。
+どれくらいトークン(費用)を節約できますか?
ゼロから開発すると約4.8万トークンかかりますが、この巻物を使えば約6,500トークンで済みます。差し引き約4.2万トークン(API料金換算で約62円)・86%の節約です。
+どうやって使いますか?
無料です。MDファイルを Claude Code などのAIに読み込ませるだけ。ワンライナーをターミナルに貼れば実装が始まります。要件定義や技術調査を省いて実装だけにトークンを使えます。
+どのAIツールに対応していますか?
claude-code、cursor、codex-cli に対応しています。
+商用利用できますか?
ライセンスは「商用利用可 (再販不可)」です。
🤝 自分でAIを動かすのは、まだ不安…という方へ
この巻物の内容を、AIを使うプロに丸ごと任せることもできます。姉妹サービスAI代行堂なら「LINEで頼むだけで、仕事が完成」。
関連する巻物
この巻物、誰かのトークンも救えます
𝕏 で節約レシートをシェア