Marblist API
Raw robotics and AI data, with engagement over time. Build your own feed.
Introduction
The Marblist API gives you everything Marblist reads in robotics and AI, raw: posts, threads, papers, launches and company pages, each with its engagement over time. Build your own feeds, alerts and newsletters on the data ours are made from.
The API is REST over HTTPS. Requests take query parameters (and JSON bodies for POST), and every response is JSON. Times are ISO 8601 in UTC. IDs are the source and its own ID: x:2112630018195276229, reddit:t3_1x83d9r, arxiv:2610.30105.
Get your API key
Leave your email and we'll send you your key.
https://api.marblist.ai/v1
{
"object": "list",
"data": [
{
"id": "x:2112630018195276229",
"source": "x",
"vertical": "robotics",
"tags": [
"launch",
"yc:F26"
],
"...": "..."
}
],
"has_more": true,
"next_cursor": "eyJ0IjoiMjAyNi0xMC0yMFQxOTo0MDoyMVoifQ"
}
Authentication
Send your API key as a bearer token in the Authorization header of every request. Keys start with mbl_live_.
Keep your key secret: anyone who has it can use your quota. Don't put it in a browser or an app you ship; call the API from your server. If a key leaks, write to us and we'll replace it.
A missing or invalid key gets a 401.
curl -G https://api.marblist.ai/v1/posts \
-H "Authorization: Bearer $MARBLIST_API_KEY" \
-d limit=1
import os, requests
API_KEY = os.environ["MARBLIST_API_KEY"]
r = requests.get(
"https://api.marblist.ai/v1/posts",
headers={"Authorization": f"Bearer {API_KEY}"},
params={"limit": "1"},
)
r.raise_for_status()
print(r.json())
const params = new URLSearchParams({ limit: "1" });
const res = await fetch(`https://api.marblist.ai/v1/posts?${params}`, {
headers: {
Authorization: `Bearer ${process.env.MARBLIST_API_KEY}`,
},
});
console.log(await res.json());
Pagination
List endpoints return a page of results and a cursor to the next one. Pass limit (1 to 100, default 25) and, for the next page, the next_cursor you got as cursor. When has_more is false, you have everything.
objectstringlist.dataarrayhas_morebooleannext_cursorstring or nullcursor to get the next page.curl -G https://api.marblist.ai/v1/posts \
-H "Authorization: Bearer $MARBLIST_API_KEY" \
-d vertical=robotics \
-d limit=50 \
-d cursor=eyJ0IjoiMjAyNi0xMC0yMFQxOTo0MDoyMVoifQ
import os, requests
API_KEY = os.environ["MARBLIST_API_KEY"]
r = requests.get(
"https://api.marblist.ai/v1/posts",
headers={"Authorization": f"Bearer {API_KEY}"},
params={
"vertical": "robotics",
"limit": "50",
"cursor": "eyJ0IjoiMjAyNi0xMC0yMFQxOTo0MDoyMVoifQ",
},
)
r.raise_for_status()
print(r.json())
const params = new URLSearchParams({
vertical: "robotics",
limit: "50",
cursor: "eyJ0IjoiMjAyNi0xMC0yMFQxOTo0MDoyMVoifQ",
});
const res = await fetch(`https://api.marblist.ai/v1/posts?${params}`, {
headers: {
Authorization: `Bearer ${process.env.MARBLIST_API_KEY}`,
},
});
console.log(await res.json());
Errors
Errors use HTTP status codes and a JSON body that says what went wrong, and which parameter when there is one.
400invalid_request401authentication_error403permission_error404not_found429rate_limitedRetry-After.500api_error{
"error": {
"type": "invalid_request",
"message": "since must be an ISO 8601 time, like 2026-10-20T00:00:00Z",
"param": "since"
}
}
Rate limits
Limits depend on your plan. Every response says where you stand, and a request over the limit gets a 429 with a Retry-After header in seconds.
X-RateLimit-LimitheaderX-RateLimit-RemainingheaderX-RateLimit-ResetheaderSources
We track the top sources wherever robotics and AI news breaks, and keep everything we read with its engagement over time. Filter by source on any post endpoint.
All sources, averaged over the last 7 days.
xThe top robotics and AI accounts, and the conversations around them.redditThe main robotics and AI communities, threads and comments.youtubeRobotics and AI channels.tiktokRobot builders and makers.instagramRobot builders and makers.arxivRobotics research papers.hfHugging Face's daily papers.webLabs' and robot companies' blogs and news, launch sites, and research data.ycYC's company directory, with each company's founders.The Post object
One item from any source: an X post, a Reddit post or comment, a paper, an article, a video, a launch or a company page. Fields a source doesn't have are null.
idstringsourcestringx, reddit, youtube, arxiv, hf, web, tiktok, instagram or yc.kindstringpost, comment, article, paper, video, launch or company.urlstringauthorobjecthandle, name and followers when the source gives them.posted_attimefirst_seen_attimetitlestring or nulltextstringlinksarraymediaarraytype and url.verticalstring or nullrobotics, ai, or null for both.tagsarraylaunch, funding, yc:<batch>, lab, paper, data-revision.quoted_id, reply_to_idstring or nullquoted_byarraymetricsobjectviews, likes, reposts, replies on X; score and comments on Reddit.rawobject{
"id": "x:2112630018195276229",
"object": "post",
"source": "x",
"kind": "post",
"url": "https://x.com/namaangupta/status/2112630018195276229",
"author": {
"handle": "namaangupta",
"name": "Naman Gupta",
"followers": 580
},
"posted_at": "2026-10-20T19:40:21Z",
"first_seen_at": "2026-10-21T11:40:42Z",
"title": null,
"text": "We're out of stealth! @antropirobotics builds fully autonomous factories for metal parts.\n\nOur goal: US quality, China prices, delivery under 24 hours.\n\nIn 6 months, we built our first factory, started shipping, and turned profitable. All bootstrapped.",
"links": [
"https://t.co/385KqrWWRd",
"https://t.co/3u20hmS0rP"
],
"media": [
{
"type": "video",
"url": "https://video.twimg.com/amplify_video/2112619794449170432/vid/avc1/1920x1080/_t6Puh2-iR_36ij6.mp4",
"width": 1920,
"height": 1080
}
],
"vertical": "robotics",
"tags": [
"launch",
"yc:F26"
],
"quoted_id": null,
"reply_to_id": null,
"quoted_by": [
"x:2112794272592228760"
],
"metrics": {
"views": 44689,
"likes": 954,
"reposts": 84,
"replies": 57
},
"raw": {
"...": "the source's own payload, as we read it"
}
}
Engagement history
Every time we read a post, we keep its numbers, so you can see what took off, and when. A reading has the same metrics as the post's source.
seen_attimeviews, likes, reposts, repliesintegerscore, commentsinteger[
{
"seen_at": "2026-10-21T11:40:42Z",
"views": 26556,
"likes": 517,
"reposts": 51,
"replies": 38
},
{
"seen_at": "2026-10-21T15:36:30Z",
"views": 36369,
"likes": 773,
"reposts": 71,
"replies": 47
},
{
"seen_at": "2026-10-21T22:13:53Z",
"views": 44689,
"likes": 954,
"reposts": 84,
"replies": 57
}
]
The Account object
An account we follow. We review the roster every week.
platform, handlestringnamestring or nullverticalsarrayrobotics, ai, or both.focusstringdedicated (it's what they post about) or adjacent.typestringtierinteger1: the core roster. 2 and 3: watched, and promoted when they matter.statusstringactive, candidate or dormant (silent for 3 months).added_attime{
"object": "account",
"platform": "x",
"handle": "pabbeel",
"name": "Pieter Abbeel",
"verticals": [
"robotics"
],
"focus": "dedicated",
"type": "Researcher",
"tier": 1,
"status": "active",
"added_at": "2026-09-29T20:48:53Z"
}
List posts
GET /v1/posts
Posts from every source, newest first unless you sort them. Combine filters to build your own feed.
Query parameters
sourcestring or listverticalstringrobotics or ai.authorstringqstring"out of stealth".tagstring or listsince, untiltimemin_viewsintegermin_scoreintegersortstringlatest (default), views, or velocity: views gained per hour between the last two readings.limit, cursorcurl -G https://api.marblist.ai/v1/posts \
-H "Authorization: Bearer $MARBLIST_API_KEY" \
-d vertical=robotics \
-d tag=launch \
-d since=2026-10-20T00:00:00Z \
-d sort=velocity
import os, requests
API_KEY = os.environ["MARBLIST_API_KEY"]
r = requests.get(
"https://api.marblist.ai/v1/posts",
headers={"Authorization": f"Bearer {API_KEY}"},
params={
"vertical": "robotics",
"tag": "launch",
"since": "2026-10-20T00:00:00Z",
"sort": "velocity",
},
)
r.raise_for_status()
print(r.json())
const params = new URLSearchParams({
vertical: "robotics",
tag: "launch",
since: "2026-10-20T00:00:00Z",
sort: "velocity",
});
const res = await fetch(`https://api.marblist.ai/v1/posts?${params}`, {
headers: {
Authorization: `Bearer ${process.env.MARBLIST_API_KEY}`,
},
});
console.log(await res.json());
{
"object": "list",
"data": [
{
"id": "x:2112998455383847332",
"object": "post",
"source": "x",
"kind": "post",
"url": "https://x.com/Tesla/status/2112998455383847332",
"author": {
"handle": "tesla",
"name": "Tesla",
"followers": 24925437
},
"posted_at": "2026-10-21T20:04:24Z",
"first_seen_at": "2026-10-21T22:11:23Z",
"text": "Q3 Shareholder Update → https://t.co/u0UcDOuMNa ...",
"vertical": "robotics",
"tags": [],
"metrics": {
"views": 1825474,
"likes": 10683,
"reposts": 1241,
"replies": 407
}
},
{
"id": "x:2112630018195276229",
"object": "post",
"source": "x",
"kind": "post",
"url": "https://x.com/namaangupta/status/2112630018195276229",
"author": {
"handle": "namaangupta",
"name": "Naman Gupta",
"followers": 580
},
"posted_at": "2026-10-20T19:40:21Z",
"first_seen_at": "2026-10-21T11:40:42Z",
"title": null,
"text": "We're out of stealth! @antropirobotics builds fully autonomous factories for metal parts.\n\nOur goal: US quality, China prices, delivery under 24 hours.\n\nIn 6 months, we built our first factory, started shipping, and turned profitable. All bootstrapped.",
"links": [
"https://t.co/385KqrWWRd",
"https://t.co/3u20hmS0rP"
],
"vertical": "robotics",
"tags": [
"launch",
"yc:F26"
],
"quoted_id": null,
"reply_to_id": null,
"quoted_by": [
"x:2112794272592228760"
],
"metrics": {
"views": 44689,
"likes": 954,
"reposts": 84,
"replies": 57
}
}
],
"has_more": true,
"next_cursor": "eyJ0IjoiMjAyNi0xMC0yMFQxOTo0MDoyMVoifQ"
}
Retrieve a post
GET /v1/posts/{id}
One post, with its engagement history when you ask for it.
Path parameters
id requiredstringQuery parameters
includestringhistory adds every reading as history.curl -G https://api.marblist.ai/v1/posts/x:2112630018195276229 \
-H "Authorization: Bearer $MARBLIST_API_KEY" \
-d include=history
import os, requests
API_KEY = os.environ["MARBLIST_API_KEY"]
r = requests.get(
"https://api.marblist.ai/v1/posts/x:2112630018195276229",
headers={"Authorization": f"Bearer {API_KEY}"},
params={"include": "history"},
)
r.raise_for_status()
print(r.json())
const params = new URLSearchParams({ include: "history" });
const res = await fetch(`https://api.marblist.ai/v1/posts/x:2112630018195276229?${params}`, {
headers: {
Authorization: `Bearer ${process.env.MARBLIST_API_KEY}`,
},
});
console.log(await res.json());
{
"id": "x:2112630018195276229",
"object": "post",
"source": "x",
"kind": "post",
"url": "https://x.com/namaangupta/status/2112630018195276229",
"author": {
"handle": "namaangupta",
"name": "Naman Gupta",
"followers": 580
},
"posted_at": "2026-10-20T19:40:21Z",
"first_seen_at": "2026-10-21T11:40:42Z",
"title": null,
"text": "We're out of stealth! @antropirobotics builds fully autonomous factories for metal parts.\n\nOur goal: US quality, China prices, delivery under 24 hours.\n\nIn 6 months, we built our first factory, started shipping, and turned profitable. All bootstrapped.",
"links": [
"https://t.co/385KqrWWRd",
"https://t.co/3u20hmS0rP"
],
"media": [
{
"type": "video",
"url": "https://video.twimg.com/amplify_video/2112619794449170432/vid/avc1/1920x1080/_t6Puh2-iR_36ij6.mp4",
"width": 1920,
"height": 1080
}
],
"vertical": "robotics",
"tags": [
"launch",
"yc:F26"
],
"quoted_id": null,
"reply_to_id": null,
"quoted_by": [
"x:2112794272592228760"
],
"metrics": {
"views": 44689,
"likes": 954,
"reposts": 84,
"replies": 57
},
"history": [
{
"seen_at": "2026-10-21T11:40:42Z",
"views": 26556,
"likes": 517,
"reposts": 51,
"replies": 38
},
{
"seen_at": "2026-10-21T15:36:30Z",
"views": 36369,
"likes": 773,
"reposts": 71,
"replies": 47
},
{
"seen_at": "2026-10-21T22:13:53Z",
"views": 44689,
"likes": 954,
"reposts": 84,
"replies": 57
}
]
}
Post history
GET /v1/posts/{id}/history
Every reading of a post, oldest first: how its views, likes and replies grew.
Path parameters
id requiredstringcurl https://api.marblist.ai/v1/posts/x:2112630018195276229/history \
-H "Authorization: Bearer $MARBLIST_API_KEY"
import os, requests
API_KEY = os.environ["MARBLIST_API_KEY"]
r = requests.get(
"https://api.marblist.ai/v1/posts/x:2112630018195276229/history",
headers={"Authorization": f"Bearer {API_KEY}"},
)
r.raise_for_status()
print(r.json())
const res = await fetch("https://api.marblist.ai/v1/posts/x:2112630018195276229/history", {
headers: {
Authorization: `Bearer ${process.env.MARBLIST_API_KEY}`,
},
});
console.log(await res.json());
{
"object": "list",
"data": [
{
"seen_at": "2026-10-21T11:40:42Z",
"views": 26556,
"likes": 517,
"reposts": 51,
"replies": 38
},
{
"seen_at": "2026-10-21T15:36:30Z",
"views": 36369,
"likes": 773,
"reposts": 71,
"replies": 47
},
{
"seen_at": "2026-10-21T22:13:53Z",
"views": 44689,
"likes": 954,
"reposts": 84,
"replies": 57
}
],
"has_more": false,
"next_cursor": null
}
Retrieve a thread
GET /v1/threads/{id}
A Reddit post and its comments, best first, each with its parent so you can rebuild the tree.
Path parameters
id requiredstringQuery parameters
limit, cursorcurl -G https://api.marblist.ai/v1/threads/reddit:t3_1x83d9r \
-H "Authorization: Bearer $MARBLIST_API_KEY" \
-d limit=3
import os, requests
API_KEY = os.environ["MARBLIST_API_KEY"]
r = requests.get(
"https://api.marblist.ai/v1/threads/reddit:t3_1x83d9r",
headers={"Authorization": f"Bearer {API_KEY}"},
params={"limit": "3"},
)
r.raise_for_status()
print(r.json())
const params = new URLSearchParams({ limit: "3" });
const res = await fetch(`https://api.marblist.ai/v1/threads/reddit:t3_1x83d9r?${params}`, {
headers: {
Authorization: `Bearer ${process.env.MARBLIST_API_KEY}`,
},
});
console.log(await res.json());
{
"id": "reddit:t3_1x83d9r",
"object": "thread",
"source": "reddit",
"subreddit": "accelerate",
"url": "https://www.reddit.com/r/accelerate/comments/1x83d9r/why_is_this_sub_going_crazy_over_a_pr_stunt_with/",
"author": {
"handle": "dangerous-day-2943"
},
"posted_at": "2026-10-17T06:48:18Z",
"title": "Why is this sub going crazy over a PR stunt with an empty shell?",
"metrics": {
"score": 2857,
"comments": 1451
},
"comments": [
{
"id": "reddit:t1_ph9h659",
"parent_id": "reddit:t3_1x83d9r",
"author": {
"handle": "demoevolved"
},
"posted_at": "2026-10-17T07:19:51Z",
"score": 150,
"rank": 1,
"text": "The real issue is the prop they used is not remotely filled out with car parts that's needed to drive around on the road. ..."
},
{
"id": "reddit:t1_pha0suq",
"parent_id": "reddit:t3_1x83d9r",
"author": {
"handle": "hasra23"
},
"posted_at": "2026-10-17T10:07:45Z",
"score": 138,
"rank": 2,
"text": "Imagine being the engineer who has to relay Elon's orders to the rest of the team. ..."
},
{
"id": "reddit:t1_phabnce",
"parent_id": "reddit:t1_pha0suq",
"author": {
"handle": "thinksharpe"
},
"posted_at": "2026-10-17T11:32:11Z",
"score": 143,
"rank": 3,
"text": "...have you never met an engineer in your life?! ..."
}
],
"has_more": true
}
List accounts
GET /v1/accounts
The accounts we follow, to see who's in the roster or to build your own list from it.
Query parameters
platformstringx, youtube, tiktok, instagram and more.verticalstringrobotics or ai.tierinteger1, 2 or 3.statusstringactive (default), candidate or dormant.qstringlimit, cursorcurl -G https://api.marblist.ai/v1/accounts \
-H "Authorization: Bearer $MARBLIST_API_KEY" \
-d platform=x \
-d vertical=robotics \
-d tier=1
import os, requests
API_KEY = os.environ["MARBLIST_API_KEY"]
r = requests.get(
"https://api.marblist.ai/v1/accounts",
headers={"Authorization": f"Bearer {API_KEY}"},
params={
"platform": "x",
"vertical": "robotics",
"tier": "1",
},
)
r.raise_for_status()
print(r.json())
const params = new URLSearchParams({
platform: "x",
vertical: "robotics",
tier: "1",
});
const res = await fetch(`https://api.marblist.ai/v1/accounts?${params}`, {
headers: {
Authorization: `Bearer ${process.env.MARBLIST_API_KEY}`,
},
});
console.log(await res.json());
{
"object": "list",
"data": [
{
"object": "account",
"platform": "x",
"handle": "pabbeel",
"name": "Pieter Abbeel",
"verticals": [
"robotics"
],
"focus": "dedicated",
"type": "Researcher",
"tier": 1,
"status": "active",
"added_at": "2026-09-29T20:48:53Z"
}
],
"has_more": true,
"next_cursor": "eyJoIjoicGFiYmVlbCJ9"
}
Create a feed
POST /v1/feeds
Save a set of filters and a sort as a feed, then read it like a list. Your feed, curated your way.
Body
name requiredstringfilters requiredobjectsortstringlatest, views or velocity.curl -X POST https://api.marblist.ai/v1/feeds \
-H "Authorization: Bearer $MARBLIST_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Humanoid launches",
"filters": {
"vertical": "robotics",
"tag": [
"launch"
],
"q": "humanoid",
"min_views": 10000
},
"sort": "velocity"
}'
import os, requests
API_KEY = os.environ["MARBLIST_API_KEY"]
r = requests.post(
"https://api.marblist.ai/v1/feeds",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"name": "Humanoid launches",
"filters": {
"vertical": "robotics",
"tag": ["launch"],
"q": "humanoid",
"min_views": 10000,
},
"sort": "velocity",
},
)
r.raise_for_status()
print(r.json())
const res = await fetch("https://api.marblist.ai/v1/feeds", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.MARBLIST_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Humanoid launches",
filters: {
vertical: "robotics",
tag: ["launch"],
q: "humanoid",
min_views: 10000,
},
sort: "velocity",
}),
});
console.log(await res.json());
{
"id": "feed_7Hq2xV",
"object": "feed",
"name": "Humanoid launches",
"filters": {
"vertical": "robotics",
"tag": [
"launch"
],
"q": "humanoid",
"min_views": 10000
},
"sort": "velocity",
"created_at": "2026-10-22T23:10:00Z"
}
curl https://api.marblist.ai/v1/feeds \
-H "Authorization: Bearer $MARBLIST_API_KEY"
import os, requests
API_KEY = os.environ["MARBLIST_API_KEY"]
r = requests.get(
"https://api.marblist.ai/v1/feeds",
headers={"Authorization": f"Bearer {API_KEY}"},
)
r.raise_for_status()
print(r.json())
const res = await fetch("https://api.marblist.ai/v1/feeds", {
headers: {
Authorization: `Bearer ${process.env.MARBLIST_API_KEY}`,
},
});
console.log(await res.json());
{
"object": "list",
"data": [
{
"id": "feed_7Hq2xV",
"object": "feed",
"name": "Humanoid launches",
"sort": "velocity",
"created_at": "2026-10-22T23:10:00Z"
}
],
"has_more": false,
"next_cursor": null
}
Read a feed
GET /v1/feeds/{id}/posts
The posts that match a feed, in its sort. Same response as List posts.
Path parameters
id requiredstringcurl -G https://api.marblist.ai/v1/feeds/feed_7Hq2xV/posts \
-H "Authorization: Bearer $MARBLIST_API_KEY" \
-d limit=20
import os, requests
API_KEY = os.environ["MARBLIST_API_KEY"]
r = requests.get(
"https://api.marblist.ai/v1/feeds/feed_7Hq2xV/posts",
headers={"Authorization": f"Bearer {API_KEY}"},
params={"limit": "20"},
)
r.raise_for_status()
print(r.json())
const params = new URLSearchParams({ limit: "20" });
const res = await fetch(`https://api.marblist.ai/v1/feeds/feed_7Hq2xV/posts?${params}`, {
headers: {
Authorization: `Bearer ${process.env.MARBLIST_API_KEY}`,
},
});
console.log(await res.json());
Changelog
- The API reference is published.
Questions, or something you need that isn't here: [email protected]