跳转到主要内容
本指南将帮助你通过 X API v2 的媒体上传 endpoint 发出第一个媒体上传请求。 在本指南中,我们将使用分块的 POST /2/media/upload endpoint 来上传视频;与单张图片的上传相比,这需要调整相应的工作流程。 对于视频或分块上传,你必须:
  1. 使用 INIT 命令初始化上传
  2. 使用 APPEND 命令上传每个分块
  3. 使用 FINALIZE 命令完成上传
注意: 请参阅此示例代码,其中提供了一个使用 Python 编写的示例。

身份验证

要运行本指南中的示例,您需要使用 OAuth 2 进行身份验证。 您可以在开发者门户的仪表板中,位于您 Project 下的 App 内找到 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-dataapplication/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 的文件拆分为 3 个 1 MB 的分片,并通过 3 次 APPEND 命令请求进行上传。整个文件上传完成后,下一步调用 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,第二个分片为 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-dataapplication/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(字符串)fields 中提供媒体标识符。对于 JavaScript 及其他无法精确表示长整型的语言,请使用 API 响应中提供的 media_id_string 返回的 media_id 仅在 expires_after_secs 秒内有效。在此时间段之后尝试在其他 API 调用中使用 media_id 将导致 Bad Request(HTTP 4xx)响应。 如果响应包含 processing_info field,则使用 STATUS 命令轮询 FINALIZE 操作的状态。异步 finalize 方式适用于媒体处理需要更长时间的情况。未来,所有视频和动画 GIF 的处理将仅支持异步 finalize。若上传会话在初始化时使用了 media_category 参数,且媒体类型为视频或动画 GIF,则会启用此行为。
注意: 如果响应中未返回 processing_info field,则 media_id 已可用于其他 API endpoint。

步骤 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 字段,其中提供媒体处理操作的当前状态信息。该字段包含一个 state 子字段,其状态依次流转为:pending -> in_progress -> [failed | succeeded]。在 state 变为 succeeded 之前,不能使用 media_id 创建 Post 或其他实体。

步骤 5:发布带媒体的 Tweet

使用 POST /2/tweets endpoint 代表已认证用户创建一个 Post,并包含 media_id 示例请求
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": "我发了一个带媒体的Post!https://t.co/DqNyXX"
    }
}

疑难解答

如果遇到 Media API 的问题,请在开发者论坛查阅 Media API 分类以寻找答案。
I