X/Twitter WebSocket API 参考
打开一个 WebSocket,把被监控账号的推文、资料/关注信号与丰富化结果流式送入机器人或提醒系统。
最后更新:2026 年 5 月 26 日
基于被监控账号 feed 构建
TweetStream 为选定的 X/Twitter 账号打开一个 WebSocket。你添加重要账号,保持 socket 连接,然后在事件到达时接收 JSON 包裹。
把本页当作实用 API 参考:连接详情、认证方式、事件操作、快速开始代码、生产重连与消息包裹。
连接详情
| 端点 | wss://ws.tweetstream.io/ws |
| 协议 1 | tweetstream.v1 |
| 协议 2 | tweetstream.auth.token.YOUR_API_KEY |
事件操作
每个帧都使用同一套包裹结构。根据消息族和操作路由,而不是解析自由文本。
认证方式
尽量使用子协议认证。对于无法设置 WebSocket 子协议的环境,也支持 Bearer 请求头和 apiKey 查询参数认证。
快速开始示例
复制以下代码即可立即连接:
TweetStream 只会发送你已在控制台跟踪账号的内容。载荷里的 author.handle 在有值时会包含开头的 @;如果要和 elonmusk 这类裸用户名比较,请先去掉它。
const API_KEY = 'YOUR_API_KEY'; // Get your key from the dashboard
const WS_URL = 'wss://ws.tweetstream.io/ws';
const protocols = [
'tweetstream.v1',
`tweetstream.auth.token.${API_KEY}`,
];
const ws = new WebSocket(WS_URL, protocols);
ws.onopen = () => {
console.log('Connected to TweetStream!');
};
ws.onmessage = (event) => {
const envelope = JSON.parse(event.data);
if (envelope.t === 'tweet' && envelope.op === 'content') {
const tweet = envelope.d;
const author = tweet.author?.handle ?? tweet.author?.name ?? 'unknown';
console.log(`[${tweet.kind}] [${author}] ${tweet.text}`);
}
};
ws.onclose = () => {
console.log('WebSocket closed');
};
ws.onerror = (error) => {
console.error('WebSocket error', error);
};生产示例
生产环境需要在部署、网络波动或 socket 关闭后自动重连。事件处理保持幂等,因为重连时可能会再次看到近期状态。
type VerifiedType = 'blue' | 'business' | 'government' | 'none';
type TweetVerifiedLabel = {
badge: string | null;
description: string;
url: string | null;
};
type TweetAuthor = {
banner?: string;
bio?: string;
followersCount?: number;
followingCount?: number;
id?: string;
joinedAt?: number;
location?: string;
metrics?: {
likes?: number;
tweets?: number;
};
// Includes a leading @ when present, for example "@elonmusk".
handle?: string;
name?: string;
platform?: 'twitter' | 'truth_social';
profileImage?: string;
url?: string;
verifiedLabel?: TweetVerifiedLabel;
verifiedType?: VerifiedType;
};
type Media = {
url: string;
type?: 'image' | 'video' | 'gif';
thumbnail?: string;
};
type TweetUrl = {
url: string;
name?: string;
tco?: string;
};
type TweetMention = {
handle?: string;
id?: string;
name?: string;
};
type TweetContentKind = 'post' | 'reply' | 'quote' | 'retweet';
type TweetContent = {
tweetId: string;
kind: TweetContentKind;
text: string;
createdAt: number;
author: TweetAuthor;
link?: string;
media?: Media[];
mentions?: TweetMention[];
receivedAt?: number;
urls?: TweetUrl[];
ref?: {
type: 'reply' | 'quote' | 'retweet';
tweetId?: string;
text?: string;
author?: TweetAuthor;
media?: Media[];
};
};
type MetaSource = 'text' | 'ocr';
type DetectedCexMarket = {
exchange: 'bybit' | 'binance' | 'hyperliquid';
symbol?: string;
priceUsd?: number;
url?: string;
baseAsset?: string;
quoteAsset?: string;
sources: MetaSource[];
};
type DetectedPredictionMarket = {
exchange: 'polymarket' | 'kalshi';
marketId?: string;
title?: string;
priceUsd?: number;
url?: string;
sources: MetaSource[];
};
type DetectedToken = {
symbol?: string;
name?: string;
contract?: string;
chain?: string;
networkId?: number;
priceUsd?: number;
sources: MetaSource[];
};
type TweetMeta = {
tweetId: string;
ocr?: {
text: string;
};
detected?: {
tokens?: Array<{
symbol?: string;
name?: string;
contract?: string;
chain?: string;
networkId?: number;
priceUsd?: number;
sources: Array<'text' | 'ocr'>;
}>;
cex?: Array<{
exchange: 'bybit' | 'binance' | 'hyperliquid';
symbol?: string;
priceUsd?: number;
url?: string;
baseAsset?: string;
quoteAsset?: string;
sources: Array<'text' | 'ocr'>;
}>;
prediction?: Array<{
exchange: 'polymarket' | 'kalshi';
marketId?: string;
title?: string;
priceUsd?: number;
url?: string;
sources: Array<'text' | 'ocr'>;
}>;
};
};
type TweetUpdate = {
tweetId: string;
kind?: TweetContentKind;
text?: string;
author?: TweetAuthor;
media?: Media[];
mentions?: TweetMention[];
receivedAt?: number;
urls?: TweetUrl[];
ref?: TweetContent['ref'];
};
type TweetDeleteEvent = {
tweetId: string;
eventId: string;
deletedAt?: number;
receivedAt?: number;
author?: TweetAuthor;
text?: string;
};
type TweetPinEvent = {
tweetId: string;
eventId: string;
observedAt: number;
receivedAt?: number;
action: 'pin' | 'unpin';
author: TweetAuthor;
text?: string;
tweet?: TweetContent;
};
type AccountEventActor = TweetAuthor & {
websiteUrl?: string;
};
type ProfileUpdateEvent = {
kind: 'PROFILE';
eventId: string;
observedAt: number;
receivedAt?: number;
actor: AccountEventActor;
changes: {
avatar?: string;
banner?: string;
bio?: string;
handle?: string;
location?: string;
name?: string;
verifiedLabel?: TweetVerifiedLabel | null;
websiteUrl?: string | null;
};
previous?: {
avatar?: string;
banner?: string;
bio?: string;
handle?: string;
location?: string;
name?: string;
verifiedLabel?: TweetVerifiedLabel | null;
websiteUrl?: string | null;
};
};
type FollowEvent = {
kind: 'FOLLOW' | 'UNFOLLOW';
eventId: string;
observedAt: number;
receivedAt?: number;
actor: AccountEventActor;
target: AccountEventActor;
};
type Envelope<T extends object> = {
v: 1;
t: 'tweet' | 'account' | 'control';
op:
| 'content'
| 'meta'
| 'update'
| 'delete'
| 'pin'
| 'unpin'
| 'profile_update'
| 'follow'
| 'unfollow'
| 'auth_ping'
| 'auth_pong'
| 'twitter_handles_result';
id?: string;
ts: number;
d: T;
};
type TwitterHandlesResult = {
action: 'follow' | 'unfollow';
requestId: string | null;
results: Array<{
input: string;
handle?: string;
name?: string;
normalizedHandle?: string;
profileImage?: string;
twitterId?: string;
state:
| 'added'
| 'already_following'
| 'invalid_input'
| 'duplicate'
| 'not_found'
| 'failed'
| 'removed'
| 'not_following';
message?: string;
}>;
error: string | null;
};
const API_KEY = process.env.TWEETSTREAM_API_KEY ?? 'YOUR_API_KEY';
const WS_URL = 'wss://ws.tweetstream.io/ws';
const PROTOCOLS = ['tweetstream.v1', `tweetstream.auth.token.${API_KEY}`];
let ws: WebSocket | null = null;
let reconnectTimer: ReturnType<typeof setTimeout> | undefined;
function connect() {
ws = new WebSocket(WS_URL, PROTOCOLS);
ws.onopen = () => {
console.log('Connected to TweetStream');
};
ws.onmessage = (event) => {
const envelope = JSON.parse(event.data) as Envelope<Record<string, unknown>>;
if (envelope.t === 'tweet') {
if (envelope.op === 'content') {
const tweet = envelope.d as TweetContent;
const author = tweet.author?.handle ?? tweet.author?.name ?? 'unknown';
const platform = tweet.author?.platform ?? 'twitter';
console.log(`[CONTENT:${tweet.kind}] ${author} (${platform}): ${tweet.text}`);
} else if (envelope.op === 'update') {
const update = envelope.d as TweetUpdate;
console.log(`[UPDATE] ${update.tweetId}`, update);
} else if (envelope.op === 'meta') {
const meta = envelope.d as TweetMeta;
console.log(`[META] ${meta.tweetId}`, meta);
} else if (envelope.op === 'delete') {
const deleted = envelope.d as TweetDeleteEvent;
console.log(`[DELETE] ${deleted.tweetId}`);
} else if (envelope.op === 'pin' || envelope.op === 'unpin') {
const pinned = envelope.d as TweetPinEvent;
console.log(`[${pinned.action.toUpperCase()}] ${pinned.tweetId}`);
}
return;
}
if (envelope.t === 'account') {
if (envelope.op === 'profile_update') {
const profile = envelope.d as ProfileUpdateEvent;
const actor = profile.actor.handle ?? profile.actor.name ?? 'unknown';
console.log(`[PROFILE] ${actor}`, profile.changes);
} else if (envelope.op === 'follow' || envelope.op === 'unfollow') {
const follow = envelope.d as FollowEvent;
const actor = follow.actor.handle ?? follow.actor.name ?? 'unknown';
const target = follow.target.handle ?? follow.target.name ?? 'unknown';
console.log(`[${follow.kind}] ${actor} -> ${target}`);
}
return;
}
if (envelope.t === 'control' && envelope.op === 'twitter_handles_result') {
const payload = envelope.d as TwitterHandlesResult;
console.log('[HANDLES RESULT]', payload);
}
};
ws.onclose = (event) => {
console.warn('WebSocket closed', event.code, event.reason);
scheduleReconnect();
};
ws.onerror = (error) => {
console.error('WebSocket error', error);
ws?.close();
};
}
function scheduleReconnect() {
if (reconnectTimer) return;
reconnectTimer = setTimeout(() => {
reconnectTimer = undefined;
connect();
}, 5_000);
}
connect();管理被监控账号
TweetStream 围绕选定账号监控构建。明确维护 watchlist,可以让 feed 足够小,便于交易机器人或提醒路由快速处理。
- 可从控制台或支持的账号管理 API 添加、移除跟踪账号。
- 账号管理命令会返回 control 消息,方便 UI 或 worker 确认变更结果。
- stream 只会发送当前 workspace 配置为监控的账号和过滤器相关事件。
封装格式
所有消息都使用一致的封装结构:
v- 协议版本(始终为 1)t- 消息族:tweet、account 或 controlop- 操作,例如 content、meta、update、delete、pin、unpin、profile_update、follow、unfollow、twitter_handles_resultts- 毫秒级 Unix 时间戳d- 载荷数据(随类型与操作变化)
常见问题
- 认证失败: 确认 API Key 来自有效订阅
- 连接数已达上限: 关闭现有连接或升级套餐
- 没有收到推文: 确认已在控制台跟踪账号;先打印原始消息再过滤;如果用裸用户名比较,请去掉 author.handle 开头的 @
立即开启实时 Twitter WebSocket 提醒
内置 WebSocket 交付、OCR 与代币检测的 Twitter API 替代方案。
开始 TweetStream 试用起价 $199/月 · Basic/Elite 含 3 天试用 · OCR + 代币检测
