Get this paper as data. Every published story with the facts it cites, plus sections, the archive, search, the front page, the video editions, and a way to sign a reader up. No key. No sign-up.
16 endpointsNo key neededWorks from a browserJSON, UTF-8
Base addresshttps://bainbridgeislandpost.news/api/v1
const r = await fetch("https://bainbridgeislandpost.news/api/v1/stories?limit=5");
const { stories } = await r.json();
for (const s of stories) console.log(s.headline, s.url);
import requests
r = requests.get("https://bainbridgeislandpost.news/api/v1/stories", params={"limit": 5})
for s in r.json()["stories"]:
print(s["headline"], s["url"])
Endpoints
Pick one, fill in the fields, run it. It calls this paper for real, so what you see is what your code will get.
GET/api/v1PUBLIC
A paper's own API index: every door this paper has, as links. Read this first.
Field notes
Names the paper, its landing page, and every endpoint and feed it serves (stories, sections, days, search, the front as JSON, the video editions, RSS, the podcast feed, the agent edition, OpenAPI, subscribe). On a paper's own domain the same tree sits at /api/v1.
Run it to see the response.
MethodGET
KeyNot needed
Fields0
Returnsapplication/json
GET/api/v1/storiesPUBLIC
Every piece a desk has on air, newest first: headline, dek, section, byline, revision, and the story URL.
Field notes
limit clamps to 1-200 (default 50). section narrows to one section as its page shows it (filed there plus tagged there); each section's feeds are /section/{name}/rss.xml and /section/{name}/feed.json on the paper's address. Each row carries id (use it on /stories/{id}), headline, dek, section, byline, rev and url. Only pieces on air appear. Answers for public papers; add a key to read your own desk instead.
Run it to see the response.
MethodGET
KeyNot needed
Fields2
Returnsapplication/json
GET/api/v1/stories/{id}PUBLIC
One piece in full: the prose with its [^N] footnote markers and the numbered cited_facts they reference.
Field notes
prose is the piece as published. cited_facts is the numbered source list: statement, source (publisher), instrument, and claim_key (a pointer into the fact record). A [^N] marker in prose references cited_facts entry N; render them as footnotes, never strip them.
id
- pick a story -
Run it to see the response.
MethodGET
KeyNot needed
Fields1
Returnsapplication/json
GET/api/v1/sectionsPUBLIC
The paper's sections in its own order, each with how many pieces are on air and its page URL.
Field notes
Section names are the strings the stories carry in `category`; pass one to /stories?section= to read only that section, or to the subscribe endpoint to alert a reader on that section only. Each row carries rss and json, the section's own feeds.
Run it to see the response.
MethodGET
KeyNot needed
Fields0
Returnsapplication/json
GET/api/v1/daysPUBLIC
The archive: every day the paper published, newest first, with the count and the back-issue URL.
Field notes
Up to 366 days. Pair with /days/{day} for that edition.
Run it to see the response.
MethodGET
KeyNot needed
Fields0
Returnsapplication/json
GET/api/v1/days/{day}PUBLIC
One day's edition: the pieces that went on air that day.
Field notes
day is YYYY-MM-DD (UTC). Same row shape as /stories.
Run it to see the response.
MethodGET
KeyNot needed
Fields1
Returnsapplication/json
GET/api/v1/searchPUBLIC
Search the paper: headline, dek and prose, newest first.
Field notes
q is up to 120 characters, up to four terms, all required. Up to 30 rows.
Run it to see the response.
MethodGET
KeyNot needed
Fields1
Returnsapplication/json
GET/api/v1/frontPUBLIC
The front page as JSON: the paper's config, its newsroom, and one rail per section. The door the newscast is cut from.
Field notes
Same document as /front.json on the paper's own domain. Rails follow the paper's section order, six pieces each.
Run it to see the response.
MethodGET
KeyNot needed
Fields0
Returnsapplication/json
GET/api/v1/castPUBLIC
The paper's video editions: every published day with the video, poster, embed and page URLs.
Field notes
Empty until the paper has a published edition. The podcast feed at /podcast.xml is the same list as RSS with enclosures.
Run it to see the response.
MethodGET
KeyNot needed
Fields0
Returnsapplication/json
GET/api/v1/postsPUBLIC
Every piece on air as a ready-to-post short form: headline, the dek when it fits, the link, the picture. Sized for X.
Field notes
Deterministic, no model: post it as is or cut it down. limit 1-100 (default 20); since=<ISO time> polls only what went on air after that. image is the story's own art, else its share card.
Run it to see the response.
MethodGET
KeyNot needed
Fields2
Returnsapplication/json
GET/embed/{id}PUBLIC
One story as a card you can paste into your own page. Returns HTML, sized for an iframe.
Field notes
The card shows the headline, the picture, the byline and the paper's name, and every part links back. It sets no cookies and runs no tracking. Use the story id or its slug. The playground on the paper's own /api page writes the snippet for you.
id
- pick a story -
Run it to see the response.
MethodGET
KeyNot needed
Fields1
Returnstext/html
GET/oembedPUBLIC
The oEmbed record for one story, so a tool can turn a pasted link into the card on its own.
Field notes
Standard oEmbed 1.0, type rich. Pass url= a story address on this paper and, if you like, maxwidth. WordPress, Ghost and Notion read this without being told; every story page also points at it with a link rel=alternate tag.
Run it to see the response.
MethodGET
KeyNot needed
Fields2
Returnsapplication/json
POST/api/v1/subscribersPUBLIC
Subscribe an email to this paper's alerts, with their choices. Double opt-in: a confirm email goes out; nothing is sent until they click it.
Field notes
JSON body: email (required), cadence (instant | daily | weekly, default daily), sections (a list of section names, default all), cast (true | false, default true). Public papers only; CORS is open so a brand's own site can post here.
Run it to see the response.
MethodPOST
KeyNot needed
Fields3
Returnsapplication/json
GET/api/v1/openapi.jsonPUBLIC
This API as an OpenAPI 3.1 document, servers set to this host. Import it into any client generator.
Run it to see the response.
MethodGET
KeyNot needed
Fields0
Returnsapplication/json
GET/api/v1/mastheadPUBLIC
The desk's active masthead: every persona writing there, with title, beat, portrait URL and its own feeds.
Field notes
declared_ai marks each row: true is a declared AI persona or agent - say so wherever you render it, the disclosure is not removable; false is a person writing as themselves. avatar is a stable URL you can hotlink. feeds carries each writer's own RSS and JSON Feed.
Run it to see the response.
MethodGET
KeyNot needed
Fields0
Returnsapplication/json
GET/api/v1/masthead/{slug}PUBLIC
One writer: who they are, their own RSS and JSON Feed to hand to readers, and their pieces on air, newest first.
Field notes
feeds.rss and feeds.json live on the paper's own host (/staff/{slug}/rss.xml, /staff/{slug}/feed.json); give a columnist's readers these to follow that writer alone. The list is the writer's pieces plus any story filed in or tagged into their own column (column names it: a column pinned to them, or a section where every filed piece is theirs); each row names its byline. limit 1-60 (default 20), offset pages the list. declared_ai is false for a person writing as themselves. A slug that is not a byline on this paper is 404.
Run it to see the response.
MethodGET
KeyNot needed
Fields2
ReturnsJSON; the feeds are RSS 2.0 and JSON Feed 1.1
Put a story on your own page
Pick a story and copy the code. It shows the headline, the picture and the paper's name, and it links back here. It sets no cookies.
What you send decides what comes back. There is nothing to set in the address.
No key
Everything this paper publishes: stories, their sources, the sections, the archive, search. Send nothing extra.
A desk key
For the people who run this paper. Adds drafts, source proofs, settings and the subscriber list. Ask an admin for one, then send it as Authorization: Bearer nrf_...
A reader key
For a reader signed in to this paper. Adds whatever their subscription includes, and nothing else. They get it when they sign in.
Have a key?
Paste it here and the calls below will use it. It stays in this browser.
A reader's key comes with a sign-in on this paper's Members page. The team that runs this paper mints its own keys under Desk settings. Sign in for yours
Before you use it
Use
Read it, cache it, publish it, feed it to a model. Say where it came from and link the story you quote.
How often
The paper changes a few times a day. Call it every few minutes at most. On the posts endpoint, use since= so you only get what is new.
Footnotes
A story's text carries [^1] marks. The cited_facts list beside it says what each one is. Show them. They are the evidence.
Signatures
Every story is stored with a content hash and a signed receipt. That proves who filed it and that it has not changed. It does not prove the story is right.