メインコンテンツへスキップ
このガイドでは、X API v2 のメディアアップロードエンドポイントを使って、メディアをアップロードする最初のリクエストを行う方法を説明します。 ここでは、分割アップロード用の POST /2/media/upload エンドポイントを使って動画をアップロードします。単一画像のアップロードとは異なる手順が必要です。 動画または分割アップロードの場合は、次の手順を実行します。
  1. INIT コマンドでアップロードを初期化する
  2. APPEND コマンドで各チャンクのバイト列をアップロードする
  3. FINALIZE コマンドでアップロードを完了する
注意: Python で書かれた例は、このサンプルコードを参照してください。

認証

このガイドの例を実行するには、OAuth 2 による認証が必要です。 CONSUMER_KEYCONSUMER_SECRETACCESS_KEYACCESS_TOKEN は、開発者ポータルのダッシュボード内のプロジェクトのアプリで確認できます。

ステップ 1 : POST media/upload (INIT)

INIT コマンドのリクエストは、ファイルアップロードセッションの開始に使用します。以降のすべてのリクエストで使用する media_id が返されます。INIT コマンドが成功したら、次のステップは APPEND コマンドです。 メディアファイルの制約や要件については、ベストプラクティスを参照してください。 リクエスト例
curl --location 'https://api.x.com/2/media/upload' \
    --header 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
    --header 'Content-Type: multipart/form-data' \
    --form 'command=INIT' \
    --form 'media_type=video/mp4' \
    --form 'total_bytes=1024' \
    --form 'media_category=amplify_video'
注記: 生の HTTP リクエストを送信する場合、リクエストは multipart/form-data または application/x-www-form-urlencoded の POST 形式である必要があります。
レスポンスの例
{
    "data":
    {
        "id":"1880028106020515840",
        "media_key":"13_1880028106020515840",
        "expires_after_secs":1295999
    }
}
レスポンスには、メディア識別子の id(文字列)と media_key(文字列)が含まれます。expires_after_secs 秒以内にファイル全体をアップロードする必要があります。

ステップ 2 : POST media/upload (APPEND)

APPEND コマンドは、メディアファイルのチャンク(連続したバイト範囲)をアップロードするために使用します。例えば、3 MB のファイルを 1 MB のチャンク 3 つに分割し、APPEND コマンドリクエストを 3 回送ってアップロードできます。ファイル全体のアップロードが完了したら、次のステップとして FINALIZE コマンドを呼び出します。
メディアファイルを小さなチャンクに分割してアップロードすることには、次のような利点があります。
  • 低帯域幅のネットワーク環境下でも信頼性と成功率が向上
  • アップロードを一時停止および再開できる
  • チャンク単位で個別に再試行できる
  • 変化するネットワーク状況(例: セルラークライアント)に合わせてチャンクサイズを調整可能
リクエスト例
curl --location 'https://api.x.com/2/media/upload' \
    --header 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
    --header 'Content-Type: multipart/form-data' \
    --form 'command=APPEND' \
    --form 'media_id=1880028106020515840' \
    --form 'segment_index=0' \
    --form 'media=@/path/to/your/media/file.mp4'
segment_index はファイルのチャンクに付与する順序インデックスです。値は 0〜999(両端を含む)の範囲である必要があります。最初のセグメントは 0、2 番目は 1、といった具合に続きます。すべてのチャンクをアップロードし終えるまで、チャンクのアップロードを続けてください。
注: 生の HTTP リクエストを送信する場合、リクエストは multipart/form-data の POST 形式にしてください。
注: アップロードが成功すると、HTTP 2XX が空のレスポンスボディで返されます。

ステップ 3 : POST media/upload (FINALIZE)

APPEND コマンドでメディアファイル全体のアップロードが完了した後に、FINALIZE コマンドを呼び出す必要があります。FINALIZE コマンドのレスポンスに processing_info フィールドが含まれている場合にのみ、STATUS コマンドを使用し、成功が返されるまで待ってから Post の作成に進む必要がある場合があります。 リクエスト例
curl --location --request POST 'https://api.x.com/2/media/upload' \
    --header 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
    --header 'Content-Type: multipart/form-data' \
    --form 'command=FINALIZE' \
    --form 'media_id=1880028106020515840'
注: 生の HTTP リクエストを送信する場合、リクエストは multipart/form-data または application/x-www-form-urlencoded の POST 形式である必要があります。
レスポンス例
{
    "data": {
        "id": "1880028106020515840",
        "media_key": "13_1880028106020515840",
        "size": 1024,
        "expires_after_secs": 86400,
        "processing_info": {
            "state": "pending",
            "check_after_secs": 1
        }
    }
}
レスポンスには、media_id(64ビット整数)と media_id_string(文字列)の各フィールドにメディア識別子が含まれます。長整数を正確に表現できない JavaScript などの言語では、API レスポンスで提供される media_id_string を使用してください。 返される media_idexpires_after_secs 秒間のみ有効です。この期間を過ぎて他の API 呼び出しで mediaId を使用しようとすると、Bad Request(HTTP 4xx)のレスポンスが返されます。 レスポンスに processing_info フィールドが含まれている場合は、FINALIZE 操作のステータスをポーリングするために STATUS コマンドを使用してください。メディアの処理に時間を要するケースでは、非同期の finalize 手法が使用されます。今後、動画とアニメーション GIF の処理は非同期 finalize のみがサポートされます。この動作は、アップロードセッションが media_category パラメータで初期化され、メディアタイプが動画またはアニメーション GIF の場合に有効になります。
注: レスポンスに processing_info フィールドが含まれていない場合は、media_id を他の API エンドポイントで使用できます。

ステップ 4 : GET media/upload (STATUS)

STATUS コマンドは、メディア処理の進行状況を定期的にポーリングするために使用します。STATUS コマンドのレスポンスが succeeded を返したら、通常は media_id を使用して Post を作成する次のステップに進みます。
注: FINALIZE コマンド、またはそれ以前の STATUS コマンドのレスポンスに processing_info フィールドが含まれている場合にのみ、STATUS コマンドを使用してください。

リクエストの例

curl --location --request GET 'https://api.x.com/2/media/upload?command=STATUS&media_id=1880028106020515840' \
    --header 'Authorization: Bearer <YOUR_ACCESS_TOKEN>'

レスポンス例

{
    "data":{
        "id":"1880028106020515840",
        "media_key":"13_1880028106020515840",
        "processing_info":{
            "state":"uploading" // 状態遷移フローは pending -> in_progress -> [failed|succeeded] です
        }
    }
}
レスポンス本文には、メディア処理の現在の状態に関する情報を提供する processing_info フィールドが含まれます。processing_info には、状態遷移 pending -> in_progress -> [failed | succeeded] を辿る state フィールドが含まれます。state フィールドが succeeded に設定されるまでは、media_id を使用して Post やその他のエンティティを作成することはできません。

ステップ 5 : メディア付きでPostを投稿

認証済みユーザーに代わり、media_id を含めて POST /2/tweets エンドポイントでPostを作成します。 リクエスト例
curl --location 'https://api.x.com/2/tweets' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <YOUR_ACCESS_TOKEN>'
--data '{
    "text": "メディア付きのPostを作成しました!",
     "media": {
       "media_ids": [
            "1880028106020515840"
        ]
    }
}'

レスポンスの例
{
    "data": {
        "edit_history_tweet_ids": [
            "1880028106020515840"
        ],
        "id": "1880028106020515840",
        "text": "メディア付きの投稿を作成しました! https://t.co/DqNyXX"
    }
}

トラブルシューティング

Media API に関する問題は、開発者フォーラムの Media API カテゴリを参照して解決策を探してください。