@rodemasu

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

XでのV2エンドポイントを使用してのメディア付きポストができないです

X(Twitter)で、Ouath2.0で認証をした後に、X APIでメディア付き(動画&画像)ポストをするPHPを作っています。(ワードプレス内)
今まではV1.1エンドポイントにTwitterOAuthを使わせてもらってメディア付き投稿をAPI経由で行っていました。
2025年4月末でv1.1のメディアアップロード用のエンドポイントが使えなくなるというアナウンスを見たので、V2エンドポイントにメディアをアップロードして、ポストしようと思っています。

V2エンドポイントにメディアをアップロードしてメディアIDを取得はできましたが、そのIDを使ってテキスト付きのポストをしようとすると400エラーが出てポストできませんでした。
エラーのレスポンスは以下のように返ってきます

{"errors":[{"parameters":{"media.media_ids":["メディアID番号"]},"message":"Your media IDs are invalid."}],"title":"Invalid Request","detail":"One or more parameters to your request was invalid.","type":"https://api.twitter.com/2/problems/invalid-request"}

アップしているのは画像1枚で、それにテキストのポスト内容を加えポストしています。
processing_infoのstateがsucceededになっているのも確認しています。

ポストのエンドポイントは
https://api.x.com/2/posts
を使用しています。

ポストのボディは以下のようになっています。
{"text":"テキスト","media":{"media_ids":["メディアID番号"]}}

テキストだけのポストなら普通に完了するのですが、メディアをつけるとNGになってしまう状況です。

かなりの初心者で、色々調べはしたのですが八方塞がりになってしまいました・・・

もし何か解決策が分かるという有識者の方いらっしゃいましたらご教授いただけませんでしょうか。
よろしくお願いします。

0 likes

3Answer

こちらもあまり詳しくはありませんが説明を読むと添付ファイルは別の所へPOSTのように思えます

V2エンドポイントにメディアをアップロードしてメディアIDを取得はできましたが

そのメディアIDを使用してテキスト投稿用のエンドポイントにメディアIDを付けてポストするように読み取れます。
メディアIDや重要な情報は伏せ字でいいのでPHPの該当ソースが無いと厳しいです

0Like

こんにちわ、ご返信ありがとうございます。
すいません、ちょうど自己解決してしまいました。
ソースの方はあまりに汚い&長いのでお見せするのはどうかと思い躊躇していました。

結論から言うとwp_remote_postでPOSTして得たメディアIDはその後の実際のポスト投稿をする際になぜか400エラーでそのメディアIDが使えなくなりました。しかし、cURLを使うってアップロードするとうまくいきました(なぜなのか全くわかりませんが・・・)
ほとんどAIに頼って作ったので、以下のコード部分で正解かどうかわかりませんが、多分・・・

ダメな例
$endpoint = 'https://api.x.com/2/media/upload';
$init_args = array(
'headers' => array(
'Authorization' => 'Bearer ' . $access_token,
),
'body' => array(
'command' => 'INIT',
'media_type' => $media_type,
'total_bytes' => $file_size,
'media_category' => $media_category,
),
);
$response = wp_remote_post($endpoint, $init_args);
$init_data = json_decode(wp_remote_retrieve_body($response), true);
$media_id = $init_data['data']['id'];
で取得したメディアIDは後でポストするときにメディアIDを指定しても
{"errors":[{"parameters":{"media.media_ids":["メディアID番号"]},"message":"Your media IDs are invalid."}],"title":"Invalid Request","detail":"One or more parameters to your request was invalid.","type":"https://api.twitter.com/2/problems/invalid-request"}

で弾かれました。
逆にうまくいったのは(これも多分)
$endpoint = 'https://api.twitter.com/2/media/upload';

    $retry_count = 0;
    $max_retries = 3;
    $retry_delay = 5;
if ($media_category === 'tweet_image') {

    while ($retry_count < $max_retries) {
        $headers = [
            'Authorization: Bearer ' . $access_token,
            'Content-Type: multipart/form-data'
        ];
        $body = [
            'media' => new CURLFile($file_path, $media_type, basename($file_path)),
            'media_category' => $media_category
        ];

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $endpoint);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        $response = curl_exec($ch);
        $response_data = json_decode($response, true);
        $media_id = $response_data['id'] ?? $response_data['media_id_string'] ?? null;
        return $media_id;
    }

DB名&カラムをV1.0OAuthから流用・引っ越ししたので、変数名がベアラトークンではなくアクセストークンなのはご容赦ください。
そして、別関数から上記のコードを呼び出し、メディアIDを取得して、以下でポストしています。(だいぶ端折ってます)

$tweet_endpoint = 'https://api.twitter.com/2/tweets';
    $tweet_text = $c['post'];
    $params = array(
        "text" => $tweet_text
    );
        $media_ids = array_merge($media_ids, $images_for_tweet);
        $params["media"] = array("media_ids" => $media_ids);
    $post_args = array(
        'headers' => $headers,
        'body'    => wp_json_encode($params),
        'timeout' => 30,
    );
    
    $tweet_response = wp_remote_post($tweet_endpoint, $post_args);

これだとうまく画像付き(動画もチャックアップロードで確認もしました)ポストができるのを確認しました。
正直まだWebプログラミングやってみて一か月もたっておらず、コーディングはほぼAI任せなので、初心者丸出しです。
なので、
$response = wp_remote_post($endpoint, $init_args);
で取得したメディアIDが無効なのに、
$response = curl_exec($ch);
で取得したメディアIDが有効なのも、実際やってみてうまくいったというだけの結果論で、「何故そうなったのか?」という点は未解決のままです。
cURLを使ってみた理由は、公式ページにcURLでのサンプルが書いてあったので、ダメもとで試したらうまくいった、というだけです。

https://docs.x.com/x-api/media/quickstart/media-upload-chunked
とりあえず、1.1エンドポイントが使えなくなる前にV2エンドポイントにメディアアップロード&ポスト投稿ができたので良かったです。

0Like

Comments

  1. それはよかったです。Xのヘルプではわかりづらかったので
    こちらもAIに説明してもらって少し理解出来たぐらいです

    ちなみにAPIの使用回数がプランによって制限があると思うのですが
    こうやってうまくいったとかうまく行かなかったとかでも回数が減る物なのですか?

フリープランで確か1日に送れるメディアの数が85(87だったかも・・・)以上送ると、レスポンスで
429
Too many request
が返されますね。

なので、検証途中にリミットに行ってしまって、その日は検証できなくなって結構大変でした・・・。
確かメディアを送信したレスポンスをすべて見ると、その中に
rate limit
とかの項目があった気がします。(ログを消しちゃったので、お見せすることができないです・・・)
リミットに到達してしまった場合、次にメディアを送信できる時間がいつなのかも表示されていました(ただし世界標準時刻表示でしたが)

かなり情報が少なくて、AIもChat GPTだとDeep researchを使っても有効な情報は得られませんでしたが、XのGrokで調べることで解決への糸口が見つかりました。

0Like

Comments

  1. 参考になりました。やはり使用回数で苦労するみたいですね。
    「XのGrokで調べる」はまさに灯台もと暗しですね

Your answer might help someone💌