Twitter API 详细规格¶
本文档详细说明 Twitter 私信、图片上传和用户采集 API 的规格和使用要求。
目录¶
- 私信 API
- API 端点
- 必需的 HTTP 请求头
- URL 查询参数
- 请求体格式
- 成功响应
- 认证信息提取
- 图片上传 API
- 三阶段上传流程
- INIT 阶段
- APPEND 阶段
- FINALIZE 阶段
- 支持的媒体类别
- 用户采集 API
- 获取粉丝列表
- 获取关注列表
- 关注
- 取消关注
- API 限流信息
- 数据类型
私信 API¶
API 端点¶
- URL:
https://x.com/i/api/1.1/dm/new2.json - 方法: POST
- Content-Type:
application/json
必需的 HTTP 请求头¶
Host: x.com
Authorization: Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA
X-Csrf-Token: {从 cookies 提取 ct0}
X-Client-Uuid: {随机生成的 UUID v4}
X-Client-Transaction-Id: {Base64 编码的随机字符串}
Cookie: {完整的 cookies 字符串}
Content-Type: application/json
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36...
URL 查询参数¶
必需的查询参数:
ext=mediaColor,altText,mediaStats,highlightedLabel,voiceInfo,birdwatchPivot,superFollowMetadata,unmentionInfo,editControl,article
include_ext_alt_text=true
include_ext_limited_action_results=true
include_reply_count=1
tweet_mode=extended
include_ext_views=true
include_groups=true
include_inbox_timelines=true
include_ext_media_color=true
supports_reactions=true
supports_edit=true
请求体格式¶
纯文本私信¶
{
"conversation_id": "{user_id}-{current_user_id}",
"recipient_ids": false,
"request_id": "{UUID v4}",
"text": "{message}",
"cards_platform": "Web-12",
"include_cards": 1,
"include_quote_count": true,
"dm_users": true
}
带图片私信¶
{
"conversation_id": "{user_id}-{current_user_id}",
"recipient_ids": false,
"request_id": "{UUID v4}",
"text": "{message}",
"cards_platform": "Web-12",
"include_cards": 1,
"include_quote_count": true,
"dm_users": true,
"attachment": {
"type": "media",
"media": {
"id": "{media_id_string from upload}"
}
}
}
注意:media_id 来自图片上传接口返回的 media_id_string 字段。
成功响应¶
HTTP 200,JSON 包含 entries 字段表示成功。
认证信息提取¶
从 cookies 字符串中提取认证信息:
- CSRF Token (ct0): 正则匹配
ct0=([^;]+) - Auth Token: 正则匹配
auth_token=([^;]+) - User ID: 从
twid提取,支持三种格式: twid=u%3D{user_id}(URL 编码)twid="u={user_id}"(带引号)twid=u={user_id}(不带引号)
图片上传 API¶
三阶段上传流程¶
Twitter 图片上传采用三阶段流程:INIT → APPEND → FINALIZE
每个阶段都是独立的 HTTP 请求,必须按顺序执行。
INIT 阶段 - 初始化上传¶
API 端点:
- URL: https://upload.x.com/i/media/upload.json?command=INIT&total_bytes={size}&media_type=image/jpeg&media_category={category}
- 方法: POST
- 状态码: 200 (成功)
请求头:
Host: upload.x.com
Authorization: Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA
X-Csrf-Token: {从 cookies 提取 ct0}
X-Twitter-Auth-Type: OAuth2Session
Accept: */*
Origin: https://x.com
Referer: https://x.com/
Accept-Language: zh-CN,zh;q=0.9
Priority: u=1, i
Cookie: {完整的 cookies 字符串}
响应格式:
APPEND 阶段 - 上传图片数据¶
API 端点:
- URL: https://upload.x.com/i/media/upload.json?command=APPEND&media_id={media_id}&segment_index=0
- 方法: POST
- Content-Type: multipart/form-data
- 状态码: 204 (成功)
Multipart 字段:
- field name: media
- filename: blob
- content-type: application/octet-stream
- 数据: 图片二进制内容
请求头: 与 INIT 阶段相同
FINALIZE 阶段 - 完成上传¶
API 端点:
- URL: https://upload.x.com/i/media/upload.json?command=FINALIZE&media_id={media_id}&original_md5={md5}
- 方法: POST
- 状态码: 201 (成功)
请求头: 与 INIT 阶段相同
重试策略: - 500 错误时自动重试,最多 2 次 - 重试等待时间: 第 1 次 2 秒,第 2 次 4 秒
支持的媒体类别¶
pub enum MediaCategory {
BannerImage, // "banner_image" - 横幅图片
TweetImage, // "tweet_image" - 推文图片
DmImage, // "dm_image" - 私信图片
}
选择建议:
- 发送私信图片 → 使用 DmImage
- 发布推文图片 → 使用 TweetImage
- 更新个人资料横幅 → 使用 BannerImage
错误处理¶
常见错误码¶
| HTTP 状态码 | 含义 | 处理方式 |
|---|---|---|
| 401 | 认证失败 | 检查 cookies 是否有效 |
| 403 | 无权限 | 检查账号状态 |
| 429 | 请求过于频繁 | 实施速率限制 |
| 500 | 服务器错误 | 自动重试(仅限 FINALIZE 阶段) |
重试建议¶
- INIT 阶段:失败后立即停止,不重试
- APPEND 阶段:失败后立即停止,不重试
- FINALIZE 阶段:500 错误自动重试 2 次,其他错误不重试
安全性约束¶
- 不在日志中输出完整的 cookies 或 token
- 验证消息长度 ≤ 10000 字符
- 验证 user_id 非空
- 使用 HTTPS 确保传输安全
- 定期刷新 cookies 避免过期
性能考虑¶
- 批量发送默认无并发限制 - 可根据账号限制自行调整
- 请求超时设置为 30 秒
- 使用连接池复用 HTTP 连接
- 图片上传前计算 MD5,避免重复上传
用户采集 API¶
获取粉丝列表¶
获取指定用户的粉丝列表,支持分页获取。
API 端点:
- URL: https://x.com/i/api/graphql/{query_id}/Followers
- 方法: GET
- 认证: 需要 Bearer Token 和 CSRF Token
URL 参数:
- variables: JSON 编码的查询参数
- userId: 目标用户的 REST ID(必需)
- count: 每页返回的数量(默认 20,最大 200)
- cursor: 分页游标(可选,获取下一页时使用)
- includePromotedContent: 是否包含推广内容(布尔值)
- features: JSON 编码的特性标志
必需的 HTTP 请求头:
Host: x.com
Authorization: Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA
X-Csrf-Token: {从 cookies 提取 ct0}
Cookie: {完整的 cookies 字符串}
Content-Type: application/json
成功响应:
- HTTP 200,包含 data.user.result.timeline 对象
- 响应头包含 x-rate-limit-* 限流信息
分页逻辑:
- 首次请求不传 cursor 参数
- 响应中的 next_cursor 用于获取下一页
- 当 next_cursor 为 "0" 或不存在时,表示没有更多数据
异常情况:
- 私密账号:返回特定错误标记,is_abnormal = true
- 用户不存在:HTTP 404
- 认证失败:HTTP 401
获取关注列表¶
获取指定用户的关注列表,支持分页获取。
API 端点:
- URL: https://x.com/i/api/graphql/{query_id}/Following
- 方法: GET
- 认证: 需要 Bearer Token 和 CSRF Token
URL 参数:
与获取粉丝列表相同,使用相同的 variables 和 features 结构。
必需的 HTTP 请求头: 与获取粉丝列表相同。
成功响应:
- HTTP 200,包含 data.user.result.timeline 对象
- 响应结构与粉丝列表相同
分页逻辑: 与获取粉丝列表相同。
关注¶
关注指定用户。
API 端点:
- URL: https://x.com/i/api/1.1/friendships/create.json
- 方法: POST
- Content-Type: application/x-www-form-urlencoded
必需的 HTTP 请求头:
Host: x.com
Authorization: Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA
X-Csrf-Token: {从 cookies 提取 ct0}
Cookie: {完整的 cookies 字符串}
Content-Type: application/x-www-form-urlencoded
请求体格式:
include_profile_interstitial_type=1&include_blocking=1&include_blocked_by=1&include_followed_by=1&include_want_retweets=1&include_mute_edge=1&include_can_dm=1&include_can_media_tag=1&include_ext_is_blue_verified=1&include_ext_verified_type=1&include_ext_profile_image_shape=1&skip_status=1&user_id={target_user_id}
成功响应:
- HTTP 200,返回目标用户完整信息(JSON 对象,包含 id_str 字段)
错误响应: - 400: 参数错误(如 user_id 无效) - 401: 认证失败 - 403: 无权限(如被对方拉黑)
取消关注¶
取消关注指定用户。
API 端点:
- URL: https://x.com/i/api/1.1/friendships/destroy.json
- 方法: POST
- Content-Type: application/x-www-form-urlencoded
必需的 HTTP 请求头:
Host: x.com
Authorization: Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA
X-Csrf-Token: {从 cookies 提取 ct0}
Cookie: {完整的 cookies 字符串}
Content-Type: application/x-www-form-urlencoded
请求体格式:
成功响应: - HTTP 200,表示成功取消关注
错误响应: - 400: 参数错误(如 user_id 无效) - 401: 认证失败 - 403: 无权限(如尝试取消关注不存在的关系)
API 限流信息¶
Twitter API 响应头包含限流信息:
x-rate-limit-limit: 500 # 时间窗口内的总请求限制
x-rate-limit-remaining: 498 # 剩余可用请求数
x-rate-limit-reset: 1705401234 # 限制重置的 Unix 时间戳
限流策略: - 获取粉丝/关注列表:每 15 分钟 500 次请求 - 关注/取消关注:每 15 分钟 1000 次请求 - 超出限制后返回 HTTP 429(Too Many Requests)
最佳实践:
1. 检查 x-rate-limit-remaining,接近 0 时暂停请求
2. 使用 x-rate-limit-reset 计算等待时间
3. 实施指数退避策略处理 429 错误
数据类型¶
FollowUser - 粉丝/关注用户信息¶
pub struct FollowUser {
pub rest_id: String, // 用户 REST ID
pub name: String, // 用户显示名称
pub screen_name: String, // 用户名(@username)
pub location: Option<String>, // 地理位置
pub can_dm: bool, // 是否可以发私信
pub followers_count: u64, // 粉丝数
pub following_count: u64, // 关注数
pub media_count: u64, // 媒体数
pub protected: bool, // 是否为私密账号
pub profile_image_url: Option<String>, // 头像 URL
pub description: Option<String>, // 个人简介
}
ApiLimit - API 限流信息¶
pub struct ApiLimit {
pub limit: Option<u32>, // 时间窗口内的总请求限制
pub remaining: Option<u32>, // 剩余可用请求数
pub reset: Option<u64>, // 限制重置的 Unix 时间戳
}
FollowListResult - 粉丝/关注列表响应¶
pub struct FollowListResult {
pub success: bool, // 请求是否成功
pub users: Vec<FollowUser>, // 用户列表
pub next_cursor: Option<String>, // 下一页游标
pub is_abnormal: bool, // 是否为异常状态(如私密账号)
pub api_limit: Option<ApiLimit>, // API 限流信息
pub error_msg: String, // 错误消息
pub http_status: u16, // HTTP 状态码
}
辅助方法:
impl FollowListResult {
/// 检查是否有更多数据可以获取
pub fn has_more(&self) -> bool {
self.next_cursor.is_some()
&& self.next_cursor.as_deref() != Some("0")
}
}
FollowResult - 关注结果¶
pub struct FollowResult {
pub success: bool, // 是否成功
pub user_id: String, // 目标用户 ID
pub error_msg: String, // 错误消息
pub http_status: u16, // HTTP 状态码
}
UnfollowResult - 取消关注结果¶
pub struct UnfollowResult {
pub success: bool, // 是否成功
pub user_id: String, // 目标用户 ID
pub error_msg: String, // 错误消息
pub http_status: u16, // HTTP 状态码
}
相关文档¶
- CLAUDE.md - 项目规范和架构设计
- TESTING.md - 测试策略
- LOGGING.md - 日志规范
- examples/ - 代码示例