Objects
The shapes referenced above, field by field. Types are informal: string[] is an array of strings, A | null may be absent.
Envelope
Present on every event, on the stream, in GET /v1/events and in webhook deliveries.
| Field | Type | Meaning |
|---|---|---|
v | int | Envelope version. 1 today |
t | string | Event type, from the table below |
op | create | update | delete | create, update (enrichment of the same id) or delete |
id | string | Stable identity. Deduplicate on this |
ts | int (ms) | When it happened on X, ms since the epoch. X does not say when a profile changed, a follow or unfollow happened, a verified follower arrived or a post was deleted: for those events it is when we detected it |
sid | string | Stream position for replay; present on the stream and in history |
target.id | string | Numeric X id of the monitored account (for search.match, of the post's author) |
target.screen_name | string | Handle of the monitored account |
target.name | string | The account's display name |
d | object | Type-specific payload |
Tweet payload
The d of tweet.create, tweet.reply, tweet.retweet and tweet.quote, and the base of search.match.
| Field | Type | Meaning |
|---|---|---|
tweet_id | string | The post's id, as a string |
kind | tweet | reply | retweet | quote | What kind of post it is |
text | string | Full text (long posts included) |
lang | string | null | Language X detected |
author | User | The account that posted it, as a full User — the same object as the author of a search.match: handle, name, bio, avatar, banner, counts, verification, location, link and join date. On a thin first frame it is the account as last read; the update carries it as read with the post |
reply_to | Brief+ | null | For replies: the post being replied to — a Brief plus screen_name, tweet_id and user_id of its author |
retweet_of | Brief | null | For reposts: the original post |
quoted | Brief | null | For quotes: the quoted post |
media | string[] | Plain image URLs, one per media item |
media_items | Media[] | Every media item with type, video variants and dimensions |
urls | string[] | Expanded links in the post |
article | Article | null | For posts that link an X Article: the article |
counts | {reply, rt, like, quote, bookmark} | Reply, repost, like, quote and bookmark counts at the time we read it |
views | int | null | View count, when X exposes it |
url | string | Canonical link to the post |
full | bool | false on a first, thin create frame; true once the event carries the whole post |
kind_final | bool | true when kind is settled. false only on a thin first frame whose kind is tweet: the post may still turn out to be a quote, and the update on the same id settles it |
kind_was | tweet | null (update only) | Only on the update that settles a post's kind, and only when the first frame said otherwise: the kind that frame had (tweet for a post that turned out to be a quote) |
edit_of | Brief | null | On tweet.edit: the version this one replaces (its id, and its text and author when we had it) |
Brief
A compact post embedded in another event: the original of a repost, the quoted post, the post being replied to, or a pinned post.
| Field | Type | Meaning |
|---|---|---|
id | string | Post id |
user | string | Author's handle |
name | string | Author's display name |
user_id | string | Author's numeric id |
text | string | Full text |
media | string[] | Plain image URLs |
media_items | Media[] | Media items with type and video variants |
created_ms | int | When it was posted, ms since the epoch |
url | string | Link to the post |
Media
One picture, video or GIF. Videos carry the highest-bitrate MP4 we could find; url is the poster frame.
| Field | Type | Meaning |
|---|---|---|
type | photo | video | animated_gif | Kind of media |
url | string | Image URL, or the poster frame of a video |
expanded_url | string | The post's media page on X |
video_url | string (video) | MP4 URL, highest bitrate available |
bitrate | int (video) | Bitrate of that MP4 |
duration_ms | int (video) | Video length |
width | int | Original width in pixels |
height | int | Original height in pixels |
Article
An X Article (long-form post) that a post links to. The first frame carries title and preview; text is null until the update on the same id brings the full article.
| Field | Type | Meaning |
|---|---|---|
id | string | Article id |
title | string | Title |
preview | string | The opening lines of the article |
text | string | null | Full text, paragraphs separated by blank lines; null in the first frame |
cover | string | null | Cover image URL |
images | string[] | Images inside the article |
url | string | Link to the article on X |
Delete payload
The d of tweet.delete. Only ever sent for a post we had seen and that is now gone. Its ts is when the deletion was detected; the post's own time is in its earlier create frame.
| Field | Type | Meaning |
|---|---|---|
tweet_id | string | The deleted post's id |
url | string | Where it used to be |
Profile change payload
The d of every profile.* event. op is update for these.
| Field | Type | Meaning |
|---|---|---|
field | string | Which profile field changed; the same word as after profile. in the type |
old | any | The previous value |
new | any | The new value |
tweet | Brief (pinned only) | For profile.pinned: the newly pinned post |
old_tweet | Brief (pinned only) | For profile.pinned: the previously pinned post, if we had it |
Follow payload
The d of follow.add, follow.remove and followers.verified.add.
| Field | Type | Meaning |
|---|---|---|
user | User | The other account, as a full User |
Account status payload
The d of account.status. A status is one of active, protected (posts visible to approved followers only), suspended (by X) or unavailable (deactivated, deleted or otherwise not visible). ts is when we detected the change.
| Field | Type | Meaning |
|---|---|---|
old | active | protected | suspended | unavailable | The status before |
new | active | protected | suspended | unavailable | The status now |
reason | string | null | X's own wording, when it gives one (for example Suspended) |
User
A full account profile, as embedded in follow events and in search.match.
| Field | Type | Meaning |
|---|---|---|
id | string | Numeric id |
screen_name | string | Handle |
name | string | Display name |
bio | string | Bio text |
avatar | string | Avatar image URL |
banner | string | null | Banner image URL |
followers | int | Follower count |
following | int | Following count |
tweets | int | Post count |
location | string | Free-text location |
url | string | null | Expanded profile link |
verified | bool | Has a verification badge |
verified_type | string | null | blue, business, government or null |
protected | bool | Posts are visible to approved followers only |
created_at | string (ISO-8601) | When the account was created |
category | string | null | Professional category, if the account set one |
Search match payload
The d of search.match: a Tweet payload plus three fields about the match. The envelope's target is the post's author, who need not be one of your targets.
| Field | Type | Meaning |
|---|---|---|
keyword.id | int | Id of the keyword that matched |
keyword.query | string | Its query |
keyword.label | string | null | Its label, if you set one |
author | User | The author's full profile |
author_is_target | bool | true if the author is also an account monitored on this system |
… | TweetPayload | Every field of the Tweet payload |
Target
One account you monitor, as this key sees it.
| Field | Type | Meaning |
|---|---|---|
id | string | Numeric X id. It never changes: key your records on it |
screen_name | string | The current handle. It can change; profile.screen_name tells you when |
name | string | Display name |
previous_screen_names | string[] | Handles the account had before, most recent first. Each still names it in /v1/monitor/targets/{target} |
push_ready | bool | Every event type you subscribe to for this account is being collected in real time. false does not hold anything back: the account is monitored from the moment it is subscribed and its events are delivered as they are collected, so do not wait for this flag before handling them |
last_push_at | datetime | null | Last time a real-time event arrived for it |
last_poll_at | datetime | null | Last time its timeline was read |
state | "subscribed" | Always subscribed here; pending resolutions have their own shape |
event_types | string[] | The event types delivered for this account; empty means every type your key allows |
event_types_all | bool | true when event_types is empty |
Pending target
What GET /v1/monitor/targets/{target} returns while an account you asked for is still being resolved.
| Field | Type | Meaning |
|---|---|---|
screen_name | string | null | The handle you asked for, if you asked by handle |
user_id | string | null | The user id you asked for, if you asked by id |
state | "queued" | Always queued |
queued_at | int (unix s) | When you asked |
event_types | string[] | The event types chosen for it, applied once it is resolved |
event_types_all | bool | true when event_types is empty |
Keyword
One query you watch across X search.
| Field | Type | Meaning |
|---|---|---|
id | int | Numeric id; use it to delete |
query | string | The query, in X search syntax |
label | string | null | Your label, echoed in every match |
active | bool | false if the operator paused it |
hits | int | Matches delivered so far |
last_hit_at | datetime | null | Last match |
last_run_at | datetime | null | Last search |
Account
What GET /v1/account returns about the key you used.
| Field | Type | Meaning |
|---|---|---|
name | string | The key's name, as issued |
plan | string | Plan preset |
key_id | string | Short id of the key, safe to quote in support requests |
scopes | string[] | Scopes the key holds |
event_types | string[] | Key-wide event-type allow-list, managed by us; empty means all |
event_types_all | bool | true when the filter is empty |
limits.max_targets | int | Monitored-account cap |
limits.max_conns | int | Concurrent WebSocket cap |
limits.max_keywords | int | Keyword cap |
limits.requests_per_minute | int | Request budget per minute |
usage.targets | int | Accounts currently monitored |
usage.keywords | int | Keywords currently watched |
Webhook
What GET /v1/account/webhook returns.
| Field | Type | Meaning |
|---|---|---|
url | string | null | The registered endpoint |
stats | {ok, http_…} | Delivery counters: ok, and one http_<code> per failure status seen |
Meta
Paging information beside every list.
| Field | Type | Meaning |
|---|---|---|
count | int | Items on this page |
has_more | bool | Whether another page exists |
next_cursor | string | null | Pass back as ?cursor=; null at the end |
Batch result
One entry per item sent to POST /v1/monitor/targets:batch, in the same order.
| Field | Type | Meaning |
|---|---|---|
index | int | Position of the item in your request |
status | int | The HTTP status the single-item endpoint would have returned |
data | object (on success) | The single-item response body, on success |
error | {code, message, details?} (on failure) | The usual error object, on failure |
Profile (read)
What GET /v1/users/{screen_name}, /v1/users/by-id/{user_id} and /v1/users/batch return per account.
| Field | Type | Meaning |
|---|---|---|
id | string | Numeric id |
name | string | Display name |
screen_name | string | Handle |
bio | string | Bio text |
location | string | Free-text location |
url | string | null | Profile link |
avatar | string | Avatar image URL |
banner | string | null | Banner image URL |
pinned | string | null | Id of the pinned post |
verified | bool | Has a verification badge |
protected | bool | Posts visible to approved followers only |
followers | int | Follower count |
following | int | Following count |
tweets | int | Post count |
Tweet (read)
A post as returned by the read endpoints. The same information as the Tweet payload, in the flatter shape our parser produces.
| Field | Type | Meaning |
|---|---|---|
id | int | Post id, numeric |
created_ms | int | When it was posted, ms since the epoch |
user_id | int | Author's numeric id |
user | string | Author's handle |
name | string | Author's display name |
text | string | Full text |
lang | string | null | Language X detected |
reply_to | string | null | Handle being replied to |
reply_to_status_id | string | null | Id of the post being replied to |
reply_to_user_id | string | null | Id of the account being replied to |
conversation_id | string | Id of the thread's root post |
is_rt | bool | It is a repost |
rt_of | Brief | null | The original, for reposts |
is_quote | bool | It quotes another post |
quoted | Brief | null | The quoted post |
media | string[] | Plain image URLs |
media_items | Media[] | Media items with type and video variants |
urls | string[] | Expanded links |
views | int | null | View count |
counts | {reply, rt, like, quote, bookmark} | Reply, repost, like, quote and bookmark counts |
article | Article | null | The X Article the post links to, when it does (title, preview, cover, images; the full text is on GET /v1/tweets/{tweet_id}/article) |
edit_of | int | null | For an edited version: the id of the first version, else null |
edit_ids | int[] | Every version's id, oldest first; a post never edited lists only itself |
source | string | null | The client it was posted from, as X gives it (an HTML link, for example Twitter for iPhone) |
User reference
The compact form used in follow-list reads.
| Field | Type | Meaning |
|---|---|---|
id | string | Numeric id |
screen_name | string | Handle |
name | string | Display name |