BYTETOOLS

Substack Public Posts API

Undocumented but public Substack endpoint listing a publication's posts as JSON, with titles, dates, reaction counts, word counts and paywall status. Tested example included.

No API key requiredHTTPSFree tier

Endpoint tested and returned HTTP 200 on 21 Aug 2026

What is the Substack Public Posts API?

Every Substack publication serves its post list as JSON at `/api/v1/posts` on its own domain, with no API key. Each post returns its title, subtitle, slug, publication date, audience setting, reaction and comment counts, word count and cover image.

Substack has never shipped a documented public API, but the endpoint its own web front-end calls is open on every publication and needs nothing to read. Point it at any Substack domain — the `*.substack.com` subdomain or a custom domain like the one in the example — and the post list comes back as JSON, ordered newest first.

The metadata is richer than the equivalent RSS feed by a wide margin. `audience` tells you whether a post is public or subscriber-only; `wordcount`, `reactions`, `restacks` and `comment_count` give you engagement figures RSS simply does not carry; `truncated_body_text` provides a preview even for paywalled posts. The obvious caveat is that undocumented means unstable — the field set can change without warning, and Substack's terms govern what you do with the content regardless of how easy it is to fetch. Custom-domain publications redirect off `*.substack.com`, so follow redirects or use the canonical domain directly.

Quick facts

Base URL
https://www.astralcodexten.com/api/v1
Authentication
No API key. Paywalled post bodies stay truncated without a subscriber session; metadata for them is still returned.
Rate limit
No published limit. It backs a live site — keep requests slow and cache results.
Pricing
Free to read. Content remains the publication's copyright.
CORS
Not enabled — call it from your server
Official docs
Read the docs

How to use the Substack Public Posts API

Every request below was executed against the live API on 21 Aug 2026, and the response shown is the real body it returned — not an illustration.

1. List a publication's most recent posts

GET https://www.astralcodexten.com/api/v1/posts?limit=1

curl
curl 'https://www.astralcodexten.com/api/v1/posts?limit=1'
JavaScript (fetch)
const res = await fetch("https://www.astralcodexten.com/api/v1/posts?limit=1");
if (!res.ok) throw new Error(`Request failed: ${res.status}`);
const data = await res.json();
console.log(data);
Python (requests)
import requests

res = requests.get("https://www.astralcodexten.com/api/v1/posts?limit=1", timeout=20)
res.raise_for_status()
print(res.json())
Response — HTTP 200 (truncated)
[
  {
    "audience": "everyone",
    "audience_before_archived": null,
    "canonical_url": "https://www.astralcodexten.com/p/college-ea-meetups-everywhere-call",
    "default_comment_sort": null,
    "editor_v2": false,
    "exempt_from_archive_paywall": false,
    "free_unlock_required": false,
    "id": 212052999,
    "podcast_art_url": null,
    "podcast_duration": null,
    "podcast_preview_upload_id": null,
    "podcast_upload_id": null,
    "podcast_url": null,
    "post_date": "2026-08-20T19:55:39.806Z",
    "updated_at": "2026-08-20T19:58:27.477Z",
    "publication_id": 89120,
    "search_engine_description": null,
    "search_engine_title": null,
    "section_id": null,
    "should_send_free_preview": false,
    "show_guest_bios": true,
    "slug": "college-ea-meetups-everywhere-call",
    "social_title": "College EA Meetups Everywhere",
    "subtitle": "...",
    "teaser_post_eligible": true,
    "title": "College EA Meetups Everywhere: Call For Organizers",
    "type": "newsletter",
    "video_upload_id": null,
    "write_comment_permissions": "everyone",
    "meter_type": "none",
    "live_stream_id": null,
    "is_published": true,
    "restacks": 9,
    "reactions": {
      "❤": 76
    },
    "top_exclusions": [],
    "pins": [],
    "section_pins": [],
    "has_shareable_clips": false,
    "previous_post_slug": "why-im-staying-out-of-the-substack",
    "next_post_slug": null,
    "cover_image": "https://substack-post-media.s3.amazonaws.com/public/images/27645a54-8b36-4494-9413-62d22a675cd7_1999x1268.png",
    "cover_image_is_square": false,
    "cover_image

Parameters

ParameterTypeRequiredDescription
limitqueryOptionalHow many posts to return. Twelve by default; large values are throttled. 1
offsetqueryOptionalHow many posts to skip, for paging back through the archive. 12
sortqueryOptional`new` for reverse-chronological, `top` for most popular. new
(publication)base URLRequiredThe publication's own domain — either `name.substack.com` or its custom domain. https://www.astralcodexten.com

Response fields

(root)array
Posts, newest first. There is no envelope object.
title / subtitle / slugstring
Headline, standfirst and URL slug. Build the post URL from `canonical_url`, which is already absolute.
post_date / updated_atstring
ISO 8601 UTC timestamps for first publication and last edit.
audiencestring
`everyone` for public posts, `only_paid` for subscriber-only. This is how you detect the paywall.
typestring
`newsletter`, `podcast` or `thread` — determines which of the podcast and audio fields are populated.
wordcountinteger
Word count of the full post, present even when the body is truncated.
reactions / reaction_count / restacksobject / integer
Engagement figures. `reactions` is a map keyed by reaction type.
comment_count / child_comment_countinteger
Top-level comments and replies.
truncated_body_textstring
Plain-text preview. For paywalled posts this is all you get.
cover_image / coverImagePalettestring / object
Header image URL and its extracted colour palette.
publishedBylinesarray
Authors, with names, handles and profile images.

What you can build with the Substack Public Posts API

  • Mirror a newsletter's archive into your own site or search index
  • Track publishing cadence and engagement across several publications
  • Build a reading list spanning multiple Substacks in one place
  • Detect which posts are public before linking to them

Common errors and how to fix them

Redirect to a different host

The publication uses a custom domain.

Fix: Follow redirects, or call the canonical domain directly. `*.substack.com` 301s to the custom domain when one is configured.

Body text is cut off

The post is subscriber-only.

Fix: `audience` will read `only_paid`. Metadata and `truncated_body_text` are all that is available without a subscriber session.

Fields disappear after a Substack deploy

The endpoint is undocumented and covered by no compatibility promise.

Fix: Read defensively, treat every field as optional, and do not build anything load-bearing on a specific key.

Requests start failing

You are hitting infrastructure that serves a live site.

Fix: Slow down, cache, and page with `offset` rather than requesting huge limits.

Substack Public Posts API — frequently asked questions

Is there an official Substack API?

No. This endpoint powers Substack's own front-end and is publicly readable, but it is undocumented and unsupported, so treat its stability as a courtesy rather than a guarantee.

Can I read paywalled posts through it?

No. Posts marked `audience: only_paid` return metadata and a truncated preview only. The full body needs a subscriber session.

Which URL do I use for a publication?

Its own domain. `example.substack.com/api/v1/posts` works, and publications on a custom domain redirect there — the example uses a custom domain directly to skip the hop.

Is it legal to use this data?

Reading public metadata is straightforward, but the content is copyright the publication and Substack's terms of service apply. Republishing post bodies is a very different proposition from linking to them.

Tools that pair with this API

Alternatives to Substack Public Posts API

If Substack Public Posts does not fit, these news & open data apis cover similar ground. Every one was called before publishing, and each links to its own reference page with a working curl command and the response it returned.

APIWhat it doesAuthCORSLast verified
Hacker NewsOfficial Hacker News API with no key: top stories, comments, users and live item feeds via Firebase. Extremely stable. Tested curl example and live JSON.No keyYes19 Aug 2026
disease.shFree open disease and health statistics API with no key: global and per-country case data, historical time series and vaccination figures. Tested example.No keyYes19 Aug 2026
Spaceflight NewsFree spaceflight news API with no key: articles, blogs and reports from major space outlets, with search, filtering and pagination. Tested curl example.No keyYes19 Aug 2026
Hacker News Search (Algolia)Free Algolia-powered Hacker News search API with no key: full-text search across all stories and comments with filtering by points, date and author. Tested.No keyYes20 Aug 2026
TagesschauFree German news API with no key: the ARD Tagesschau homepage as structured JSON, with headlines, teaser images in every crop and regional tagging. Tested example included.No keyYes21 Aug 2026
Wikipedia On This DayFree Wikimedia On This Day API with no key: historical events, births, deaths and holidays for any calendar date, with linked Wikipedia articles. Tested.No keyYes20 Aug 2026
All News & Open Data APIs

Substack Public Posts is an independent third-party service and is not affiliated with ByteTools or ByteVancer. Details on this page were verified on 21 Aug 2026; always check the official documentation before relying on this API in production, as terms and limits can change.