Payloads, Token Detection & OCR
Complete reference for TweetStream alert data structures and enrichment features
Tweet Lifecycle
For tweet events, TweetStream sends a base content message first, optional update messages, lifecycle messages when observed, and a meta message when enrichment is ready:
content- The tweet text, author, and media (arrives first)update- Optional ref context or URL expansion updatesmeta- Enrichment data: OCR results, detected tokens, markets (arrives shortly after)delete,pin,unpin- Deleted tweet and pinned tweet state changes when observed
Message Families
TweetStream uses one WebSocket envelope format for live events and a separate history response shape for replay:
tweet- tweet envelopes carry content, update, meta, delete, pin, and unpin eventsaccount- account envelopes carry profile_update, follow, and unfollow eventscontrol- control envelopes carry handle-management results such as twitter_handles_result/api/history- the history API returns rows with tweetId, body, time, receivedTime, link, messageType, twitterHandle, twitterId, content, and optional meta
Tweet Content Type
type VerifiedType = 'blue' | 'business' | 'government' | 'none';
type TweetAuthor = {
id?: string;
// Includes a leading @ when present, for example "@elonmusk".
handle?: string;
name?: string;
platform?: 'twitter' | 'truth_social';
profileImage?: string;
followersCount?: number;
verifiedType?: VerifiedType;
};
type Media = {
url: string;
type?: 'image' | 'video' | 'gif';
thumbnail?: string;
};
type TweetContent = {
tweetId: string;
text: string;
createdAt: number;
author: TweetAuthor;
link?: string;
media?: Media[];
ref?: {
type: 'reply' | 'quote' | 'retweet';
tweetId?: string;
text?: string;
author?: TweetAuthor;
media?: Media[];
};
};Truth Social posts use the same tweet content shape. Check author.platform to distinguish them from X/Twitter posts.
Tweet Lifecycle Event Types
Deletes, pins, and unpins use tweet envelopes. Pin events include the observed tweet content when available.
type TweetDeleteEvent = {
tweetId: string;
eventId: string;
deletedAt?: number;
author?: TweetAuthor;
text?: string;
};
type TweetPinEvent = {
tweetId: string;
eventId: string;
observedAt: number;
action: 'pin' | 'unpin';
author: TweetAuthor;
text?: string;
tweet?: TweetContent;
};Account Event Types
Profile updates, follow notifications, and unfollow notifications use the account envelope family and share the richer actor fields shown below:
type AccountEventActor = TweetAuthor & {
banner?: string;
bio?: string;
location?: string;
url?: string;
websiteUrl?: string;
followingCount?: number;
};
type ProfileUpdateEvent = {
kind: 'PROFILE';
eventId: string;
observedAt: number;
actor: AccountEventActor;
changes: {
avatar?: string;
banner?: string;
bio?: string;
handle?: string;
location?: string;
name?: string;
};
previous?: {
avatar?: string;
banner?: string;
bio?: string;
handle?: string;
location?: string;
name?: string;
};
};
type FollowEvent = {
kind: 'FOLLOW' | 'UNFOLLOW';
eventId: string;
observedAt: number;
actor: AccountEventActor;
target: AccountEventActor;
};Tweet Meta Type
The meta payload contains all enrichment data:
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'>;
}>;
};
};History Response Type
Historical replay returns tweet, profile, and follow rows in one response shape with metadata filters echoed back.
type VerifiedType = 'blue' | 'business' | 'government' | 'none';
type TweetAuthor = {
id?: string;
// Includes a leading @ when present, for example "@elonmusk".
handle?: string;
name?: string;
platform?: 'twitter' | 'truth_social';
profileImage?: string;
followersCount?: number;
verifiedType?: VerifiedType;
};
type AccountEventActor = TweetAuthor & {
banner?: string;
bio?: string;
location?: string;
url?: string;
websiteUrl?: string;
followingCount?: number;
};
type ProfileUpdateEvent = {
kind: 'PROFILE';
eventId: string;
observedAt: number;
actor: AccountEventActor;
changes: {
avatar?: string;
banner?: string;
bio?: string;
handle?: string;
location?: string;
name?: string;
};
previous?: {
avatar?: string;
banner?: string;
bio?: string;
handle?: string;
location?: string;
name?: string;
};
};
type FollowEvent = {
kind: 'FOLLOW' | 'UNFOLLOW';
eventId: string;
observedAt: 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';
};
type TweetContent = {
tweetId: string;
text: string;
createdAt: number;
author: TweetAuthor;
link?: string;
media?: HistoryMedia[];
ref?: {
type: 'reply' | 'quote' | 'retweet';
tweetId?: string;
text?: string;
author?: TweetAuthor;
media?: HistoryMedia[];
};
};
type HistoricalContent = TweetContent | ProfileUpdateEvent | FollowEvent;
type HistoricalTweetResponse = {
tweetId: string;
twitterId: string;
twitterHandle: string | null;
body: string;
time: string;
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';
};
};Control Event Type
Handle-management responses use the control envelope family. These results arrive after follow or unfollow commands you send over the WebSocket.
type TwitterHandlesResult = {
action: 'follow' | 'unfollow';
requestId: string | null;
results: Array<{
input: string;
handle?: string;
normalizedHandle?: string;
twitterId?: string;
state: string;
message?: string;
}>;
error: string | null;
};Token Detection
TweetStream automatically detects tokens from multiple sources:
| Source | Examples |
|---|---|
| $TICKER symbols | $BTC, $ETH, $SOL |
| Contract addresses | 0x... (EVM), pump... (Solana) |
| DEX URLs | dexscreener.com, birdeye.so |
| OCR text | Tickers and addresses in images |
OCR Text Extraction
Text is automatically extracted from images attached to tweets. This includes:
- Screenshots of charts and trading terminals
- Images containing token information
- Announcements and promotional graphics
OCR results are included in the meta.ocr.text field and are also scanned for token detection.
Prediction Markets
References to Polymarket markets are detected and enriched with live odds. The detected.prediction array includes:
- Market ID and title
- Current price (probability)
- Direct link to the market
Example: Content Envelope
{
"v": 1,
"t": "tweet",
"op": "content",
"ts": 1702500000000,
"d": {
"tweetId": "1234567890",
"text": "MAKE AMERICA WEALTHY AGAIN!",
"createdAt": 1702500000000,
"author": {
"id": "25073877",
"handle": "@realDonaldTrump",
"name": "Donald J. Trump",
"platform": "truth_social",
"followersCount": 9800000,
"verifiedType": "government"
},
"link": "https://truthsocial.com/@realDonaldTrump/posts/114338322578075372"
}
}Example: Meta Envelope
{
"v": 1,
"t": "tweet",
"op": "meta",
"ts": 1702500001000,
"d": {
"tweetId": "1234567890",
"ocr": {
"text": "Chart showing SOL breakout at $100"
},
"detected": {
"tokens": [
{
"symbol": "SOL",
"name": "Solana",
"priceUsd": 98.50,
"sources": ["text", "ocr"]
}
]
}
}
}Example: Account Envelope
{
"v": 1,
"t": "account",
"op": "profile_update",
"ts": 1744156801000,
"d": {
"kind": "PROFILE",
"eventId": "profile_1",
"observedAt": 1744156800000,
"actor": {
"id": "123",
"handle": "@tracked",
"name": "Tracked Account",
"profileImage": "https://pbs.twimg.com/profile_images/new-avatar_normal.jpg",
"followersCount": 125000,
"followingCount": 321,
"verifiedType": "business",
"websiteUrl": "https://tracked.example",
"location": "New York, NY"
},
"changes": {
"avatar": "https://pbs.twimg.com/profile_images/new-avatar_normal.jpg",
"bio": "Now watching markets 24/7"
},
"previous": {
"avatar": "https://pbs.twimg.com/profile_images/old-avatar_normal.jpg",
"bio": "Old bio"
}
}
}Example: Control Envelope
{
"v": 1,
"t": "control",
"op": "twitter_handles_result",
"ts": 1744156802000,
"d": {
"action": "follow",
"requestId": "req_123",
"results": [
{
"input": "newaccount",
"handle": "@newaccount",
"normalizedHandle": "@newaccount",
"twitterId": "456",
"state": "added",
"message": "Now tracking @newaccount"
}
],
"error": null
}
}Example: History Response
{
"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"
}
}Start real-time Twitter WebSocket alerts today
WebSocket delivery, OCR, and token detection - no infrastructure to build.
Start 3-Day TrialFrom $199/mo · Basic/Elite 3-day trial · OCR + token detection included
