Skip to docs content

Tweet metadata, updates, and lifecycle

Replace live metadata snapshots and merge updates by (platform, tweetId), then apply lifecycle operations without replacing stored content.

Run the 5-minute quickstart
Open in chat
Reviewed against product code on September 2, 2026

tweet/meta

A live metadata payload is the latest snapshot for its post. Replace the previous metadata so omitted fields are cleared. History returns the stored enrichment attached to its row. During recovery, use it only when local metadata is empty; do not overwrite a live snapshot.

Tweet metadata type

typescript
type TweetMeta = {
  tweetId: string;
  // Pair with tweetId when merging enrichment. Omitted means twitter on legacy frames.
  platform?: 'twitter' | 'truth_social' | 'binance_square';
  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'>;
    }>;
  };
};

Tweet metadata event

json
{
  "v": 1,
  "t": "tweet",
  "op": "meta",
  "id": "1234567890",
  "ts": 1702500001000,
  "d": {
    "tweetId": "1234567890",
    "platform": "twitter",
    "ocr": {
      "text": "Chart showing SOL breakout at $100"
    },
    "detected": {
      "tokens": [
        {
          "symbol": "SOL",
          "name": "Solana",
          "priceUsd": 98.50,
          "sources": ["text", "ocr"]
        }
      ]
    }
  }
}

tweet/update

Apply each present field to the stored post. A reference in an update replaces the stored reference snapshot.

Tweet update type

typescript
type VerifiedType = 'blue' | 'business' | 'government' | 'verified' | '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' | 'binance_square';
  profileImage?: string;
  url?: string;
  verifiedLabel?: TweetVerifiedLabel;
  verifiedType?: VerifiedType;
};
 
type Media = {
  url: string;
} & (
  | {
      type: 'video';
      // Every video is a progressive MP4. A public still poster is included when available.
      thumbnail?: string;
    }
  | {
      type?: 'image' | 'gif';
      thumbnail?: string;
    }
);
 
type TweetUrl = {
  url: string;
  name?: string;
  tco?: string;
};
 
type TweetMention = {
  handle?: string;
  id?: string;
  name?: string;
};
 
type TweetArticle = {
  description?: string;
  id?: string;
  publishedAt?: number;
  text?: string;
  thumbnail?: string;
  title: string;
  updatedAt?: number;
  url: string;
};
 
type TweetPollChoice = {
  id?: string;
  image?: string;
  label: string;
  votes?: number;
};
 
type TweetPoll = {
  choices: TweetPollChoice[];
  endsAt?: number;
  totalVotes?: number;
  updatedAt?: number;
};
 
type TweetContentKind = 'post' | 'reply' | 'quote' | 'retweet';
 
type TweetReference = {
  article?: TweetArticle;
  type: 'reply' | 'quote' | 'retweet';
  tweetId: string;
  text?: string;
  translatedText?: string;
  author?: TweetAuthor;
  media?: Media[];
  poll?: TweetPoll;
  quoted?: TweetReference;
  subtweet?: TweetReference;
};
 
type TweetContent = {
  tweetId: string;
  kind: TweetContentKind;
  // Original tweet text when the event includes both original and translated text.
  text: string;
  // Translation, present only when available.
  translatedText?: string;
  createdAt: number;
  author: TweetAuthor;
  article?: TweetArticle;
  link?: string;
  media?: Media[];
  mentions?: TweetMention[];
  poll?: TweetPoll;
  receivedAt?: number;
  urls?: TweetUrl[];
  ref?: TweetReference;
};
 
type TweetUpdate = {
  tweetId: string;
  // Pair with tweetId. On legacy frames, fall back to author.platform, then twitter.
  platform?: 'twitter' | 'truth_social' | 'binance_square';
  article?: TweetArticle;
  kind?: TweetContentKind;
  translatedText?: string;
  author?: TweetAuthor;
  media?: Media[];
  mentions?: TweetMention[];
  poll?: TweetPoll;
  receivedAt?: number;
  urls?: TweetUrl[];
  ref?: TweetReference;
} & (
  | {
      text?: string;
      textUpdateType?: never;
    }
  | {
      text: string;
      // Completes an earlier truncated rendering. This is not an edit signal.
      textUpdateType: 'completion';
    }
);

Tweet update event

json
{
  "v": 1,
  "t": "tweet",
  "op": "update",
  "id": "1234567890",
  "ts": 1702500000180,
  "d": {
    "tweetId": "1234567890",
    "platform": "twitter",
    "ref": {
      "type": "reply",
      "tweetId": "1234567880",
      "text": "Mainnet is ready for launch."
    }
  }
}

Recursive reference update

json
{
  "v": 1,
  "t": "tweet",
  "op": "update",
  "id": "1234567890",
  "ts": 1702500000240,
  "d": {
    "tweetId": "1234567890",
    "platform": "twitter",
    "ref": {
      "type": "reply",
      "tweetId": "1234567880",
      "text": "Mainnet is ready for launch.",
      "author": {
        "handle": "@projectteam",
        "name": "Project Team"
      },
      "subtweet": {
        "type": "quote",
        "tweetId": "1234567800",
        "text": "Launch proposal and contract details.",
        "author": {
          "handle": "@projectteam",
          "name": "Project Team"
        }
      }
    }
  }
}

Lifecycle events

Lifecycle operations update a known post and do not replace its stored content.

Tweet lifecycle types

typescript
type VerifiedType = 'blue' | 'business' | 'government' | 'verified' | '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' | 'binance_square';
  profileImage?: string;
  url?: string;
  verifiedLabel?: TweetVerifiedLabel;
  verifiedType?: VerifiedType;
};
 
type Media = {
  url: string;
} & (
  | {
      type: 'video';
      // Every video is a progressive MP4. A public still poster is included when available.
      thumbnail?: string;
    }
  | {
      type?: 'image' | 'gif';
      thumbnail?: string;
    }
);
 
type TweetUrl = {
  url: string;
  name?: string;
  tco?: string;
};
 
type TweetMention = {
  handle?: string;
  id?: string;
  name?: string;
};
 
type TweetArticle = {
  description?: string;
  id?: string;
  publishedAt?: number;
  text?: string;
  thumbnail?: string;
  title: string;
  updatedAt?: number;
  url: string;
};
 
type TweetPollChoice = {
  id?: string;
  image?: string;
  label: string;
  votes?: number;
};
 
type TweetPoll = {
  choices: TweetPollChoice[];
  endsAt?: number;
  totalVotes?: number;
  updatedAt?: number;
};
 
type TweetContentKind = 'post' | 'reply' | 'quote' | 'retweet';
 
type TweetReference = {
  article?: TweetArticle;
  type: 'reply' | 'quote' | 'retweet';
  tweetId: string;
  text?: string;
  translatedText?: string;
  author?: TweetAuthor;
  media?: Media[];
  poll?: TweetPoll;
  quoted?: TweetReference;
  subtweet?: TweetReference;
};
 
type TweetContent = {
  tweetId: string;
  kind: TweetContentKind;
  // Original tweet text when the event includes both original and translated text.
  text: string;
  // Translation, present only when available.
  translatedText?: string;
  createdAt: number;
  author: TweetAuthor;
  article?: TweetArticle;
  link?: string;
  media?: Media[];
  mentions?: TweetMention[];
  poll?: TweetPoll;
  receivedAt?: number;
  urls?: TweetUrl[];
  ref?: TweetReference;
};
 
type TweetDeleteEvent = {
  tweetId: string;
  // On legacy frames, fall back to author.platform, then twitter.
  platform?: 'twitter' | 'truth_social' | 'binance_square';
  eventId?: string;
  deletedAt?: number;
  receivedAt?: number;
  author?: TweetAuthor;
  text?: string;
};
 
type TweetPinEvent = {
  tweetId: string;
  // On legacy frames, fall back to tweet.author.platform or author.platform, then twitter.
  platform?: 'twitter' | 'truth_social' | 'binance_square';
  eventId: string;
  observedAt: number;
  receivedAt?: number;
  action: 'pin';
  author: TweetAuthor;
  text?: string;
  tweet?: TweetContent;
};
 
type TweetUnpinEvent = {
  tweetId: string;
  // On legacy frames, fall back to tweet.author.platform or author.platform, then twitter.
  platform?: 'twitter' | 'truth_social' | 'binance_square';
  eventId: string;
  observedAt: number;
  receivedAt?: number;
  action: 'unpin';
  author: TweetAuthor;
  text?: string;
  tweet?: TweetContent;
};

tweet/delete

Mark the post deleted when this event is observed.

Tweet delete event

json
{
  "v": 1,
  "t": "tweet",
  "op": "delete",
  "id": "tweet-delete",
  "ts": 1772000001060,
  "d": {
    "eventId": "delete-1",
    "tweetId": "tweet-delete",
    "platform": "twitter",
    "author": {
      "id": "10228272",
      "handle": "@TeamYouTube"
    },
    "deletedAt": 1772000001040,
    "receivedAt": 1772000001050,
    "text": "deleted"
  }
}

tweet/pin

Mark the post pinned and retain any included post snapshot.

Tweet pin event

json
{
  "v": 1,
  "t": "tweet",
  "op": "pin",
  "id": "tweet-pin",
  "ts": 1772000001060,
  "d": {
    "action": "pin",
    "author": {
      "id": "10228272",
      "handle": "@TeamYouTube"
    },
    "eventId": "pin-1",
    "observedAt": 1772000001060,
    "tweetId": "tweet-pin",
    "platform": "twitter",
    "receivedAt": 1772000001050,
    "text": "pinned"
  }
}

tweet/unpin

Remove the pinned state for the identified post.

Tweet unpin event

json
{
  "v": 1,
  "t": "tweet",
  "op": "unpin",
  "id": "tweet-unpin",
  "ts": 1772000001060,
  "d": {
    "action": "unpin",
    "author": {
      "id": "10228272",
      "handle": "@TeamYouTube"
    },
    "eventId": "unpin-1",
    "observedAt": 1772000001060,
    "tweetId": "tweet-unpin",
    "platform": "twitter",
    "receivedAt": 1772000001050,
    "text": "unpinned"
  }
}