Skip to main content
This Source is a format, not a site. It reads whatever feed you point it at — RSS 2.0, Atom 1.0 or RDF — and it follows recent news when you give it a search term instead of a URL. You are responsible for the terms of the feeds you point us at.

The entry

Every entry becomes an Article: a title, a URL, a text summary, a publication date, the publisher’s domain, and the feed it came from. Text only. The summary is the feed’s own description or content with markup stripped and capped at 2 000 characters. There is no HTML field: Nephia reads feeds, it does not render them, and a stored HTML blob is a sanitising problem for every consumer downstream.

Identity

An entry’s id is, in order: its guid, then Atom’s id, then its link, then a hash of its title and publication date. The fallback matters — a feed with none of the first three is a real feed, not a broken one, and a poll that cannot tell entries apart would re-emit the whole page every tick.

Coverage

A Watch takes exactly one of feed_url or query. A URL polls that feed; a term follows the news for it. Both at once is not a filtered feed — it is two different requests — so it is rejected with 400. On a news Watch, lang (default en) and country (default US) select an edition, not a filter: they have to agree with each other, and the API assembles the pair for you. Each result names its publisher in source, and its url can be an aggregator redirect rather than the publisher’s own address. A feed_url must be HTTPS, and it is checked the same way a webhook URL is: localhost, literal private addresses, and any hostname that resolves to a private or link-local address are rejected with 400. Bodies over 5 MB are refused, and the fetch times out after 15 s. Interval: 120–86400 seconds. Cap: 20 active Watches per Account. Each tick costs 1 credit, including a tick that finds nothing.

What an event carries

The first tick establishes a silent baseline and emits nothing — a feed’s front page is its whole recent history, and firing fifty webhooks about posts that predate the Watch is not what “watch this blog” means. Later ticks emit article.created.

Conditional GET

Each Watch remembers the ETag and Last-Modified the feed last sent, and sends them back on the next tick. A feed that answers 304 Not Modified costs the tick and nothing else — no parse, no diff, no events. A 304 is not an empty feed: the Watch keeps the entries it already knew about. That distinction is what stops a quiet feed from looking like a feed that lost all its posts, and then re-emitting everything on the tick after.

Finding a feed

Plan 129-E. RSS is the only Source whose criterion is a URL nobody knows by heart, so the console can find one for you. All three routes below write an ordinary feed_url — there is no separate “preset” or “catalog” criterion, and a search created from a chip is indistinguishable from one you pasted a URL into.

Discovery

GET /api/rss/discover?url= reads a page and reports the feeds it declares. If the page declares none, five well-known paths are tried — /feed, /rss.xml, /atom.xml, /feed.xml, /index.xml — and only then: a site that links to its feed is answering the question, and guessing past that answer would be five requests to prove it wrong. At most five candidates come back, each marked declared (the site linked to it) or probed (a path answered and parsed). Costs 1 credit for the run, whatever it takes. This is a dashboard route, not /v1: it reads a host you supply, so it carries the same SSRF guard feed_url does — on the page and on every candidate, because a page can declare a feed on any host it likes.

OPML import

POST /api/rss/opml takes a Feedly, Inoreader or NetNewsWire export, flattens its folders, dedupes by URL, and hands back the feeds that fit in your remaining watch slots — plus, by name, the ones that did not. Up to 200 feeds per file; a larger one is refused rather than truncated, because a half-import that says nothing looks like a whole one. The call creates nothing. The console adds the feeds as ordinary RSS searches, and you save them the way you save any other change.

DEV.to, Medium and App Store reviews

These are feeds, not Sources — deliberately. Their content is articles, article already stores exactly what they carry, and inventing a dev.to Source would add an envelope key for what RSS holds today. The App Store URL is the one worth reading closely: sortby=mostrecent is not optional. Apple’s default order is “most helpful”, which on a review feed means a Watch would re-read the same page forever and never see a new review. Each entry arrives as an article — the review’s title, the reviewer in author, and the star rating among categories.

Errors

A feed that cannot be reached, or that answers with something that is not a feed, is a 503 and is not charged; the Watch reports it in its activity, readable through GET /v1/rss/watches/{id}/activity. A feed_url that is malformed, not HTTPS, or pointed at a private address is rejected with 400 at create time and never fetched.