Read an X Article

GET /v1/x/posts/{id}/article

Returns the X Article a post carries: title, cover image, and the full body as plain text, Markdown, and X's own blocks (headings, lists, quotes, code, links, images, and embedded posts), with every image and video in it. Pass the id of the post that shares the Article — the number in its x.com/…/status/ link; an x.com/i/article/ link carries the Article's own id, which is not a post id. A post that carries an Article has only a link as its text, so use this, or article on the post, to read it. 404 when the post does not exist or is not an Article.

Price: 1 credit per call, plus 1 credit per X post returned. Failed and refused calls cost nothing.

Rate limit: Counts as 1 request against your per-minute rate limit.

MCP tool: get_x_article, on every MCP connection.

Requires an API key, sent as Authorization: Bearer <key>.

Request

curl --request GET \
  --url https://api.weirapp.io/v1/x/posts/ID/article \
  --header "Authorization: Bearer $WEIR_API_KEY"

Path parameters

Field Type Required Notes
id string yes Numeric post id: the digits after /status/ in a post's URL. · matches ^\d{1,19}$

Response

The Article, with the post and author that carry it.

200

Field Type Required Notes
data object yes
data.id string yes The Article's own id, distinct from the id of the post carrying it.
data.url string yes
data.title string yes
data.previewText string or null yes The opening lines X shows in a feed.
data.coverImage object or null yes
data.coverImage.id string yes X's media id; blocks refer to media by this id.
data.coverImage.type string yes X's own media type names. · photo, video, animated_gif
data.coverImage.url string or null yes The original image for a photo; the highest-bitrate MP4 for a video or GIF. Null when X offers only a stream.
data.coverImage.width integer or null yes
data.coverImage.height integer or null yes
data.publishedAt string or null yes
data.updatedAt string or null yes
data.text string or null yes The full body as plain text. Null in lists of posts, where X sends only the preview: get the post, or its article, for the body.
data.markdown string or null yes The full body as Markdown — headings, emphasis, lists, quotes, code, links, images, and embedded posts — for reading or for a model. Null wherever text is.
data.blocks array of object or null yes The body in X's own block structure. Null wherever text is.
data.blocks[].type string yes X's block type: unstyled (paragraph), header-one, header-two, header-three, unordered-list-item, ordered-list-item, blockquote, code-block, or atomic (an embed: see entities).
data.blocks[].text string yes
data.blocks[].depth integer yes Nesting level for list items; 0 otherwise. · min 0
data.blocks[].styles array of object yes Inline styles over spans of text.
data.blocks[].styles[].offset integer yes Start, in UTF-16 code units of text. · min 0
data.blocks[].styles[].length integer yes min 0
data.blocks[].styles[].style string yes X's inline style name: Bold, Italic, Strikethrough, …
data.blocks[].entities array of object yes Links and embeds attached to spans of text.
data.blocks[].entities[].offset integer yes Start, in UTF-16 code units of text. · min 0
data.blocks[].entities[].length integer yes min 0
data.blocks[].entities[].type string yes X's entity type: LINK, MEDIA, TWEET (an embedded post), DIVIDER, MARKDOWN (a code or formatted snippet), or another X adds later.
data.blocks[].entities[].url string or null yes The target of a LINK.
data.blocks[].entities[].mediaIds array of string yes For MEDIA: ids into the Article's media list, in display order.
data.blocks[].entities[].postId string or null yes For TWEET: the embedded post's id.
data.blocks[].entities[].markdown string or null yes For MARKDOWN: the snippet's source.
data.media array of object yes Images and videos in the body, in order. Empty in lists of posts.
data.media[].id string yes X's media id; blocks refer to media by this id.
data.media[].type string yes X's own media type names. · photo, video, animated_gif
data.media[].url string or null yes The original image for a photo; the highest-bitrate MP4 for a video or GIF. Null when X offers only a stream.
data.media[].width integer or null yes
data.media[].height integer or null yes
data.postId string yes The post that carries the Article.
data.postUrl string yes
data.author object yes
data.author.id string yes
data.author.username string yes
data.author.name string yes
data.author.verified boolean yes
data.author.followersCount integer yes min 0
data.author.profileImageUrl string or null yes
meta object yes
meta.requestId string yes
meta.nextCursor string or null no

Errors

Status Meaning What to do
400 The request failed validation. The request was malformed. The details object names the field.
401 The API key is missing, malformed, expired, or revoked. The key is missing, malformed, revoked, or expired.
402 The account is out of credit. Not retryable: this cannot clear until the billing period resets or the plan changes. Out of credits. Never retry. Only a person can clear it, by adding credits at https://weirapp.io/dashboard/billing. Retrying never will.
403 The API key does not carry the scope this route requires. The key is valid but lacks the scope this operation needs.
404 The requested resource does not exist. No such resource, or it is not public.
429 The per-minute rate limit is exhausted. Retryable: wait for Retry-After and try again. Rate limited. Retryable: wait for Retry-After, then try again.
500 An unexpected error occurred. Something failed on our side. Retryable with backoff.
503 The source is temporarily unavailable. The request is safe to retry. A source was unreachable. Retryable with backoff.

View this page as Markdown