API Reference

Public REST API for 21st News. Read-only access to stories, comments, and users — no authentication required.

Base URL

https://news.21st.dev

All endpoints are public. No API key or authentication is needed. Responses are JSON with a Cache-Control: public, s-maxage=60 header.

Endpoints

Stories

GET/api/v1/news/topTop Stories
GET/api/v1/news/newNew Stories
GET/api/v1/news/bestBest Stories
GET/api/v1/news/showShow Stories
GET/api/v1/news/askAsk Stories

Items

GET/api/v1/news/item/:idGet Item

Users

GET/api/v1/news/user/:usernameGet User

List Endpoints

GEThttps://news.21st.dev/api/v1/news/top

Each list endpoint returns a plain JSON array of up to 500 numeric item IDs. Use the item endpoint to fetch full details for each ID.

EndpointSort
/api/v1/news/topHot rank (trending)
/api/v1/news/newCreation date (newest first)
/api/v1/news/bestScore (all-time highest)
/api/v1/news/showShow 21st posts by hot rank
/api/v1/news/askAsk 21st posts by hot rank

Response

[150, 149, 148, 147, 146, 145, ...]

Example

curl https://news.21st.dev/api/v1/news/top

Get Item

GEThttps://news.21st.dev/api/v1/news/item/:id

Returns a single item — either a story or a comment — by its numeric ID. Stories and comments share the same ID space.

Story Fields

FieldTypeDescription
idnumberUnique item ID
type"story"Always "story"
bystringUsername of the author
timenumberUnix timestamp of creation
titlestringStory title
urlstring?URL for link posts (omitted for text posts)
textstring?Body markdown for text/show/ask posts
scorenumberUpvote count
descendantsnumberTotal comment count
kidsnumber[]IDs of direct child comments, ranked by score

Response

{
  "id": 42,
  "type": "story",
  "by": "serafim",
  "time": 1713000000,
  "title": "Show 21st: A new way to build UIs",
  "url": "https://example.com/article",
  "score": 15,
  "descendants": 3,
  "kids": [43, 44, 47]
}

Comment Fields

FieldTypeDescription
idnumberUnique item ID
type"comment"Always "comment"
bystringUsername of the author
timenumberUnix timestamp of creation
textstringComment body in markdown
parentnumberID of parent item (story or comment)
kidsnumber[]IDs of direct child replies

Response

{
  "id": 43,
  "type": "comment",
  "by": "alice",
  "time": 1713003600,
  "text": "This looks great! How does it handle SSR?",
  "parent": 42,
  "kids": [45, 46]
}

Deleted items return {"id": 42, "type": "story", "deleted": true}

Dead items (flagged/hidden) return {"id": 42, "type": "story", "dead": true}

Example

curl https://news.21st.dev/api/v1/news/item/42

Get User

GEThttps://news.21st.dev/api/v1/news/user/:username

Returns a public user profile by username.

FieldTypeDescription
idstringUsername
creatednumberUnix timestamp of account creation
karmanumberUser's news karma
aboutstringUser bio (empty string if not set)

Response

{
  "id": "serafim",
  "created": 1700000000,
  "karma": 42,
  "about": "Building 21st.dev"
}

Example

curl https://news.21st.dev/api/v1/news/user/serafim

Design Notes

  • The API is modeled after the Hacker News API for maximum compatibility with existing clients and tools.
  • Stories and comments share a single ID namespace — every ID is unique across both types.
  • All responses include Cache-Control: public, s-maxage=60 for edge caching.
  • Hidden and killed items return minimal payloads with dead or deleted flags.
  • Timestamps are Unix seconds (not milliseconds).
  • Text content (text field) is raw Markdown.