跳到文档正文
文档

历史 API

使用 History API 在重连后回补已存内容、资料和关注事件,复盘事故窗口,或对账下游机器人和 Discord 路由。

请求

History 在 Pro 和 Scale 可用。未过滤请求会搜索你的全部活跃监控账号;过滤请求只能包含你当前正在监控的 handles。History 返回已存 `TWEET`、`PROFILE` 和 `FOLLOW` 行;delete、pin、unpin 等生命周期事件通过实时流发送。

参数必填说明
handle, handles, handle[], handles[]单个 handle、重复 handle 或逗号分隔 handles
startDateISO datetime 下界
endDateISO datetime 上界
limit默认 100;最大 1000
typeTWEET、PROFILE 或 FOLLOW。默认 TWEET
获取历史typescript
const response = await fetch(
  "https://api.tweetstream.io/api/history?handles=marketdesk&limit=25&type=TWEET",
  {
    headers: {
      Authorization: `Bearer ${process.env.TWEETSTREAM_API_KEY}`,
    },
  },
);
 
console.log(await response.json());
 

回补窗口

History 按最新结果优先返回,并且每次请求最多 1000 行。对于较大的回放窗口,请按时间范围拆分:请求有界的 `startDate` 和 `endDate`,幂等处理,然后从最旧已处理事件继续推进下一个窗口。重连恢复期间保持实时生命周期 handler 可用,避免把状态变化混进历史内容回放。

响应

结果按最新优先返回,并包含 `metadata.count` 以及请求中的时间边界或 handle 过滤条件。

类型typescript
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 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 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 HistoryMedia = {
  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 HistoryTweetReference = {
  type: 'reply' | 'quote' | 'retweet';
  tweetId?: string;
  text?: string;
  translatedText?: string;
  author?: TweetAuthor;
  media?: HistoryMedia[];
  quoted?: HistoryTweetReference;
};
 
type TweetContent = {
  tweetId: string;
  kind: TweetContentKind;
  // Original tweet text when the stored content includes both original and translated text.
  text: string;
  translatedText?: string;
  createdAt: number;
  author: TweetAuthor;
  link?: string;
  media?: HistoryMedia[];
  mentions?: TweetMention[];
  // Epoch ms from the realtime payload when the stored content includes it.
  receivedAt?: number;
  urls?: TweetUrl[];
  ref?: HistoryTweetReference;
};
 
type HistoricalContent = TweetContent | ProfileUpdateEvent | FollowEvent;
 
type HistoricalTweetResponse = {
  tweetId: string;
  twitterId: string;
  twitterHandle: string | null;
  body: string;
  time: string;
  // ISO persistence receive time for the history row.
  receivedTime: string;
  link: string;
  messageType: 'TWEET' | 'PROFILE' | 'FOLLOW';
  content: HistoricalContent;
  meta?: TweetMeta;
};
 
type HistoryResult = {
  data: HistoricalTweetResponse[];
  metadata: {
    count: number;
    handle?: string;
    handles?: string[];
    startDate?: string;
    endDate?: string;
    type?: 'TWEET' | 'PROFILE' | 'FOLLOW';
  };
};
 
示例json
{
  "data": [
    {
      "tweetId": "follow_1",
      "twitterId": "123",
      "twitterHandle": "tracked",
      "body": "Followed @newaccount",
      "time": "2026-04-09T01:00:00.000Z",
      "receivedTime": "2026-04-09T01:00:00.500Z",
      "link": "https://x.com/newaccount",
      "messageType": "FOLLOW",
      "content": {
        "kind": "FOLLOW",
        "eventId": "follow_1",
        "observedAt": 1744160400000,
        "actor": {
          "id": "123",
          "handle": "tracked",
          "name": "Tracked Account",
          "followersCount": 125000,
          "followingCount": 321,
          "verifiedType": "business"
        },
        "target": {
          "id": "456",
          "handle": "newaccount",
          "name": "New Account",
          "profileImage": "https://pbs.twimg.com/profile_images/newaccount_normal.jpg",
          "websiteUrl": "https://newaccount.example"
        }
      }
    }
  ],
  "metadata": {
    "count": 1,
    "handle": "tracked",
    "handles": ["tracked"],
    "startDate": "2026-04-01T00:00:00.000Z",
    "endDate": "2026-04-30T23:59:59.999Z",
    "type": "FOLLOW"
  }
}
 

错误

状态Body含义
400{ "error": "Invalid query parameters" }日期、limit、type 或 handle 格式错误
400{ "error": "Invalid handle provided", "handle": "..." }Handle 校验失败
400{ "error": "startDate must be before endDate" }日期范围反向
401{ "error": "Missing or invalid API key" }Bearer token 缺失或格式错误
401{ "error": "Invalid API key" }Bearer token 格式正确,但不匹配有效 API key
403{ "error": "This endpoint is only available for Pro and Scale plan users" }套餐不包含 History API
403{ "error": "Your subscription is not active", "message": "Please ensure your subscription is active", "status": "PAST_DUE" }订阅状态不允许使用历史
403{ "error": "Handle ... is not among your tracked accounts" }请求回放的 handle 不在你的监控列表中
429{ "error": "Too many history requests", "retryAfterSeconds": 60 }超过速率限制