Bluesky API: List recent posts
Lists an account's latest public Bluesky posts, newest first. Replies and reposts are left out unless requested; a repost's time is when the account reposted it.
Unofficial. Not affiliated with or endorsed by Bluesky.
Inputs
Values from the run on Oct 23, 2026, shown under Output.
- Username, required
username Account handle (with or without @) or Bluesky profile link, for example nytimes.com or https://bsky.app/profile/nytimes.com.
@nytimes.com
- Max Results optional
max_results Maximum posts to return, for example 20.
100
Whole number from 1 to 100. Default
20.- Include Replies optional
include_replies Include replies, for example true.
false (default)
True or false.
- Include Reposts optional
include_reposts Include posts reposted by the account, for example true.
true
True or false. Default
false.
Input as JSON
{ "username": "@nytimes.com", "max_results": 100, "include_reposts": true}Output
{ "posts": [ { "text": "In @nytopinion.nytimes.com\n\n“The students are coming for the machine,” Filip Balunovic writes from Serbia in a guest essay. “And, astonishingly, they might win.”", "likes": 10, "quotes": 0, "replies": 0, "reposts": 2, "post_uri": "at://did:plc:eclio37ymobqex2ncko63h4r/app.bsky.feed.post/3myjvntrd332s" , "is_repost": false, "post_link": "https://bsky.app/profile/nytimes.com/post/3myjvntrd332s" , "posted_at": "2026-10-23T09:50:04.785866Z", "image_links": [], "original_author_handle": null }, { "text": "Breaking News: A powerful earthquake in Tibet killed at least 16 people and injured dozens of others, Chinese state media said.", "likes": 18, "quotes": 0, "replies": 1, "reposts": 4, "post_uri": "at://did:plc:eclio37ymobqex2ncko63h4r/app.bsky.feed.post/3myjszyhzj22m" , "is_repost": false, "post_link": "https://bsky.app/profile/nytimes.com/post/3myjszyhzj22m" , "posted_at": "2026-10-23T09:03:11.211873Z", "image_links": [], "original_author_handle": null }, { "text": "DOJ immediately asking the Ninth Circuit to step in on its lawsuit aiming to force California to set aside 20,000 mail ballots. A lower court had set a hearing for next Tuesday to consider its claims.", "likes": 25, "quotes": 0, "replies": 5, "reposts": 7, "post_uri": "at://did:plc:ad4baew4rs5doyjstoi3puem/app.bsky.feed.post/3myj4yufl7223" , "is_repost": true, "post_link": "https://bsky.app/profile/zjmontague.bsky.social/post/3myj4yufl7223" , "posted_at": "2026-10-23T03:46:41.943000Z", "image_links": [], "original_author_handle": "zjmontague.bsky.social" } ]}Code
curl https://api.fous.com/v1/runs \ -H "Authorization: Bearer $FOUS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"method":"bsky.app/list_recent_posts","input":{"username":"@nytimes.com","max_results":100,"include_reposts":true}}' # Save as fous.py, then run: python3 fous.pyimport json, os, timefrom urllib.error import HTTPErrorfrom urllib.request import Request, urlopenAPI = "https://api.fous.com/v1/runs" KEY = os.environ["FOUS_API_KEY"]HEADERS = { "Authorization": f"Bearer {KEY}", "Content-Type": "application/json" ,}def call(url, body=None): data = json.dumps(body).encode() if body else None request = Request(url, data, HEADERS) try: with urlopen(request, timeout=120) as r: return r.status, json.load(r) except HTTPError as error: message = json.load(error)["error"]["message"] raise RuntimeError(message) from errorstatus, run = call(API, { "method": "bsky.app/list_recent_posts" , "input": { "username": "@nytimes.com", "max_results": 100, "include_reposts": True }})# 202: still going after 30 s. Ask again until it ends.while status == 202: time.sleep(2) status, run = call(f"{API}/{run['id']}")print(json.dumps(run["data"], indent=2))// Save as fous.mjs, then run: node fous.mjsconst api = "https://api.fous.com/v1/runs" ;const headers = { Authorization: `Bearer ${process.env.FOUS_API_KEY}`, "Content-Type": "application/json" ,};let response = await fetch(api, { method: "POST", headers, body: JSON.stringify({ "method": "bsky.app/list_recent_posts" , "input": { "username": "@nytimes.com", "max_results": 100, "include_reposts": true } }), signal: AbortSignal.timeout(120_000),});let run = await response.json();// 202: still going after 30 s. Ask again until it ends.while (response.status === 202) { await new Promise((done) => setTimeout(done, 2_000)); response = await fetch(`${api}/${run.id}`, { headers }); run = await response.json();}if (!response.ok) throw new Error(run.error.message);console.log(run.data);# Connect your agent to Fous once, over MCP (Streamable HTTP):# https://api.fous.com/mcp# Set FOUS_API_KEY first: create a key at https://app.fous.com/keys.# Claude Codeclaude mcp add \ --scope user \ --transport http fous https://api.fous.com/mcp \ --header "Authorization: Bearer ${FOUS_API_KEY:?Set FOUS_API_KEY to your Fous API key}"# Codexcodex mcp add fous \ --url https://api.fous.com/mcp \ --bearer-token-env-var FOUS_API_KEY# Cursor, VS Code, Windsurf, Cline and morenpx -y add-mcp https://api.fous.com/mcp -g -n fous \ --header "Authorization: Bearer ${FOUS_API_KEY:?Set FOUS_API_KEY to your Fous API key}"# Then ask your agent:# "Use Fous to run bsky.app/list_recent_posts# with {"username":"@nytimes.com","max_results":100,"include_reposts":true}"Over HTTP, the answer’s data holds the output. A run still going after 30 seconds answers 202 with its id: ask GET /v1/runs/{id} until it ends.
Schema
Input schema
{ "type": "object", "required": [ "username" ], "properties": { "username": { "type": "string", "description": "Account handle (with or without @) or Bluesky profile link, for example nytimes.com or https://bsky.app/profile/nytimes.com." }, "max_results": { "type": "integer", "default": 20, "maximum": 100, "minimum": 1, "description": "Maximum posts to return, for example 20." }, "include_replies": { "type": "boolean", "default": false, "description": "Include replies, for example true." }, "include_reposts": { "type": "boolean", "default": false, "description": "Include posts reposted by the account, for example true." } }}Output schema
{ "type": "object", "required": [ "posts" ], "properties": { "posts": { "type": "array", "items": { "type": "object", "required": [ "text", "posted_at", "likes", "reposts", "replies", "quotes", "is_repost", "original_author_handle", "image_links", "post_link", "post_uri" ], "properties": { "text": { "type": "string" }, "likes": { "type": "integer" }, "quotes": { "type": "integer" }, "replies": { "type": "integer" }, "reposts": { "type": "integer" }, "post_uri": { "type": "string" }, "is_repost": { "type": "boolean" }, "post_link": { "type": "string" }, "posted_at": { "type": "string" }, "image_links": { "type": "array", "items": { "type": "string" } }, "original_author_handle": { "type": [ "string", "null" ] } } } } }}- Price
- 1 credit per completed run (1¢ with pay as you go); failed runs are free.
- Method
bsky.app/list_recent_posts- Returns
- text, time, like/repost/reply/quote counts, repost flag, original author, images, link
Use it from your agent
Give your agent this line. It reads SKILL.md, gets a Fous API key and connects the Fous MCP server. Its run then takes the method bsky.app/list_recent_posts with the inputs above.
Ask your agent
- Show me the latest 10 posts from the account @nytimes.com on Bluesky, newest first
- I need the most recent public posts by bsky.app/profile/techcrunch.com including their like and repost counts
- Pull up the last 15 Bluesky posts from jay.bsky.team, with any replies included
- List the newest posts from the handle washingtonpost.com, and also show the posts they reposted
- Get me 50 recent posts from https://bsky.app/profile/npr.org with the images and links they shared
See more
All Bluesky methodsSearches public Bluesky posts for words, optionally ordered by latest or top and filtered by date, author or language. Search indexing may lag behind new posts.
bsky.app/search_postsLooks up a public Bluesky profile by handle or profile link, including bio, audience counts and join date. A bare name first checks its .bsky.social handle, then the top relevant people-search result.
bsky.app/get_profileLists the latest publicly embeddable posts and reels from an Instagram account, newest first. Without login Instagram may show fewer posts than requested. View counts that are not available are null.
instagram.com/list_recent_postsLists an account's latest public Threads posts, newest first, with text, engagement counts, thumbnails and links. Only posts shown without logging in are returned.
threads.com/list_recent_postsLists a Mastodon account's latest public posts, newest first. Replies and boosts are optional. Private and unlisted posts are left out.
mastodon.social/list_recent_postsLists the latest public articles by a Medium writer or publication (by username, publication name or Medium link), with dates, reading times, claps, member-only labels and tags.
medium.com/list_author_articlesLists recent public posts of a Tumblr blog, optionally only those with a given tag. Private or login-only blogs cannot be read.
tumblr.com/list_blog_postsFinds a Substack newsletter by name or web address and returns its latest public posts with dates, authors, access level and engagement counts.
substack.com/list_newsletter_posts