Documentation
API reference
One base URL, four endpoints, and a response shape that has not changed since v1 shipped in 2017. There is no v2 planned.
Quickstart
Create a key on the pricing page, export it, and make one request. There is no SDK to install and no onboarding call.
shell
$ export NF_KEY=nf_live_8f2c4b19a0e7 $ curl -sH "Authorization: Bearer $NF_KEY" \ "https://api.neutralfeed.com/v1/feed?limit=1" | jq .items[0].headline "There are ten cloud genera"
Authentication
A bearer token in the Authorization header. Keys are scoped to an environment and may be restricted to a set of channels. There is no OAuth flow, because there is no user data to delegate access to — nothing the API returns belongs to anybody.
header
Authorization: Bearer nf_live_8f2c4b19a0e7
GET /v1/feed
Returns calibrated items. All parameters are optional; with none, you get one item from any channel at the default reading level.
| Parameter | Default | Notes |
|---|---|---|
channel | all | One key or a comma-separated list. |
limit | 1 | 1 to 50. Fetching a batch is one request; fetching them singly is not. |
preset | — | lobby, column, kiosk or ticker. |
reading_level | 9 | 6, 9, 12 or 14. |
units | metric | metric or imperial. Applied server-side. |
locale | en-GB | 41 supported. Affects number formatting as well as text. |
rotation_token | — | Echo back the token from the previous response and you will not see the same item twice inside the window. |
max_novelty | 0.20 | Tighten it if our threshold is too lively for your room. |
The item schema
Every item, on every endpoint, in every delivery method, has this shape.
application/json
{
"id": "met_0088",
"channel": "meteorology",
"headline": "There are ten cloud genera",
"body": "Cirrus, cirrocumulus, cirrostratus, altocumulus, ...",
"calibration": {
"stakes": 0.00,
"controversy": 0.00,
"urgency": 0.00,
"novelty": 0.16
},
"sources": 5,
"citations": [
"WMO-No. 407, International Cloud Atlas, 2017 ed.",
"Howard, L. (1803) On the Modifications of Clouds",
"Met Office Fact Sheet 1: Clouds"
],
"verified": "2026-03-08",
"half_life": "indefinite",
"reading_level": 8,
"duration_s": 20
}
half_life
How long the item can be shown before it should be re-verified. Most are indefinite. A timetable is 1 year. Nothing in the corpus is shorter than a month; if it were, it would be news.
duration_s
How long to leave it on screen, derived from length and reading level. Honour it and the rotation feels considered. Ignore it and it feels like a slideshow.
GET /v1/channels
Returns the six channels with item counts and the date each was last added to. Useful for building a picker; not useful for much else, as the list changes about once every four years.
Streaming
GET /v1/stream holds the connection open and emits an item on each rotation, so a display that runs for six months makes one request rather than six hundred thousand.
text/event-stream
event: item
data: {"id":"inf_2290","headline":"The Falkirk Wheel turns on about 1.5 kilowatt-hours",...}
event: heartbeat
data: {"t":"2026-08-06T09:14:00Z"}
Web component
For pages rather than displays. One script, one element. If the network is unavailable it renders the last item it saw, and if it has never seen one it renders nothing at all rather than an error.
html
<!-- one script, deferred --> <script src="https://cdn.neutralfeed.com/v1/nf.js" defer></script> <neutral-feed key="nf_pub_2b71c0" channel="infrastructure" preset="lobby"></neutral-feed>
Errors and limits
| Status | Meaning |
|---|---|
200 | Fine. Check X-NF-Stale; if it is 1 you are over quota and this is the last good response rather than a fresh one. |
304 | Nothing has rotated since your If-None-Match. The expected response for most polls. |
401 | Missing or malformed key. |
403 | Key is not scoped to the requested channel. |
422 | A parameter is out of range. The body names it. |
429 | Burst limit, not the daily quota. Retry after the header says to. |
On exceeding the daily quota
The API does not start returning errors. It returns the most recent successful response with X-NF-Stale: 1. A blank screen in a public room is a worse outcome than a screen showing yesterday's item, and yesterday's item is still true.