Mastodon API: List hashtag posts
Lists the latest public posts for a hashtag on a Mastodon server, newest first. Some servers require login for public timelines.
Unofficial. Not affiliated with or endorsed by Mastodon.
Inputs
Values from the run on Oct 23, 2026, shown under Output.
- Server optional
server Mastodon server to read, such as fosstodon.org. Defaults to mastodon.social.
mastodon.social
Default
mastodon.social.- Hashtag, required
hashtag Hashtag, with or without #, such as climate.
photography
- Max Results optional
max_results Maximum posts to return, such as 20; at most 100.
55
Whole number from 1 to 100. Default
20.
Input as JSON
{ "server": "mastodon.social", "hashtag": "photography", "max_results": 55}Output
{ "posts": [ { "text": "Old San Juan, Puerto Rico\n#People #photography #StreetPhotography #urbanPhotography #SanJuan #PuertoRico", "boosts": 0, "post_id": "117489511436858646", "replies": 0, "post_link": "https://mstdn.social/@alexf24/117489511341283936" , "posted_at": "2026-10-23T09:27:50Z", "favourites": 0, "image_links": [ "https://files.mastodon.social/cache/media_attachments/files/117/489/511/396/699/020/original/82322ba822b3421e.jpg" ], "author_handle": "@alexf24@mstdn.social", "author_display_name": "Alexf24" }, { "text": "📷 A photograph of a Formosan Blue Magpie carrying a coathanger is a finalist in the Wildlife Photographer of the Year competition\nThe photographer, Mary Bell, spent three years observing the birds to capture the image\nhttps://www.nhm.ac.uk/wpy/wpy/gallery/2026-urban-architect?tags=ed.current\n#Taiwa…" , "boosts": 0, "post_id": "117489503438295612", "replies": 1, "post_link": "https://mstdn.social/@davidonformosa/117489503380659682" , "posted_at": "2026-10-23T09:25:49Z", "favourites": 0, "image_links": [], "author_handle": "@davidonformosa@mstdn.social", "author_display_name": "David on Formosa" }, { "text": "#nature #photography #darktable", "boosts": 0, "post_id": "117489485711046508", "replies": 0, "post_link": "https://pixelfed.social/p/noname98571/1019175918547577846" , "posted_at": "2026-10-23T09:21:14Z", "favourites": 0, "image_links": [ "https://files.mastodon.social/cache/media_attachments/files/117/489/485/603/350/942/original/b72fe501671f35cd.jpg" ], "author_handle": "@noname98571@pixelfed.social", "author_display_name": "noname98571" } ]}Code
curl https://api.fous.com/v1/runs \ -H "Authorization: Bearer $FOUS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"method":"mastodon.social/list_hashtag_posts","input":{"server":"mastodon.social","hashtag":"photography","max_results":55}}' # 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": "mastodon.social/list_hashtag_posts" , "input": { "server": "mastodon.social", "hashtag": "photography", "max_results": 55 }})# 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": "mastodon.social/list_hashtag_posts" , "input": { "server": "mastodon.social", "hashtag": "photography", "max_results": 55 } }), 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 mastodon.social/list_hashtag_posts# with {"server":"mastodon.social","hashtag":"photography","max_results":55}"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": [ "hashtag" ], "properties": { "server": { "type": "string", "default": "mastodon.social", "description": "Mastodon server to read, such as fosstodon.org. Defaults to mastodon.social." }, "hashtag": { "type": "string", "minLength": 1, "description": "Hashtag, with or without #, such as climate." }, "max_results": { "type": "integer", "default": 20, "maximum": 100, "minimum": 1, "description": "Maximum posts to return, such as 20; at most 100." } }}Output schema
{ "type": "object", "required": [ "posts" ], "properties": { "posts": { "type": "array", "items": { "type": "object", "required": [ "author_handle", "author_display_name", "text", "posted_at", "boosts", "favourites", "replies", "image_links", "post_id" ], "properties": { "text": { "type": "string", "description": "Post text without markup." }, "boosts": { "type": "integer", "description": "Number of boosts." }, "post_id": { "type": "string", "description": "Post ID on the selected server." }, "replies": { "type": "integer", "description": "Number of replies." }, "post_link": { "type": "string", "description": "Page link for this post." }, "posted_at": { "type": "string", "format": "date-time", "description": "Post time in UTC." }, "favourites": { "type": "integer", "description": "Number of favourites." }, "image_links": { "type": "array", "items": { "type": "string" }, "description": "Links to attached images." }, "author_handle": { "type": "string", "description": "Author handle including server." }, "author_display_name": { "type": "string", "description": "Author display name." } } }, "description": "Latest public posts for the hashtag, newest first." } }}- Price
- 1 credit per completed run (1¢ with pay as you go); failed runs are free.
- Method
mastodon.social/list_hashtag_posts- Returns
- posts with author, text, time, boost, favourite and reply counts, image links and post 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 mastodon.social/list_hashtag_posts with the inputs above.
Ask your agent
- Show me the latest 15 public posts tagged #sourdough on mastodon.social, newest first, with boost and favourite counts.
- What are people posting right now under the hashtag #retrogaming? Give me 25 recent posts with author and post link.
- Pull up the newest posts about #birdwatching from fosstodon.org, including any image links.
- I want to see the last 10 toots tagged with #linuxmint along with how many replies each got.
- Can you list up to 50 recent posts for the hashtag climate, showing text, time posted and the link to each post?
See more
All Mastodon methodsLists 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_postsGets a public Mastodon profile by handle or profile link, with its bio, counts, dates and profile fields. Major servers are read directly. Other servers are looked up through mastodon.social, and their home-server account ID is not available.
mastodon.social/get_profileLists publicly visible TikTok Creative Center trending hashtags by country, time period and industry. Anonymous visitors see at most three rows; rank change and new-entry status are not public and come back null.
ads.tiktok.com/list_trending_hashtagsLists the latest posts from a public Telegram channel preview, with text, posting time, approximate views, edit flag, forwarded source, thumbnails and post links.
t.me/list_channel_postsLists 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_postsLists 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.
bsky.app/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 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_posts