Substack API endpoint
Searches posts across all of Substack and returns the publications that also matched, unlike /substack/publication/posts which searches within a single publication. Set focus_publication_id to additionally receive that one publication's own matching posts in focused_posts alongside the site-wide results.
/substack/searchquery: required search text.page: optional zero-based page, 20 posts per page. Defaults to 0.focus_publication_id: optional numeric publication id. When set,
focused_posts carries that one publication's own matching posts
alongside the site-wide results.focus_limit: optional cap on focused_posts, 1-20. Requires
focus_publication_id.This is the site-wide counterpart to
substack-publication-posts, whose
search parameter is scoped to a single publication.
Post bodies are not returned. Subscriber and subscription fields on
publications[] follow the same rules as
substack-category.
| Field | Filled in, of 20 checked | Values in the sample |
|---|---|---|
| id | 20 | |
| title | 20 | |
| subtitle | 17 | |
| slug | 20 | |
| url | 20 | arnoldkling.substack.com and 19 other hosts |
| type | 20 | |
| audience | 20 | |
| published_at | 20 | 2026-09-16 to 2026-10-13 |
| paywalled | 20 | true in 0 of 20 |
| description | 20 | |
| comment_count | 10 | 1 to 77, median 3 |
| reaction_count | 18 | 1 to 314, median 7 |
| cover_image_url | 15 | substackcdn.com and 2 other hosts |
| Parameter | Type | Required | Default | Description | Example |
|---|---|---|---|---|---|
| query | string | Yes | Search text | artificial intelligence | |
| page | integer | No | Zero-based page, 20 posts per page | ||
| focus_publication_id | integer | No | Numeric publication id whose own matching posts are returned in focused_posts | 6349492 | |
| focus_limit | integer | No | Cap on focused_posts, 1-20. Requires focus_publication_id. | ||
| x-api-key (header) | string | Yes | API key required |
curl -X GET "https://api.crawlora.net/api/v1/substack/search?query=artificial+intelligence&page=1" \ -H "x-api-key: $CRAWLORA_API_KEY"
{
"code": 200,
"data": {
"query": "artificial intelligence",
"page": 0,
"has_more": true,
"posts": [
{
"id": 214198231,
"title": "The State of AI in 2026",
"url": "https://example.substack.com/p/the-state-of-ai-in-2026",
"type": "newsletter",
"audience": "everyone",
"paywalled": false
}
],
"publications": [
{
"id": 6349492,
"name": "SemiAnalysis",
"subdomain": "semianalysis",
"url": "https://semianalysis.substack.com"
}
]
},
"msg": "success"
}Request schema
No body schema
Response schema
#/definitions/substack.searchResponseDoc
| Field | Type | Required | Enum | Bounds | Example | Description |
|---|---|---|---|---|---|---|
| code | integer | No | 200 | |||
| data | substack.SearchResult | No | ||||
| data.focused_posts | array | No | ||||
| data.focused_posts[].audience | string | No | everyone | |||
| data.focused_posts[].comment_count | integer | No | ||||
| data.focused_posts[].cover_image_url | string | No | ||||
| data.focused_posts[].description | string | No | ||||
| data.focused_posts[].id | integer | No | 213613469 | |||
| data.focused_posts[].paywalled | boolean | No | ||||
| data.focused_posts[].published_at | string | No | ||||
| data.focused_posts[].reaction_count | integer | No | ||||
| data.focused_posts[].slug | string | No | ||||
| data.focused_posts[].subtitle | string | No | ||||
| data.focused_posts[].title | string | No | ||||
| data.focused_posts[].type | string | No | newsletter | |||
| data.focused_posts[].url | string | No | ||||
| data.has_more | boolean | No | ||||
| data.page | integer | No | ||||
| data.posts | array | No | ||||
| data.posts[].audience | string | No | everyone | |||
| data.posts[].comment_count | integer | No | ||||
| data.posts[].cover_image_url | string | No | ||||
| data.posts[].description | string | No | ||||
| data.posts[].id | integer | No | 213613469 | |||
| data.posts[].paywalled | boolean | No | ||||
| data.posts[].published_at | string | No | ||||
| data.posts[].reaction_count | integer | No | ||||
| data.posts[].slug | string | No | ||||
| data.posts[].subtitle | string | No | ||||
| data.posts[].title | string | No | ||||
| data.posts[].type | string | No | newsletter | |||
| data.posts[].url | string | No | ||||
| data.publications | array | No | ||||
| data.publications[].author_handle | string | No | ||||
| data.publications[].author_id | integer | No | ||||
| data.publications[].author_name | string | No | Dylan Patel | |||
| data.publications[].custom_domain | string | No | ||||
| data.publications[].explicit | boolean | No | ||||
| data.publications[].hero_text | string | No | ||||
| data.publications[].id | integer | No | 6349492 | |||
| data.publications[].language | string | No | ||||
| data.publications[].logo_url | string | No | ||||
| data.publications[].name | string | No | SemiAnalysis | |||
| data.publications[].payments_enabled | boolean | No | ||||
| data.publications[].subdomain | string | No | semianalysis | |||
| data.publications[].subscribers | substack.SubscriberCounts | No | ||||
| data.publications[].subscribers.follower_count | integer | No | 365727 | |||
| data.publications[].subscribers.paid_rough | string | No | Thousands of paid subscribers | PaidRough and PaidRoughInt are the only paid-subscriber figures Substack publishes, and both are buckets rather than counts. PaidRoughInt is the finer of the two and is always present; PaidTier is the coarser threshold behind the public bestseller badge. | ||
| data.publications[].subscribers.paid_rough_int | integer | No | 1000 | |||
| data.publications[].subscribers.paid_tier | integer | No | 1000 | |||
| data.publications[].subscribers.total | integer | No | 315000 | |||
| data.publications[].subscribers.total_display | string | No | 315K+ | |||
| data.publications[].subscribers.total_hidden | boolean | No | ||||
| data.publications[].subscribers.total_rough | string | No | Hundreds of thousands of subscribers | |||
| data.publications[].subscription | substack.Subscription | No | ||||
| data.publications[].subscription.annual_disabled | boolean | No | ||||
| data.publications[].subscription.app_store_plans | array | No | ||||
| data.publications[].subscription.app_store_plans[].active | boolean | No | ||||
| data.publications[].subscription.app_store_plans[].amount_cents | integer | No | 1400 | |||
| data.publications[].subscription.app_store_plans[].currency | string | No | usd | |||
| data.publications[].subscription.app_store_plans[].display_name | string | No | ||||
| data.publications[].subscription.app_store_plans[].display_price | string | No | $14 | |||
| data.publications[].subscription.app_store_plans[].is_founding | boolean | No | ||||
| data.publications[].subscription.app_store_plans[].period | string | No | month | |||
| data.publications[].subscription.app_store_plans[].sku | string | No | ||||
| data.publications[].subscription.founding_benefits | array | No | ||||
| data.publications[].subscription.founding_plan_name | string | No | Founding Member | |||
| data.publications[].subscription.free_benefits | array | No | ||||
| data.publications[].subscription.free_trial_enabled | boolean | No | ||||
| data.publications[].subscription.group_discount_percent | number | No | 20 | |||
| data.publications[].subscription.monthly_disabled | boolean | No | ||||
| data.publications[].subscription.paid_benefits | array | No | ||||
| data.publications[].subscription.payments_state | string | No | enabled | |||
| data.publications[].subscription.plans | array | No | ||||
| data.publications[].subscription.plans[].active | boolean | No | ||||
| data.publications[].subscription.plans[].amount_cents | integer | No | 5000 | |||
| data.publications[].subscription.plans[].currencies | array | No | ||||
| data.publications[].subscription.plans[].currencies[].amount_cents | integer | No | 900 | |||
| data.publications[].subscription.plans[].currencies[].currency | string | No | eur | |||
| data.publications[].subscription.plans[].currency | string | No | usd | |||
| data.publications[].subscription.plans[].id | string | No | monthly50usd_982ddb86 | |||
| data.publications[].subscription.plans[].interval | string | No | month | |||
| data.publications[].subscription.plans[].interval_count | integer | No | 1 | |||
| data.publications[].subscription.plans[].kind | string | No | monthly | |||
| data.publications[].subscription.plans[].nickname | string | No | $50 a month | |||
| data.publications[].subscription.plans[].trial_period_days | integer | No | ||||
| data.publications[].subscription.pledges_enabled | boolean | No | ||||
| data.publications[].url | string | No | https://semianalysis.substack.com | |||
| data.query | string | No | artificial intelligence | |||
| msg | string | No | success |
| Status | Description | Schema |
|---|---|---|
| 400 | Bad Request | #/definitions/app.Response |
| 429 | Too Many Requests | #/definitions/app.Response |
| 503 | Service Unavailable | #/definitions/app.Response |
Use environment variables for secrets and keep Crawlora API keys server-side.
curl -X GET "https://api.crawlora.net/api/v1/substack/search?query=artificial+intelligence&page=1" \
-H "x-api-key: $CRAWLORA_API_KEY"