Nordic Financial News Stories API

The Stories API from Nordic Financial News — 2 operation(s) for stories.

Operations 2

GET /api/v1/stories List Stories #
GET /api/v1/stories/{id} Get Story Details #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/nordic-financial-news:nordic-financial-news-stories-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

nordic-financial-news-stories-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Nordic Financial News Stories API
  version: v1.0
  contact:
    name: API Support
    email: hello@nordicfinancialnews.com
  description: 'Operations tagged Stories across 2 of this provider''s published API definitions: nordic-financial-news-openapi-original.yml, nordic-financial-news-openapi.yml. Each path carries the servers of the definition it was published in.'
servers:
- url: https://nordicfinancialnews.com
  description: Production server
tags:
- name: Stories
paths:
  /api/v1/stories:
    get:
      summary: List Stories
      tags:
      - Stories
      security:
      - bearer_auth: []
      description: 'Returns a paginated list of published stories ordered by publication date (newest first). Each story synthesizes coverage of a single developing event from multiple source articles into one narrative.


        ## Filtering

        Supports filtering by country, category, source, and company ticker. Use `GET /api/v1/sources` to discover source IDs for the `sources` filter.


        ## Search

        Use `q` for full-text search: relevance-ranked by default, newest-first with `sort=latest`, or matched by meaning with `mode=semantic`.


        ## Polling for updates

        Use `updated_after` for incremental syncing.


        ## Caching

        Requests with `updated_after` are not cached: they return `Cache-Control: no-cache, no-store` and no `ETag`. The `ETag` reflects the response as served, not only record timestamps: it changes when plan limits alter the visible set, and when a story''s visible article set changes, so a changed `ETag` does not necessarily mean a record was updated.'
      parameters:
      - name: limit
        in: query
        required: false
        description: Number of stories to return per page (default 25, max 100).
        example: 25
        schema:
          type: integer
      - name: cursor
        in: query
        required: false
        description: Opaque pagination cursor returned as `pagination.next_cursor` from a previous response. Mutually exclusive with `q` unless `sort=latest` is also given.
        schema:
          type: string
      - name: updated_after
        in: query
        required: false
        description: 'ISO 8601 datetime. Returns only stories updated after this timestamp. Use this for incremental sync: store the timestamp of your last completed sync, then request only newer results on each poll. Results are ordered by `updated_at` ascending and are cursor-paginated. Follow `pagination.next_cursor`, resending the same `updated_after` value, until it is null. Only advance your stored timestamp once you have drained every page (see the Real-Time Updates guide at https://docs.nordicfinancialnews.com). Mutually exclusive with `sort=latest` (with or without `q`). An `updated_after` walk is always ordered by `updated_at`.'
        example: '2024-01-01T00:00:00Z'
        schema:
          type: string
      - name: q
        in: query
        required: false
        description: Full-text search query (2-200 characters). By default, results are ranked by relevance instead of publication date, as a single page with no cursor. Mutually exclusive with `cursor` unless `sort=latest` is also given. Disables caching.
        example: Volvo earnings
        schema:
          type: string
      - name: sort
        in: query
        required: false
        description: Result order for `q`. `relevance` (default) is a single relevance-ranked page with no cursor; it requires `q`, and returns 400 without one. `latest` turns `q` into a match filter under the endpoint's normal newest-first order (`published_at` descending) and the response is cursor-paginated like any other request; without `q` it is an accepted no-op (that's already the default order). Mutually exclusive with `updated_after`.
        example: latest
        schema:
          type: string
          enum:
          - relevance
          - latest
      - name: mode
        in: query
        required: false
        description: 'Set to `semantic` to match `q` by meaning rather than by keyword. The match runs over each story''s title, summary and key entities. The narrative body is not part of the match, so it answers thematic questions a keyword match cannot ("defense contract wins", "battery cell capacity expansion").


          Requires `q`, is mutually exclusive with `sort`, `cursor` and `updated_after`, and returns a single ranked page capped by `limit`; every other filter (`country`, `category`, `sources`, `ticker`, `company`, `market`, `domicile`, `exchange`, `index`, `sector`, `watchlist`, `published_after`/`published_before`) remains a hard filter applied before the match, not after.


          Each story gains a `distance` (raw cosine, lower is closer, rounded to 4dp). Compare it only within one response, never across responses: the scale is model-dependent. Ranking also blends in a small recency bonus that `distance` does not reflect. A server-side relevance floor drops weak matches, so a page is frequently shorter than `limit` and can be empty. Raising `limit` does not recover floored rows.


          On restricted plans, the story age window narrows the candidate set and the story count cap applies as a clamp on this page, so a capped plan receives its closest matches rather than its newest stories; either restriction sets `plan_limited: true`.


          The response `pagination` object carries `count` only. There is no `next_cursor`, since a distance ranking cannot be cursor-paginated, and the response is uncacheable (`Cache-Control: no-cache, no-store`, no `ETag`). If the query cannot be embedded the request returns `503` rather than silently falling back to keyword matching.'
        example: semantic
        schema:
          type: string
          enum:
          - semantic
      - name: country
        in: query
        required: false
        description: Filter by country using ISO 3166-1 alpha-2 code (e.g. `SE`, `NO`, `DK`). Comma-separated for multiple (e.g. `SE,NO`). Case-insensitive.
        example: SE
        schema:
          type: string
      - name: category
        in: query
        required: false
        description: Filter by category `id` (from `GET /api/v1/categories`). Comma-separated for multiple (e.g. `cat_earnings1,cat_mna000001`); unknown ids are ignored.
        example: cat_earnings1
        schema:
          type: string
      - name: sources
        in: query
        required: false
        description: Comma-separated list of source IDs (max 25). Use `GET /api/v1/sources` to discover source IDs. Also accepts array form (`sources[]=id1&sources[]=id2`). Returns stories with at least one article from a listed source.
        example: abc123def456,ghi789jkl012
        schema:
          type: string
      - name: ticker
        in: query
        required: false
        description: 'Filter by company stock ticker symbol, comma-separated for several (e.g. `VOLV-B` or `VOLV-B,ERIC-B`; matches any of them). Accepts full tickers with exchange suffix (e.g. `VOLV-B.ST`). Returns stories mentioning the company. Former tickers resolve too: a company that renamed or moved venues is still reachable by an old ticker; the returned company `former_tickers` lists any such historical tickers. Matching is case-insensitive. Every value must resolve to a company, or the request is rejected with `400` naming the unknown values. Combined with `company`, the two filters intersect.'
        example: VOLV-B
        schema:
          type: string
      - name: company
        in: query
        required: false
        description: Filter by company `id` (as returned by the companies endpoints), comma-separated for several (matches any of them). Complements `ticker`; use this to reach companies without a stock listing. Every value must resolve, or the request is rejected with `400` naming the unknown ids. Combined with `ticker`, the two filters intersect.
        example: cmpny1234567
        schema:
          type: string
      - name: exchange
        in: query
        required: false
        description: Filter by exchange using ISO 10383 Market Identifier Code, comma-separated for multiple (e.g. `XSTO` for Nasdaq Stockholm, `XCSE` for Nasdaq Copenhagen, `XHEL` for Nasdaq Helsinki, `XOSL` for Oslo Børs). Returns stories about companies actively listed there. Case-insensitive.
        example: XSTO,XCSE
        schema:
          type: string
      - name: market
        in: query
        required: false
        description: Filter to stories about companies with an active equity listing in these countries' exchanges (ISO 3166-1 alpha-2, comma-separated, e.g. `SE,NO`). `SE` covers Nasdaq Stockholm, First North, Spotlight and NGM. Distinct from `country` (the source that reported it) and `domicile` (legal domicile). Includes foreign-domiciled but locally-listed issuers.
        example: SE
        schema:
          type: string
      - name: domicile
        in: query
        required: false
        description: Filter to stories about companies legally domiciled in these countries (ISO 3166-1 alpha-2, comma-separated). Reaches unlisted companies; excludes foreign-domiciled but locally-listed issuers. Use `market` for market-coverage questions.
        example: SE
        schema:
          type: string
      - name: index
        in: query
        required: false
        description: Filter by stock index id or symbol (e.g. `OMXS30`, `OMXC25`, `OMXH25`, `OBX`). Returns stories about companies in that index. Case-insensitive for symbols.
        example: OMXS30
        schema:
          type: string
      - name: sector
        in: query
        required: false
        description: 'Filter by company sector. Case-sensitive; must exactly match one of: `Communication Services`, `Consumer Discretionary`, `Consumer Staples`, `Energy`, `Financials`, `Health Care`, `Industrials`, `Information Technology`, `Materials`, `Real Estate`, `Utilities`.'
        example: Industrials
        schema:
          type: string
      - name: listed
        in: query
        required: false
        description: When `true`, only return stories linked to at least one company with an active listing on any exchange. A company whose listings are all delisted does not count. Hidden and unverified companies do not count.
        example: 'true'
        schema:
          type: string
      - name: watchlist
        in: query
        required: false
        description: Restricts to stories mentioning companies in a single watchlist, identified by its `id` (from the List Watchlists endpoint). An unknown id returns no stories. Requires `read:watchlist` scope.
        example: wl_8fk2a1b3c4d5
        schema:
          type: string
      - name: published_after
        in: query
        required: false
        description: ISO 8601 datetime. Returns stories published on or after this timestamp.
        example: '2024-06-01T00:00:00Z'
        schema:
          type: string
      - name: published_before
        in: query
        required: false
        description: ISO 8601 datetime. Returns stories published before this timestamp.
        example: '2024-12-31T23:59:59Z'
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: 'Comma-separated list of fields to include in the response. Available fields: `id`, `title`, `summary`, `published_at`, `updated_at`, `article_count`, `article_ids`, `country`, `category`, `company_ids`.'
        example: id,title,summary,published_at
        schema:
          type: string
      - name: If-None-Match
        in: header
        required: false
        description: ETag value from a previous response. Returns `304 Not Modified` if data has not changed.
        schema:
          type: string
      - name: If-Modified-Since
        in: header
        required: false
        description: HTTP date from a previous `Last-Modified` header. Returns `304 Not Modified` if nothing has changed since.
        schema:
          type: string
      responses:
        '200':
          description: Stories retrieved
          content:
            application/json:
              schema:
                type: object
                properties:
                  stories:
                    type: array
                    items:
                      $ref: '#/components/schemas/StorySummary'
                  pagination:
                    type: object
                    properties:
                      count:
                        type: integer
                        example: 25
                      next_cursor:
                        type:
                        - string
                        - 'null'
                  plan_limited:
                    type: boolean
                    description: Present and `true` when your plan restricted what this endpoint can return, so the result may be incomplete. Absent when your plan applies no restriction.
                    example: true
        '304':
          description: Not Modified
        '401':
          description: Unauthorized
          content:
            application/json:
              examples:
                unauthorized:
                  value:
                    type: https://docs.nordicfinancialnews.com/problems/auth-invalid
                    title: Unauthorized
                    status: 401
                    detail: Missing or invalid API key
                    instance: urn:request:abc123
              schema:
                $ref: '#/components/schemas/problem_details'
      operationId: getApiV1Stories
      x-operation-id-source: derived
    servers:
    - url: https://nordicfinancialnews.com
      description: Production server
  /api/v1/stories/{id}:
    get:
      summary: Get Story Details
      tags:
      - Stories
      security:
      - bearer_auth: []
      description: Returns the full details of a single story, including content in Markdown format, associated articles, and companies. Supports conditional requests via `If-None-Match` for efficient caching.
      parameters:
      - name: id
        in: path
        required: true
        description: Story ID (e.g. `sty_abc123def`).
        example: sty_abc123def
        schema:
          type: string
      - name: If-None-Match
        in: header
        required: false
        description: ETag value from a previous response. Returns `304 Not Modified` if the story has not changed.
        schema:
          type: string
      responses:
        '200':
          description: Story found
          content:
            application/json:
              schema:
                type: object
                properties:
                  story:
                    $ref: '#/components/schemas/StoryDetail'
        '304':
          description: Not Modified
        '404':
          description: Story not found
          content:
            application/json:
              examples:
                not_found:
                  value:
                    type: https://docs.nordicfinancialnews.com/problems/not-found
                    title: Not Found
                    status: 404
                    detail: The requested resource could not be found
                    instance: urn:request:abc123
              schema:
                $ref: '#/components/schemas/problem_details'
      operationId: getApiV1StoriesById
      x-operation-id-source: derived
    servers:
    - url: https://nordicfinancialnews.com
      description: Production server
components:
  schemas:
    StoryDetail:
      allOf:
      - $ref: '#/components/schemas/StorySummary'
      - type: object
        properties:
          content:
            type: string
            format: markdown
            description: Full story content in Markdown format
            example: '## Volvo Q3 Results\n\nVolvo reported record earnings...'
          updated_at:
            type: string
            format: date-time
            description: When the story was last updated (ISO 8601)
            example: '2026-03-15T14:00:00.000Z'
          companies:
            type: array
            description: Companies mentioned in this story
            items:
              type: object
              properties:
                id:
                  type: string
                  description: Unique company identifier
                  example: uejazctgchj4
                name:
                  type: string
                  description: Company name
                  example: AB Volvo (Volvo Group)
                ticker:
                  type:
                  - string
                  - 'null'
                  description: Primary stock ticker
                  example: VOLV-B
            example:
            - id: uejazctgchj4
              name: AB Volvo (Volvo Group)
              ticker: VOLV-B
    StorySummary:
      type: object
      required:
      - id
      - title
      - summary
      - article_count
      - published_at
      - updated_at
      properties:
        id:
          type: string
          description: Unique story identifier
          example: story_volvo_q3
        title:
          type: string
          description: Story title
          example: Volvo Reports Record Q3 Results
        summary:
          type: string
          description: Story summary
          example: Volvo reported record third-quarter earnings, beating analyst expectations...
        article_count:
          type: integer
          description: Number of articles in this story (matches the length of article_ids)
          example: 4
        published_at:
          type: string
          format: date-time
          description: 'When the story''s newest source article was published (ISO 8601). This is editorial time, not the time the story reached this API: a story about older news carries an older date. Use it to filter by when news happened, never to track what is new to you.'
          example: '2026-03-15T09:30:00.000Z'
        updated_at:
          type: string
          format: date-time
          description: 'When this record last changed (ISO 8601). This is the clock incremental sync runs on. It only ever moves forward, unlike published_at. To sync: pass your last completed sync time as `updated_after`, drain every page via `pagination.next_cursor`, and only then advance your stored timestamp.'
          example: '2026-03-15T09:35:00.000Z'
        article_ids:
          type: array
          items:
            type: string
          description: IDs of articles in this story, most relevant first
          example:
          - art_abc123def
          - art_def456ghi
        country:
          type:
          - string
          - 'null'
          description: Country code (ISO 3166-1 alpha-2)
          example: SE
        company_ids:
          type: array
          items:
            type: string
          description: IDs of companies mentioned in this story
          example:
          - uejazctgchj4
        category:
          type: object
          description: Story category
          properties:
            id:
              type: string
            name:
              type: string
        event_id:
          type:
          - string
          - 'null'
          description: ID of the event this story was generated from. An event that has since been merged or removed still answers `GET /events/{id}` with a tombstone rather than a 404.
          example: 8fzq2rmtnk5c
    problem_details:
      type: object
      required:
      - type
      - title
      - status
      - detail
      - instance
      properties:
        type:
          type: string
          description: URI that identifies the problem type
        title:
          type: string
          description: Short human-readable summary
        status:
          type: integer
          description: HTTP status code
        detail:
          type: string
          description: Human-readable explanation
        instance:
          type: string
          description: URI that identifies the specific occurrence
  securitySchemes:
    bearer_auth:
      type: http
      scheme: bearer
      bearerFormat: API Key
      description: API Key authentication using Bearer token
x-refined-from:
- nordic-financial-news-openapi-original.yml
- nordic-financial-news-openapi.yml