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’sid 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 search takes exactly one offeedUrl 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.
These are this Source’s own criteria: on the keyword they go in the search’s
overrides.filters (see Keywords).
On a news search, 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 feedUrl 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 to 86400 seconds. At most 20 active RSS searches 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 keyword is not what “watch this blog” means. Later ticks emitarticle.created. webhookUrl is optional: without it the keyword still records every match, readable through GET /v1/keywords/{id}/events in the same shape. See Webhooks.
Conditional GET
Each search remembers theETag 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 search 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
RSS is the only Source whose criterion is a URL nobody knows by heart, so the dashboard can find one for you: paste a site’s address and it reports the feeds the page declares, or import an OPML export from your reader. Both write an ordinaryfeedUrl. There is no separate “preset” or “catalog” criterion, and a search created that way is indistinguishable from one you pasted a URL into. Neither is part of this API.
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 search 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 keyword reports it in its activity, readable throughGET /v1/keywords/{id}/activity. A feedUrl that is malformed, not HTTPS, or pointed at a private address is rejected with 400 at create time and never fetched.