All Topics
All Topics
Technology
Technology
Design
Design
Programming
Programming
Science
Science
News
News
Gaming
Gaming
Entertainment
Entertainment
Business
Business
Finance
Finance
Sports
Sports
Health
Health
Food
Food
Travel
Travel
Art
Art
Music
Music
Books
Books
Education
Education
Politics
Politics
Personal
Personal
Bluesky
Twitter
No algorithm. No AI slop. No ads. Just RSS. Pro-human. Indie writers. Real journalism. Open web. Chronological. Hand toasted.

REST API

The FeedBagel API

Hosts, feeds, entries, authors, tags. JSON in, JSON out. Every endpoint requires an API key. Free tier is generous: 120 reads/minute, 50k/day. Build a reader, a directory, a research tool, whatever you fancy.

Get an API keyhttps://api.feedbagel.com

Authentication

Send your key on every request:

Authorization: Bearer fb_…

Missing or invalid key returns 401. Over your rate limit returns 429 with a Retry-After header.

Three ways in

Pull data when you want it, have it pushed to you, or wire it into an AI assistant.

API (pull)
Call the endpoints below with an API key to fetch feeds and articles on demand. Best for readers, directories, and research tools. Get a key.
Webhooks (push)
We POST new entries to your URL as they publish, so you don't poll. No API key is needed to receive: every delivery is signed with your webhook's secret (shown once when you create it) so you can verify it's really us. Add a webhook.
MCP (AI)
Connect FeedBagel to Claude or any MCP client to search and manage feeds from your assistant. MCP setup.

Conventions

Quick rules of the road that apply to every endpoint.

Authentication
None. Send a friendly User-Agent so we can spot you in the logs.
Pagination
page + per_page on every list endpoint. per_page caps at 50 unless noted.
Caching
Most reads cache for 60–300 seconds with stale-while-revalidate. Treat responses as eventually consistent.
Errors
Standard HTTP status codes. Errors return { "error": "...", "message": "..." }.
Slugs
Hosts, feeds, entries and authors all have URL slugs. Prefer slug-based endpoints over numeric IDs for stable links.
Rate limit
Be reasonable. Need high volume? Email [email protected] and we'll sort something out.

MCPagent

Drop the FeedBagel MCP server into any MCP-compatible client (Claude Desktop, Cursor, Zed, custom agents) and the LLM can search feeds, manage follows, and create webhook subscriptions on the user's behalf, all gated by the user's Agent key.

1. Mint an Agent key

Sign up at /dashboard/keys, pick Agent when creating the key, and copy the fb_… token (shown once).

2. Configure your MCP client

Add to your MCP client's config (location varies; see your client's docs):

{
  "mcpServers": {
    "feedbagel": {
      "command": "npx",
      "args": ["-y", "feedbagel-mcp"],
      "env": { "FEEDBAGEL_API_KEY": "fb_…" }
    }
  }
}

3. Use it

Restart your client. The agent now has these tools:

ToolScopeDescription
mereadSmoke test. Returns the account's email + status.
search_feedsreadFind feeds by keyword.
search_feeds_by_urlreadFind feeds at a hostname or URL.
get_host_metadatareadSite info + nested feeds for a host.
list_entriesreadRecent entries across all feeds, paginated.
get_entryreadSingle entry by numeric id.
get_entry_by_slugreadSingle entry by URL slug.
list_subscriptionsreadUnified follows + webhook subscriptions.
list_webhooksreadThe user's webhook subscriptions.
follow_feedwriteBookmark a feed.
unfollow_feedwriteRemove a feed bookmark.
create_webhookwriteSubscribe a URL to feed updates. Returns secret once.
delete_webhookwriteTear down a webhook subscription.
pause_webhookwriteStop deliveries without losing config.
resume_webhookwriteResume a paused subscription.
attach_feed_to_webhookwriteAdd a feed to a webhook's delivery list.
detach_feed_from_webhookwriteRemove a feed from a webhook.

Write tools count against the subscription cap on your account. The server forwards your key to api.feedbagel.com on each call and never stores it.

Feeds8

List, group, and look up feeds. Every feed has a stable slug + activity stats.

GET/api/v1/feeds/list

List all feeds

Paginated flat list of every indexed feed.

Query parameters

NameTypeDefaultDescription
pageinteger1Page number.
per_pageinteger10Items per page (max 50).
sortstringlast_seenlast_seen · title · host · views

Try it

GET /api/v1/feeds/list?page=1&per_page=5&sort=last_seen
Example response shape
{
  "feeds": [
    {
      "id": 42,
      "url": "https://prototypr.io/feed.xml",
      "title": "Prototypr Design Discovery Feed",
      "slug": "main",
      "host": { "host": "prototypr.io", "title": "Prototypr", "slug": "prototypr" }
    }
  ],
  "total_feeds": 5000, "current_page": 1, "per_page": 5
}
GET/api/v1/feeds/group

Feeds grouped by site

Hosts, each with their feeds nested. Best for directory-style pages.

Query parameters

NameTypeDefaultDescription
pageinteger1Page number.
per_pageinteger6Sites per page (max 20).
sortstringlast_seenlast_seen · host · views

Try it

GET /api/v1/feeds/group?page=1&per_page=3&sort=last_seen
Example response shape
{
  "sites": [
    {
      "host": "prototypr.io",
      "title": "Prototypr",
      "slug": "prototypr",
      "feeds": [
        { "url": "https://prototypr.io/feed.xml", "title": "Prototypr Design Discovery Feed", "slug": "main" }
      ]
    }
  ],
  "total_sites": 1200, "current_page": 1, "per_page": 3
}
GET/api/v1/feeds/most-viewed

Most-viewed feeds

Feeds ordered by view count, optionally scoped to a category.

Query parameters

NameTypeDefaultDescription
limitinteger10Max items (max 50).
categorystringOptional category filter.

Try it

GET /api/v1/feeds/most-viewed?limit=5
Example response shape
{
  "feeds": [
    {
      "url": "https://prototypr.io/feed.xml",
      "title": "Prototypr Design Discovery Feed",
      "views_count": 1234,
      "host": { "host": "prototypr.io", "title": "Prototypr", "slug": "prototypr" }
    }
  ]
}
GET/api/v1/tag-feeds

Feeds by tag

Feeds matching a tag, grouped by host with per-feed activity stats (entries_30d, activity_score, activity_histogram_30d, slug, host_slug).

Query parameters

NameTypeDefaultDescription
tagrequiredstringTag name (e.g. technology).
viewstringgroupgroup · list
pageinteger1Page number.
per_pageinteger20Sites per page.

Try it

GET /api/v1/tag-feeds?tag=technology&view=group&page=1&per_page=5
Example response shape
{
  "feeds": [
    {
      "host_title": "A List Apart",
      "host_slug": "a-list-apart",
      "feeds": [
        {
          "url": "https://alistapart.com/feed/",
          "title": "A List Apart",
          "slug": "main",
          "entries_30d": 8,
          "activity_score": 0.42
        }
      ]
    }
  ],
  "meta": { "total_feeds": 1, "current_page": 1, "per_page": 5, "tag": "technology" }
}
GET/api/v1/feed/{feed_id}

Feed by ID

Full record for a single feed, including its host and tags.

Path parameters

NameTypeDefaultDescription
feed_idrequiredintegerNumeric feed ID.

Try it

GET /api/v1/feed/{feed_id}
Fill the required path parameter to run.
Example response shape
{
  "feed": {
    "id": 42,
    "url": "https://example.com/rss.xml",
    "title": "Example",
    "slug": "main",
    "host": { "host": "example.com", "slug": "example" }
  }
}
GET/api/v1/feed-by-slug

Feed by host + slug

Resolve a feed by its host (or host slug) and feed slug. Use this for clean /site/<host>/<slug> URLs.

Query parameters

NameTypeDefaultDescription
hostrequiredstringHost domain or host slug.
slugrequiredstringFeed slug.

Try it

GET /api/v1/feed-by-slug?host=prototypr&slug=main
Example response shape
{ "feed": { "id": 42, "url": "...", "title": "...", "slug": "main" } }
GET/api/v1/direct-feed

Validate or import a feed by URL

Validates the URL, fetches sample entries, and adds the feed to the index if it isn't already there.

Query parameters

NameTypeDefaultDescription
urlrequiredstringA direct feed URL (RSS/Atom/JSON Feed).

Try it

GET /api/v1/direct-feed?url=https%3A%2F%2Fmedium.com%2Ffeed%2Fandroiddevelopers
Example response shape
{
  "feed": { "url": "...", "title": "...", "feed_type": "rss" },
  "entries": [ /* up to 10 sample entries */ ],
  "source": "fetched"
}

Hosts5

Sites that contain feeds. Each host has a slug, favicon, tags, and aggregated activity.

GET/api/v1/hosts

List hosts

Every indexed host with feed count, aggregated entries_30d, activity_score, post_cadence_days, and a 30-day histogram.

Query parameters

NameTypeDefaultDescription
pageinteger1Page number.
per_pageinteger20Hosts per page.
tagstringFilter to hosts that have a feed in this tag.

Try it

GET /api/v1/hosts?page=1&per_page=10
Example response shape
{
  "hosts": [
    {
      "host": "prototypr.io",
      "title": "Prototypr",
      "slug": "prototypr",
      "feed_count": 2,
      "featured": true,
      "entries_30d": 12,
      "post_cadence_days": 4.2
    }
  ],
  "total": 1200, "page": 1, "per_page": 10
}
GET/api/v1/host/{host}/metadata

Host metadata

Full record for a single host, including its nested feeds with activity stats.

Path parameters

NameTypeDefaultDescription
hostrequiredstringHost domain (e.g. medium.com) or host slug.

Try it

GET /api/v1/host/prototypr.io/metadata
Example response shape
{
  "host": "prototypr.io",
  "title": "Prototypr",
  "slug": "prototypr",
  "feeds": [
    { "url": "...", "title": "...", "slug": "main", "entries_30d": 8 }
  ]
}
GET/api/v1/host/title/{host_title}

Host by title

Look up a host by its display title (case-insensitive).

Path parameters

NameTypeDefaultDescription
host_titlerequiredstringURL-encoded title.

Try it

GET /api/v1/host/title/Prototypr
Example response shape
{ "host": { "id": 1, "host": "prototypr.io", "title": "Prototypr" } }
GET/api/v1/host/{host}/tags

Tags on a host

Distinct tags across all feeds for the given host.

Path parameters

NameTypeDefaultDescription
hostrequiredstringHost domain or slug.

Try it

GET /api/v1/host/prototypr.io/tags
Example response shape
{ "tags": ["technology", "design"] }
GET/api/v1/recent_hosts

Recently added hosts

The six most-recently-discovered hosts.

Try it

GET /api/v1/recent_hosts
Example response shape
{ "hosts": [ /* Host[] */ ] }

Entries13

Articles, listings, links, and releases. Read individual posts or browse them by feed, host, or tag. Every endpoint that returns Entry[] shares the object shape shown under “List entries” below.

GET/api/v1/entries

List entries

Paginated stream of entries across every feed. The response below is the full Entry object returned by every entries endpoint (only the most useful fields are shown; internal crawl/rating bookkeeping fields are omitted).

Query parameters

NameTypeDefaultDescription
pageinteger1Page number.
per_pageinteger20Items per page (max 50).
sort_bystringpublishedpublished · updated
sort_orderstringdescasc · desc

Try it

GET /api/v1/entries?page=1&per_page=5&sort_by=published&sort_order=desc
Example response shape
{
  "entries": [
    {
      "id": 57399,
      "title": "What Time Does 'Love Island USA' Season 8 Air?",
      "smart_title": "Love Island USA Season 8 Premieres on Peacock This Week",
      "slug": "what-time-love-island-usa-season-8",
      "url": "https://decider.com/2026/06/01/love-island-usa-season-8/",
      "pretty_link": "decider.com/2026/06/01/love-island-usa-season-8",
      "published": "Mon, 01 Jun 2026 13:00:00 GMT",
      "updated": "Mon, 01 Jun 2026 13:00:10 GMT",
      "author": "Samantha Nungesser",

      // Content
      "description": "A new group of sexy Islanders is heading to Fiji...",
      "smart_summary": "Love Island USA Season 8 premieres on Peacock, hosted by...",
      "reading_time": 3,
      "entry_kind": "article",
      "article_type": "news",
      "detected_language": "en",
      "has_paywall": false,

      // Images & media. thumbnail_url is a cached, low-resolution preview
      // image hosted by FeedBagel, attributed to the source article via
      // image_source_url, and removable on publisher request. We do not
      // serve the publisher's original image.
      "thumbnail_url": "https://images.feedbagel.com/thumb/sm/57399.webp",
      "image_source_url": "https://decider.com/2026/06/01/love-island-usa-season-8/",
      "publisher": "Decider",
      "favicon": "https://decider.com/.../favicon-32x32.png",
      "host_favicon_url": "https://images.feedbagel.com/host/1654/favicon.ico",
      "host_logo_url": "https://images.feedbagel.com/5b0f329b.svg",
      "feed_favicon_url": null,
      "blurhash": "LaJ}b[oL0ejZoLo1ayfQ0eayY5bH",
      "smart_videos": [],
      "links": ["https://decider.com/show/love-island-usa/"],

      // Source. host_domain = the feed's publisher; article_domain = the real
      // destination host parsed from "url" (use it for the article's favicon).
      "host_domain": "decider.com",
      "article_domain": "decider.com",
      "host_id": 1654,
      "host_title": "Decider",
      "feed_id": null,
      "feed_url": "https://decider.com/feed/",
      "feed_title": "Decider",
      "trust_level": 50,

      // Signals
      "tags": ["entertainment"],
      "rating_bagel": 85,          // 0-100 quality score
      "sentiment_label": "positive",
      "ai_processed": true,
      "canonical_entry_id": null   // set when this entry is a duplicate of another
    }
  ],
  "meta": { "total": 312000, "page": 1, "per_page": 5, "total_pages": 62400 }
}
GET/api/v1/entries/ranked

Ranked entries

Entries sorted by FeedBagel's composite ranking (recency × bagel_score × source quality). This is the homepage feed.

Query parameters

NameTypeDefaultDescription
pageinteger1Page number.
per_pageinteger20Items per page.

Try it

GET /api/v1/entries/ranked?page=1&per_page=5
Example response shape
{
  "entries": [
    { "id": 12345, "title": "...", "slug": "introducing-...", "rating_bagel": 85, "host_title": "Example" /* full Entry shape, see "List entries" */ }
  ],
  "total": 1000, "page": 1, "per_page": 5
}
GET/api/v1/entry/slug/{slug}

Entry by slug

Single entry resolved from its URL slug. Powers /post/<slug>.

Path parameters

NameTypeDefaultDescription
slugrequiredstringEntry slug.

Try it

GET /api/v1/entry/slug/{slug}
Fill the required path parameter to run.
Example response shape
{ "entry": { "id": 123, "title": "...", "slug": "...", "url": "..." } }
GET/api/v1/entry/slug/{slug}/related

Related entries

Entries on the same topic as this one (vector similarity, host-diversified).

Path parameters

NameTypeDefaultDescription
slugrequiredstringEntry slug.

Query parameters

NameTypeDefaultDescription
limitinteger6Max items.

Try it

GET /api/v1/entry/slug/{slug}/related?limit=6
Fill the required path parameter to run.
Example response shape
{ "entries": [ /* Entry[] */ ] }
GET/api/v1/entry/slug/{slug}/similar

Similar entries

Pure vector similarity, with no host diversification. Useful for "more like this".

Path parameters

NameTypeDefaultDescription
slugrequiredstringEntry slug.

Query parameters

NameTypeDefaultDescription
limitinteger6Max items.

Try it

GET /api/v1/entry/slug/{slug}/similar?limit=6
Fill the required path parameter to run.
Example response shape
{ "entries": [ /* Entry[] */ ] }
GET/api/v1/entry/slug/{slug}/variants

Entry variants

When the same story is published on multiple sites, FeedBagel canonicalises one and lists the others as variants.

Path parameters

NameTypeDefaultDescription
slugrequiredstringEntry slug.

Try it

GET /api/v1/entry/slug/{slug}/variants
Fill the required path parameter to run.
Example response shape
{ "canonical_id": 100, "is_canonical": true, "canonical_slug": "story-slug", "variants": [ /* Entry[] */ ] }
GET/api/v1/entries/feed/{feed_id}

Entries for a feed

Paginated entries from a single feed.

Path parameters

NameTypeDefaultDescription
feed_idrequiredintegerNumeric feed ID.

Query parameters

NameTypeDefaultDescription
pageinteger1Page number.
per_pageinteger20Items per page.

Try it

GET /api/v1/entries/feed/{feed_id}?page=1&per_page=20
Fill the required path parameter to run.
Example response shape
{ "entries": [ /* Entry[] */ ], "total": 120, "page": 1, "per_page": 20 }
GET/api/v1/entries/host/{host}

Entries from a host

All entries from every feed belonging to a host.

Path parameters

NameTypeDefaultDescription
hostrequiredstringHost domain or slug.

Query parameters

NameTypeDefaultDescription
pageinteger1Page number.
per_pageinteger20Items per page.

Try it

GET /api/v1/entries/host/prototypr.io?page=1&per_page=20
Example response shape
{ "entries": [ /* Entry[] */ ], "total": 8000, "page": 1 }
GET/api/v1/entries/tag/{tag}

Entries for a tag

All entries from feeds tagged with a given topic.

Path parameters

NameTypeDefaultDescription
tagrequiredstringTag name.

Query parameters

NameTypeDefaultDescription
pageinteger1Page number.
per_pageinteger20Items per page.

Try it

GET /api/v1/entries/tag/technology?page=1&per_page=20
Example response shape
{ "entries": [ /* Entry[] */ ], "total": 3000, "page": 1 }
GET/api/v1/entries/slugs

Slug index (sitemap)

Cursor-paginated entry slug list. Used to build the sitemap.

Query parameters

NameTypeDefaultDescription
after_idinteger0Cursor: returns rows with id > after_id.
limitinteger50000Max rows per call (cap 100000).

Try it

GET /api/v1/entries/slugs?after_id=0&limit=10
Example response shape
{
  "slugs": [ { "slug": "story-one", "published": "2026-05-01T..." } ],
  "next_cursor": 12345,
  "limit": 10
}

Authors3

People who write across the indexed feeds. Slug-friendly URLs and per-feed scoping.

GET/api/v1/authors

List authors

Authors ordered by article count, with their dominant entry kind and a URL slug.

Query parameters

NameTypeDefaultDescription
pageinteger1Page number.
per_pageinteger50Items per page (max 100).
discovered0 | 1Only authors whose origin domain isn't yet a tracked host.

Try it

GET /api/v1/authors?page=1&per_page=10
Example response shape
{
  "authors": [
    { "author": "Jane Smith", "author_slug": "jane-smith", "article_count": 42, "kind": "article" }
  ],
  "total": 12000, "page": 1, "per_page": 10
}
GET/api/v1/author/{name_or_slug}

Author detail

Entries by a specific author. Accepts either the raw display name or a URL slug. The slug is resolved server-side.

Path parameters

NameTypeDefaultDescription
name_or_slugrequiredstringURL-encoded name OR a slug like "jane-smith".

Query parameters

NameTypeDefaultDescription
pageinteger1Page number.
per_pageinteger20Items per page.
hoststringScope entries to a specific feed host.
slugstringCombined with host, scopes to a single feed.

Try it

GET /api/v1/author/{name_or_slug}?page=1&per_page=20
Fill the required path parameter to run.
Example response shape
{
  "author": "Jane Smith",
  "author_slug": "jane-smith",
  "entries": [ /* Entry[] */ ],
  "total_entries": 42,
  "feeds": [ { "host_slug": "the-verge", "feed_slug": "main", "feed_title": "The Verge" } ]
}
GET/api/v1/discovered-sources

Discovered source domains

Domains seen as origin sites for aggregator articles, with their feed-discovery status.

Query parameters

NameTypeDefaultDescription
pageinteger1Page number.
per_pageinteger50Items per page (max 100).
has_feeds0 | 1Filter by whether feeds were discovered.
unchecked0 | 1Show only sources we haven't scanned yet.

Try it

GET /api/v1/discovered-sources?page=1&per_page=10
Example response shape
{ "sources": [ { "domain": "...", "feeds_discovered": 2 } ], "total": 800 }

Tags1

Topic taxonomy across feeds.

GET/api/v1/tags

List tags

Every tag with its feed count.

Try it

GET /api/v1/tags
Example response shape
{ "tags": ["technology", "design", "news"], "tag_counts": { "technology": 1240, "design": 380 } }

Stats1

Aggregate counts for the index.

GET/api/v1/feed-stats

Index size

Top-level counts: feeds, sites, entries.

Try it

GET /api/v1/feed-stats
Example response shape
{ "stats": { "feed_count": 4565, "site_count": 1200, "entry_count": 312000 } }

Spotted something off?

The API evolves with the product, so docs occasionally lag the truth. If a field looks wrong or you want a new endpoint, ping [email protected].