databank

APInews as it reaches us, weighed for the market

What this is

Every story the wire brings is judged by a model in two words: how much it weighs for the market (high, elevated or nothing) and whether it is the first telling of its event. This API hands the stories out two ways: a page over REST, and the same stories the moment they are judged, over a stream. One token opens both.

Endpoints

GET /v1/news

A page of stories, newest received first.

cursor
the next_cursor of the previous page
limit
stories per page, 1 to 100, 50 by default
by
received (default) or published: the clock the page is ordered and windowed by
level
high, elevated, or both separated by a comma
first
true for first tellings only, false for repeats only
judged
false to include stories the model has not judged yet
since
ISO 8601 moment on the chosen clock, inclusive
until
ISO 8601 moment on the chosen clock, exclusive
publisher
one outlet, by its exact name
GET /v1/news/{id}

One story by its id.

GET /v1/news/stream

Server-sent events, one story per event. Every story here is already judged.

want
the subscription: news (default), news+high, news+high+first, news+elevated
after
resume after this version, the same as the Last-Event-ID header
GET /v1/openapi.json

This contract, machine-readable (OpenAPI 3.1).

Token

Send it as a bearer token in the Authorization header. A browser EventSource cannot set headers, so the stream also takes the token in the path. A token is shown once when it is issued and never again.

Authorization: Bearer dbk_…
https://api.databank.fi/t/dbk_…/v1/news/stream

Try it

curl -H "Authorization: Bearer $TOKEN" \
  "https://api.databank.fi/v1/news?level=high&limit=20"

curl -N -H "Authorization: Bearer $TOKEN" \
  "https://api.databank.fi/v1/news/stream?want=news+high"

Pages

A page carries next_cursor and has_more. Pass the cursor back to get the next page: it is a position on the chosen clock, not an offset, so a feed that keeps arriving never skips or repeats a story. A cursor made on one clock is refused on the other.

Stream

Each event carries the story as data and a version as its id. Keep the last id: on a reconnect send it as Last-Event-ID, or as the after parameter, and the stream resumes from there without a gap. A new reader starts at the head and takes history from the page endpoint. Heartbeats arrive as hb events, and the server closes a stream after an hour: reconnect with the last id. The log keeps thirty days. Ask to resume from further back and the first event is a reset naming the gap, so the client knows to take that stretch by pages.

Limits

Calls per minute are a property of the token and travel back in the RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset headers. Over the limit the answer is 429 with Retry-After. Up to five streams may be open on one token at once.

Errors

{"schema": "databank.news.1",
 "error": {"type": "unauthorized", "message": "unauthorized"}}
unauthorized
no token, or a token that is unknown, revoked or expired
forbidden
the token is alive but was not given this scope
invalid_request
a parameter is at fault, and the message names it
not_found
no such story or no such path
rate_limited
over the token's calls per minute, or too many streams at once
unavailable
the database did not answer, try again shortly