Skip to main content
The Nordic Financial News API supports HTTP caching with ETags on list and detail endpoints alike, including the company member routes such as GET /companies/{identifier}/articles. Send a conditional request with the If-None-Match header, and the API returns 304 Not Modified if nothing has changed, saving bandwidth and reducing your monthly usage count.

How ETag caching works

1

Make a request

The response includes an ETag header with a unique identifier for the current state of the resource.
Response headers
2

Send the ETag on subsequent requests

Include the If-None-Match header with the ETag value:
3

Receive a 304 if unchanged

If the resource hasn’t changed, the API returns 304 Not Modified with no body:
List endpoints work the same way. Send back the If-None-Match value from the previous response for the same URL, filters included.

Why use ETag caching

  • Save bandwidth by not re-downloading unchanged data
  • Reduce monthly usage since 304 Not Modified responses do not count against your monthly quota
  • Faster responses with no response body to parse

What the ETag covers

An ETag on a list endpoint fingerprints the whole response, not one record. Four things go into it:
  • The request’s query string, so the same endpoint under different filters carries different ETags
  • The id and updated_at of every record in the response
  • State that no record’s updated_at reflects, such as whether a plan cap applied, on story routes which of a story’s articles you can see, and on calendar routes the name and ticker of each embedded issuer
  • A version token, bumped whenever a response body gains, loses, or renames a field
Two consequences follow. Cache the ETag against the full request URL rather than against a resource, since changing a single filter gives you a different one. And treat a changed ETag as “fetch this again”, not as “a record changed”: a plan change, an article leaving the feed, or a response-shape change all move the ETag while every record’s updated_at sits still. To detect changed records, walk updated_after instead.

Last-Modified and If-Modified-Since

Cached responses also carry Last-Modified, set to the newest updated_at in the record set. On a list it appears whenever the page is not empty. GET /stories/{id} and the events routes (GET /events, GET /events/{id}, and GET /companies/{identifier}/events) set an ETag and no Last-Modified, so If-None-Match is your only conditional request there. On the calendar routes Last-Modified also takes in the embedded issuers, so renaming a company moves the Last-Modified of every calendar response that carries it. Send it back as If-Modified-Since for the same 304. If-None-Match is the stronger check of the two, because Last-Modified has one-second resolution and does not see the state the ETag folds in beyond updated_at. Prefer If-None-Match, and send both only if your HTTP client does so by default. Every cached response also sets Cache-Control: private, max-age=0, must-revalidate, so a shared cache will not serve your data to anyone else and every read revalidates.

When ETag caching is not available

Two parameters turn caching off, on any endpoint that otherwise supports it. Both send Cache-Control: no-cache, no-store and no ETag:
  • q, because search results are ranked per request
  • updated_after, because sync walks are time-sensitive. See Real-time updates for the walk that replaces caching here
GET /search is never cached, for the same reason q is not. Every other list and single-resource endpoint supports conditional requests, and each one’s reference page declares the headers it accepts.
Last modified on September 30, 2026