Key Takeaway
X Articles are long-form posts on X (formerly Twitter) that can hold up to 100,000 characters, a cover image, and rich formatting. The official X API does not expose article bodies through standard tweet endpoints, t.co links return an empty wrapper, and the note_tweet field only covers 25,000-character extended posts, not Articles. To pull the full article body, cover image, publication date, and engagement metrics in a single JSON response, you need an endpoint that resolves the article object directly, such as Sorsa's POST /v3/article.
In January 2026, X expanded Articles from a Premium+ exclusive to all Premium subscribers and announced a $1 million monthly prize for the best-performing long-form post on the platform. Predictably, the volume of Articles being published jumped, and so did the number of teams trying to programmatically monitor, archive, or analyze them.
The problem: the official X API was never designed around the Articles object. Hit a long-form post URL through the standard /2/tweets endpoint and you get back a t.co short link in the tweet text, with no body, no cover image, no formatted content. That is the gap this guide covers. We will look at what X Articles actually are, why standard tweet endpoints fail to return them, and how to retrieve full article content via a single REST call. We will also work through two practical use cases in code: benchmarking competitor article performance and running NLP analysis on article bodies. At Sorsa API, we built the /article endpoint specifically because we kept seeing teams burn weeks gluing together Playwright, cookies, and brittle DOM selectors just to extract content that should have been a one-line API call.
Disclosure: Sorsa API is our product. The comparison sections below are honest about what the official X API can and cannot do, but you should always validate any provider against your own workload.
Table of Contents
- What Are X Articles, Exactly?
- Why the Official X API Doesn't Return Article Content
- X Articles vs Long Posts vs Threads: A Comparison
- When Programmatic Access to X Articles Matters
- The Sorsa /article Endpoint Reference
- Quickstart: Fetching an Article
- Detecting Whether a Tweet Is an X Article
- Benchmarking Competitor Articles
- NLP Analysis: Sentiment and Summarization on Article Bodies
- Pricing and Rate Limits
- Getting Started
- FAQ
What Are X Articles, Exactly?
X Articles are a long-form publishing format on X that lets eligible accounts publish formatted, multi-thousand-character pieces directly inside the platform, not as threads or attached files. Think of them as native blog posts: each Article has a cover image, a title, body text with headings, bold, italics, lists, and embedded media, and a separate publication timestamp from the tweet that announces it.
Some hard facts that matter when you build against this format:
- Launched: March 8, 2024, initially limited to Premium+ subscribers and Verified Organizations.
- Expanded: January 7, 2026, X opened Articles to all Premium subscribers, ending the Premium+ exclusivity.
- Maximum length: approximately 100,000 characters, which is roughly 25,000 to 30,000 words. That is novella territory, far beyond what any standard tweet field is designed to carry.
- Distinct surface area on a profile: Articles appear in a dedicated "Articles" tab on the author's profile in addition to the timeline.
- Distinct engagement object: Articles accumulate likes, retweets, replies, quotes, bookmarks, and views, but with engagement patterns that differ noticeably from regular tweets (higher bookmark rates, lower retweet rates).
Having worked with the Twitter API since the v1.1 era, I have watched X gradually layer new content surfaces on top of the original tweet object. Articles are the most extreme example: the announcement tweet is still a tweet, but the actual content lives in a separate object that the public API treats as a second-class citizen.
Why the Official X API Doesn't Return Article Content
If you have ever tried to fetch an X Article through the official API, you have run into the same wall the rest of us have. Here is the precise failure mode.
When an author publishes an Article, X also creates an "announcement tweet" that links to it. That announcement tweet is what shows up in followers' timelines. Hit that tweet ID through the standard X API v2 endpoint:
curl "https://api.twitter.com/2/tweets/{tweet_id}?tweet.fields=text,note_tweet" \
-H "Authorization: Bearer $X_BEARER_TOKEN"
You get back something that looks like this:
{
"data": {
"id": "1234567890",
"text": "Just published a new piece on the state of crypto Twitter in 2026 https://t.co/XYZ123",
"edit_history_tweet_ids": ["1234567890"]
}
}
That t.co link is the entire payload. There is no article body, no cover image, no published_at field, no breakdown of formatting. Follow the t.co URL and you are redirected to https://x.com/i/article/{article_id}, which is a rendered web page, not a JSON endpoint.
People sometimes ask whether the note_tweet field solves this. It does not. note_tweet was added to handle 25,000-character extended posts (the long-form posts feature for Premium users), which are a completely different object from Articles. A note_tweet is still a single text blob with no formatting, no cover image, no separate publication date, and a hard ceiling well below the 100,000-character Article limit.
The community workarounds I have seen in production all involve some form of browser automation. The OpenClaw x-article-extract skill on GitHub, for example, falls back to Playwright with an authenticated cookie just to scrape the article body. The XMCP project does the same. That works, but it is operationally painful: you maintain a headless browser cluster, you rotate cookies before they expire, you handle CAPTCHA challenges, you eat CPU on every fetch, and your latency goes from milliseconds to seconds. For a one-off research project, fine. For a production pipeline, it is a maintenance tax you keep paying forever.
This is exactly the kind of gap that drives teams to look for a Twitter API alternative. The data is public, the access pattern should be a REST call, and yet the official API leaves you reaching for a browser. Sorsa's /article endpoint returns the full article object as JSON in one request, without any of the scraping infrastructure.
X Articles vs Long Posts vs Threads: What Actually Differs
This is a frequent source of confusion. Three distinct long-form mechanisms exist on X, and people often conflate them. Here is how they compare for anyone building data infrastructure around them.
| Feature | Regular Tweet | Long Post (Premium) | X Article |
|---|---|---|---|
| Max length | 280 characters | 25,000 characters | ~100,000 characters |
| Formatting | None | None | Headings, bold, italics, lists, embedded media |
| Cover image | No | No | Yes |
| Separate publication date | No | No | Yes (different from announcement tweet) |
| Dedicated profile tab | No | No | Yes ("Articles" tab) |
| Official X API field | text | note_tweet.text | None directly exposed |
Returned by /2/tweets | Yes, fully | Yes, with tweet.fields=note_tweet | No, only a t.co wrapper |
| Eligibility to publish | All accounts | Premium subscribers | Premium subscribers |
The practical implication for anyone building monitoring or analytics: regular tweets and long posts can be handled through the standard API with caveats. X Articles cannot, period. If you need article bodies, you need a dedicated retrieval method.
When Programmatic Access to X Articles Matters
Articles are not a niche format anymore. Since the Premium expansion in January 2026, the publishing pool grew roughly 4x overnight, and the $1M monthly prize is actively pulling in journalists, thought leaders, and project teams who would previously have posted to Medium or Substack. Here are the use cases where you actually need to fetch article objects, not just their announcement tweets:
Competitive content intelligence. Tracking what competitors publish as long-form content gives you a much clearer view of their messaging strategy than scraping their regular tweet stream. Articles are deliberate, structured, and represent the positions the company actually wants to stake out. Pulling them weekly and diffing the content is a low-effort, high-signal monitoring loop. We have a dedicated competitor analysis guide that walks through this in more detail.
Archiving and content databases. If your team relies on insights from specific authors (analysts, traders, founders), you want a durable archive in case the post gets edited, deleted, or hidden behind a Subscriber-only paywall. The full_text plus published_at plus author fields give you everything needed to build a searchable database. Pair this with the /historical-data capability for older archives.
NLP training and analysis. Articles are some of the cleanest long-form data on the platform. They are written, edited, and intentionally structured, which makes them far better suited for sentiment analysis, topic modeling, or fine-tuning a domain model than the noisy short-tweet stream. We cover the broader pattern in our Twitter sentiment analysis guide.
Engagement benchmarking. Articles have different engagement profiles than tweets. Bookmark rates are higher, retweet rates are lower, view-to-engagement ratios are different. If you benchmark them against regular tweets, your numbers will be misleading. You need to pull article objects separately and analyze them as a distinct content class. This is essentially a specialized form of Twitter analytics.
Journalist and thought-leader monitoring. With X paying out a million dollars a month to top Articles, journalists are publishing there more aggressively. If you run a media monitoring tool, you need article ingestion as a first-class data source, not a scraping afterthought.
The Sorsa /article Endpoint Reference
Sorsa's POST /v3/article endpoint takes a tweet URL or numeric ID and returns the full article object. One request, one JSON response, no browser automation. Full specification lives in the API reference and the X Articles guide.
Request
POST https://api.sorsa.io/v3/article
Content-Type: application/json
ApiKey: YOUR_API_KEY
{
"tweet_link": "https://x.com/SorsaApp/status/1234567890"
}
| Parameter | Type | Required | Description |
|---|---|---|---|
tweet_link | string | Yes | Full tweet URL or numeric tweet ID of the article's announcement tweet. |
Response (200)
{
"full_text": "this isn't a cosmetic rebrand. it's a response to how crypto twitter actually works in 2026...",
"preview_text": "this isn't a cosmetic rebrand. it's a response to how crypto twitter actually works in 2026.\nthe old model was simple...",
"cover_image_url": "https://pbs.twimg.com/media/G-t2hYTaIAAstc8.jpg",
"published_at": "2026-01-15T16:24:02Z",
"views": 36538,
"favorite_count": 315,
"bookmark_count": 38,
"quote_count": 37,
"reply_count": 80,
"retweet_count": 41,
"author": {
"id": "1934538036466810880",
"username": "SorsaApp",
"display_name": "Sorsa",
"description": "Crypto social analytics made simple...",
"followers_count": 6050,
"verified": false
}
}
Response Fields
| Field | Description |
|---|---|
full_text | Complete article body. Can be tens of thousands of characters. |
preview_text | Truncated snippet shown in the timeline before "Read more." |
cover_image_url | URL of the cover image. null if no cover was set. |
published_at | ISO 8601 publication timestamp (distinct from the announcement tweet's created_at). |
views | Total impressions. |
favorite_count | Likes. |
bookmark_count | Bookmarks. |
quote_count | Quote tweets. |
reply_count | Replies. |
retweet_count | Retweets. |
author | Full author profile object. |
Heads up on field names. The article response uses
favorite_countandviews, notlikes_countandview_countlike the standard Tweet object. If you process both tweets and articles through the same pipeline, normalize these keys before pushing them downstream. The response format reference has the full mapping.
Quickstart: Fetching an Article in Two Languages
The simplest curl call:
curl -X POST https://api.sorsa.io/v3/article \
-H "ApiKey: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"tweet_link": "https://x.com/SorsaApp/status/1234567890"}'
A Python client using nothing but requests:
import requests
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.sorsa.io/v3"
def get_article(tweet_link: str) -> dict:
"""Fetch a single X Article by its announcement tweet URL or ID."""
resp = requests.post(
f"{BASE_URL}/article",
headers={
"ApiKey": API_KEY,
"Content-Type": "application/json",
},
json={"tweet_link": tweet_link},
timeout=30,
)
resp.raise_for_status()
return resp.json()
if __name__ == "__main__":
article = get_article("https://x.com/SorsaApp/status/1234567890")
print(f"Author: @{article['author']['username']}")
print(f"Published: {article['published_at']}")
print(f"Views: {article['views']:,}")
print(f"Body length: {len(article['full_text']):,} chars")
print(f"Preview: {article['preview_text'][:120]}...")
That is the entire interaction. No OAuth dance, no developer portal approval, no per-endpoint rate limit, and no Playwright. Authentication is a single header.
Detecting Whether a Tweet Is an X Article
In a real pipeline you rarely have a clean list of "these are article URLs." You have a stream of tweets, some of which are regular posts and some of which are announcement tweets for Articles. You need to route each one correctly.
The cheapest signal is the URL pattern of the announcement tweet itself. Articles get rendered at x.com/i/article/{id}, but the tweet object that announces them is at the usual x.com/{username}/status/{id} path. So URL alone is not enough. The reliable approach is to try the article endpoint first and fall back to the regular tweet endpoint if the response looks degenerate.
import requests
from typing import Literal, TypedDict
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.sorsa.io/v3"
class Content(TypedDict):
type: Literal["article", "tweet"]
data: dict
def get_content(tweet_link: str) -> Content:
"""
Fetch a tweet or article, returning the appropriate object.
Tries /article first. If the response lacks a substantive full_text
(the link did not point to an Article), falls back to /tweet-info.
"""
headers = {"ApiKey": API_KEY, "Content-Type": "application/json"}
try:
resp = requests.post(
f"{BASE_URL}/article",
headers=headers,
json={"tweet_link": tweet_link},
timeout=30,
)
if resp.status_code == 200:
article = resp.json()
# Articles always have substantial body text. A short or
# missing full_text means this was not an Article.
if article.get("full_text") and len(article["full_text"]) > 500:
return {"type": "article", "data": article}
except requests.RequestException:
pass
# Fall back to regular tweet retrieval
resp = requests.post(
f"{BASE_URL}/tweet-info",
headers=headers,
json={"tweet_link": tweet_link},
timeout=30,
)
resp.raise_for_status()
return {"type": "tweet", "data": resp.json()}
# Example: a mixed batch
mixed_links = [
"https://x.com/SorsaApp/status/1234567890", # an Article
"https://x.com/elonmusk/status/9876543210", # a regular tweet
]
for link in mixed_links:
item = get_content(link)
print(f"[{item['type']}] {link}")
The 500-character threshold is a heuristic that works well in practice. If your domain has shorter Articles (rare but possible) you can lower it. If you want to be conservative, also check for the presence of cover_image_url or published_at, which are Article-specific fields.
Benchmarking Competitor Articles
Here is a concrete workflow we use internally when a client asks "how is competitor X performing on long-form content compared to us?" The goal is to pull all known Article announcement tweets from a list of accounts, compute normalized engagement metrics, and rank them.
This example assumes you already have a list of Article URLs (from a watchlist, a /user-tweets scan filtered by URL pattern, or a mentions feed). Building that input list is a separate concern.
import requests
from dataclasses import dataclass
from datetime import datetime, timezone
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.sorsa.io/v3"
@dataclass
class ArticleMetrics:
author: str
published_at: datetime
views: int
favorites: int
bookmarks: int
replies: int
retweets: int
quotes: int
body_length: int
@property
def engagement_rate(self) -> float:
"""Engagement events per 1,000 views."""
if self.views == 0:
return 0.0
total_engagement = (
self.favorites + self.bookmarks + self.replies
+ self.retweets + self.quotes
)
return (total_engagement / self.views) * 1000
@property
def bookmark_rate(self) -> float:
"""Bookmarks per 1,000 views. Strong signal for save-worthy content."""
if self.views == 0:
return 0.0
return (self.bookmarks / self.views) * 1000
def fetch_article_metrics(tweet_link: str) -> ArticleMetrics:
resp = requests.post(
f"{BASE_URL}/article",
headers={"ApiKey": API_KEY, "Content-Type": "application/json"},
json={"tweet_link": tweet_link},
timeout=30,
)
resp.raise_for_status()
a = resp.json()
return ArticleMetrics(
author=a["author"]["username"],
published_at=datetime.fromisoformat(a["published_at"].replace("Z", "+00:00")),
views=a["views"],
favorites=a["favorite_count"],
bookmarks=a["bookmark_count"],
replies=a["reply_count"],
retweets=a["retweet_count"],
quotes=a["quote_count"],
body_length=len(a["full_text"]),
)
def benchmark_articles(article_links: list[str]) -> list[ArticleMetrics]:
"""Pull metrics for a batch of articles and return them sorted by engagement rate."""
results = []
for link in article_links:
try:
results.append(fetch_article_metrics(link))
except requests.HTTPError as e:
print(f"Skipping {link}: {e}")
return sorted(results, key=lambda m: m.engagement_rate, reverse=True)
# Example run
article_links = [
"https://x.com/competitor_a/status/1100000000000000001",
"https://x.com/competitor_b/status/1100000000000000002",
"https://x.com/our_account/status/1100000000000000003",
]
ranked = benchmark_articles(article_links)
print(f"{'Author':<20} {'Views':>10} {'Eng/1k':>8} {'Bookmk/1k':>10} {'Length':>8}")
for m in ranked:
print(
f"@{m.author:<19} {m.views:>10,} {m.engagement_rate:>8.2f} "
f"{m.bookmark_rate:>10.2f} {m.body_length:>8,}"
)
A few notes on what this surfaces that raw tweet metrics will not. Bookmark-per-thousand-views is one of the most underrated signals for Articles specifically. It tracks "I want to come back to this," which correlates strongly with article quality and authority. Regular tweets rarely accumulate meaningful bookmark counts, so this metric only becomes useful once you separate Articles into their own bucket.
The cost of a benchmark over 50 competitor Articles is 50 requests, which is well inside the Starter plan at $49/month and trivial inside Pro. Running this weekly costs less than two hundred requests a month per competitor.
NLP Analysis: Sentiment and Summarization on Article Bodies
The reason Articles are interesting for NLP is that the data is clean. Regular tweets are noisy: misspellings, abbreviations, emojis, sarcasm, missing context, fragmented threads. Articles are written, edited, and structured. You can feed full_text straight into a sentiment model or a summarization model and get useful output without heavy preprocessing.
This example pairs Sorsa for retrieval with OpenAI for the NLP layer. Swap in your preferred model provider, the integration pattern is the same.
import os
import requests
from openai import OpenAI
SORSA_KEY = os.environ["SORSA_API_KEY"]
openai = OpenAI() # reads OPENAI_API_KEY from env
def fetch_article(tweet_link: str) -> dict:
resp = requests.post(
"https://api.sorsa.io/v3/article",
headers={"ApiKey": SORSA_KEY, "Content-Type": "application/json"},
json={"tweet_link": tweet_link},
timeout=30,
)
resp.raise_for_status()
return resp.json()
def analyze_article(article: dict) -> dict:
"""Run sentiment + topic + summary on an article body in one model call."""
prompt = f"""Analyze this X Article. Return a JSON object with:
- sentiment: one of "positive", "negative", "neutral", "mixed"
- sentiment_confidence: float 0.0 to 1.0
- main_topics: list of 3-5 short topic tags (lowercase, hyphenated)
- summary: 2-3 sentence neutral summary
- key_claims: list of 3-5 factual or argumentative claims, verbatim or close paraphrase
Article title cue (preview): {article['preview_text'][:200]}
Article body:
{article['full_text']}
"""
completion = openai.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}],
response_format={"type": "json_object"},
temperature=0.1,
)
import json
return json.loads(completion.choices[0].message.content)
def analyze_article_by_link(tweet_link: str) -> dict:
article = fetch_article(tweet_link)
analysis = analyze_article(article)
return {
"author": article["author"]["username"],
"published_at": article["published_at"],
"views": article["views"],
"body_length": len(article["full_text"]),
**analysis,
}
# Example
result = analyze_article_by_link(
"https://x.com/SorsaApp/status/1234567890"
)
print(result)
# {
# "author": "SorsaApp",
# "published_at": "2026-01-15T16:24:02Z",
# "views": 36538,
# "body_length": 4127,
# "sentiment": "neutral",
# "sentiment_confidence": 0.78,
# "main_topics": ["crypto-twitter", "product-strategy", "rebrand"],
# "summary": "...",
# "key_claims": [...]
# }
For batch workloads, the bottleneck is the LLM call, not the retrieval. Sorsa handles 20 requests per second per API key universally, so you can pull a hundred articles in five seconds, and then the NLP layer becomes your rate limit. For very high throughput, wrap the analyze_article call in an async queue and parallelize against the model provider's concurrency limits.
This pattern works well as a daily cron job over a watchlist of authors. Combine it with real-time monitoring if you need sub-minute detection of new Articles from specific accounts.
Pricing and Rate Limits
Each /article call counts as one request from your monthly quota, regardless of how long the article body is. There is no per-character billing, no surcharge for cover images, and no separate rate limit on this endpoint. A few practical numbers from our internal pricing reference:
| Plan | Monthly requests | Articles you can fetch | Cost per article |
|---|---|---|---|
| Starter ($49) | 10,000 | 10,000 | $0.0049 |
| Pro ($199) | 100,000 | 100,000 | $0.00199 |
| Enterprise ($899) | 500,000 | 500,000 | $0.0018 |
For context, if you want to fetch every X Article published by 200 watchlisted authors once a week, you are probably looking at 800 to 2,000 requests per week (most accounts publish less than one Article per week). That fits comfortably inside Starter with room left for other endpoints. The universal rate limit of 20 requests per second applies, but a single /article call is rarely a bottleneck.
If you are migrating from the official X API, the migration guide walks through field mappings and authentication changes.
Getting Started
The fastest path from zero to a working article fetch:
- Visit the API playground and paste an article tweet URL. You will get the JSON response in your browser without writing any code, useful for verifying the response shape before integrating.
- Pull an API key from your dashboard and follow the quickstart guide.
- Drop the Python snippet above into a Jupyter notebook to confirm the integration.
- For the production pipeline, add error handling, retries on 429, and a persistence layer (the simplest is dumping
full_textplus metadata into Postgres with a unique constraint onpublished_at + author.id).
If you hit a question that this guide does not cover, the API reference has the full specification, and Discord support is responsive.
FAQ
Are X Articles available via the official X API?
Not directly. The official X API does not expose an article-specific endpoint, and the tweet that announces an Article only contains a t.co link in its text field. The note_tweet field handles 25,000-character extended posts, which are a different feature and do not carry article formatting or cover images. To retrieve article bodies programmatically, you either run browser automation against the rendered article page or use a third-party API that resolves the article object directly.
What's the difference between X Articles and Twitter long-form posts?
Long-form posts (also called extended posts) are tweets up to 25,000 characters available to Premium subscribers. They appear inline in the timeline with a "Show more" button, have no separate publication date, no cover image, and no formatting. X Articles are a distinct format that supports up to ~100,000 characters, headings, bold and italic text, embedded media, a cover image, and a separate Articles tab on the author's profile. They are closer to a Substack post than to a tweet.
Can I use an alternative to the official X API to get long-form post data affordably?
Yes. Several providers offer REST access to X data without the official API's pricing and approval process. Sorsa API, for example, has a dedicated /article endpoint that returns full article bodies, cover images, and engagement metrics in one call, with flat per-request pricing starting at $49 a month. The cost of fetching a single article ranges from $0.0018 to $0.0049 depending on the plan, with no per-character surcharge. See our Twitter API alternative breakdown for a fuller comparison.
Do I need OAuth to fetch X Article content?
It depends on the provider. The official X API requires OAuth 2.0 with bearer tokens and an approved developer project, plus your data still won't include article bodies. API-key-based alternatives like Sorsa skip OAuth entirely: you send a single ApiKey header with each request. For a side-by-side, see migration from the official X API.
Why does the article response use favorite_count and views instead of likes_count and view_count?
The article object inherits some legacy naming from X's internal representation, which differs slightly from the standard Tweet object schema. If you process both tweets and articles through the same downstream code, normalize these keys at the edge of your pipeline. The response format documentation has the complete schema comparison.
Can I fetch X Articles published years ago?
Yes, as long as the Article is still public on X. Articles have a permanent URL once published, so any historical Article is retrievable by its announcement tweet URL. If the author later deletes the Article, the tweet endpoint will return a not-found error.
How do I track new X Articles from specific accounts in near real time?
The cleanest pattern is: pull each watchlisted account's recent tweets via /user-tweets on a short polling interval (every few minutes), filter for tweets whose text contains only a t.co link pointing to x.com/i/article/..., and then hit /article to resolve the body. For sub-minute latency across many accounts, real-time monitoring describes the architectural pattern, and rate limits on Sorsa Pro (20 req/s) are typically enough for a watchlist of 500-1,000 accounts on a 5-minute cycle.
Is there an alternative to the official X API with higher rate limits and article support?
For teams that specifically need long-form X content alongside regular tweet data, Sorsa API combines /article with the rest of the read endpoints (search, mentions, followers, communities) at a universal 20 req/s rate limit, 4x the official API's Basic tier price-per-tweet, and no separate approval process. The 38 endpoints share one quota and one rate limit, so adding article retrieval to an existing workflow doesn't require provisioning a separate integration. There's a free API playground for testing without a card on file.
About the Author
Daniel Kolbassen is a data engineer and API infrastructure consultant with 12+ years of experience building data pipelines around social media platforms. He has worked with the Twitter/X API since the v1.1 era and has helped over 40 companies restructure their data infrastructure after the 2023 pricing overhaul. He writes about APIs, scraping, and social data engineering at api.sorsa.io/blog/daniel-kolbassen.
Last verified: May 2026. X Articles is an evolving feature, particularly around the Premium tier expansion and the 2026 $1M prize program. Pricing and rate-limit numbers in this article reflect Sorsa's published plans as of the publication date.