fintopic.

Guide · 6 min read · updated 1 Oct 2026

Never miss a statement: an alert stream with /v2/feed

A cursor feed in the order statements enter the API gives you every new fact exactly once, including late articles. Run it as an alert loop, and keep the log as your own point-in-time history.

On this page
  1. The first call
  2. The loop
  3. An empty page is normal
  4. How fresh is fresh?

Polling a search endpoint for "anything newer than the last thing I saw" has two failure modes. Articles are not indexed in the order they were published: a story posted at 09:00 can arrive at 09:40, after you already moved your "newer than" mark past it, and you never see it. And if you widen the window to be safe, you see the same statements again and again.

/v2/feed removes both problems. It returns statements in the order they entered the API and hands you a cursor that marks your position in that order. Pass the cursor back and you get exactly what arrived since: nothing missed, nothing repeated.

The first call

Without a cursor the feed starts 24 hours back. Filters are the same as on /v2/statements; here, only important statements:

You need a RapidAPI key to run the examples: the free plan is enough.

curl
curl -G https://finance-pulse.p.rapidapi.com/v2/feed \
  --data-urlencode "importance_min=high" --data-urlencode "limit=5" \
  -H "X-RapidAPI-Key: YOUR_RAPIDAPI_KEY" -H "X-RapidAPI-Host: finance-pulse.p.rapidapi.com"
Response · captured 1 Oct 2026 11:34 UTC
{
  "data": [
    {
      "statement": "Kenon Holdings Ltd. entered into an agreement to acquire 25% equity interest in Vicinity District Energy for approximately $450 million.",
      "published_at": "2026-09-30T10:09:00Z",
      "indexed_at": "2026-09-30T11:33:18.118855Z",
      "source_domain": "prnewswire.com",
      "importance": "high",
      "topic_name": "Kenon acquires 25% stake in Vicinity District Energy"
    },
    {
      "statement": "Gold Circuit Electronics plans to bring in Amazon as a strategic investor through a private placement",
      "published_at": "2026-09-30T10:06:28Z",
      "indexed_at": "2026-09-30T11:34:17.428960Z",
      "source_domain": "digitimes.com",
      "importance": "high",
      "topic_name": "Gold Circuit Electronics acquires Amazon equity for AI server PCBs"
    },
    … 3 more
  ],
  "next_cursor": "WzI2MDU0OSwiNTVkYTE5ZDItZDE4My01ZTc5LWE5M2YtNzRlOTY4YWEwMjQzIl0"
}

Statements come oldest first by indexed_at, the moment they entered the API. Compare the two timestamps on each: published_at is often minutes, sometimes hours, earlier. A loop keyed on publication time would have to guess how long to wait for late articles; the feed simply delivers each statement when it arrives.

The loop

Store next_cursor after every call and pass it on the next one. Persisting it to disk means a restart resumes where it stopped:

import json, pathlib, time, requests

API = "https://finance-pulse.p.rapidapi.com"
HEADERS = {"X-RapidAPI-Key": "YOUR_RAPIDAPI_KEY", "X-RapidAPI-Host": "finance-pulse.p.rapidapi.com"}
STATE, LOG = pathlib.Path("feed.cursor"), pathlib.Path("statements.jsonl")

params = {"sector": "Energy", "importance_min": "high", "limit": 100}
while True:
    if STATE.exists():
        params["cursor"] = STATE.read_text()
    page = requests.get(f"{API}/v2/feed", headers=HEADERS, params=params, timeout=30).json()
    with LOG.open("a") as log:
        for s in page["data"]:
            log.write(json.dumps(s) + "\n")
            print("ALERT", s["published_at"][:16], s["statement"], f"({s['source_domain']})")
    STATE.write_text(page["next_cursor"])
    if len(page["data"]) < params["limit"]:
        time.sleep(150)            # caught up: new data arrives about every 2.5 minutes
import { readFileSync, writeFileSync, appendFileSync, existsSync } from "node:fs";

const API = "https://finance-pulse.p.rapidapi.com";
const HEADERS = { "X-RapidAPI-Key": "YOUR_RAPIDAPI_KEY", "X-RapidAPI-Host": "finance-pulse.p.rapidapi.com" };
const params = new URLSearchParams({ sector: "Energy", importance_min: "high", limit: "100" });

for (;;) {
  if (existsSync("feed.cursor")) params.set("cursor", readFileSync("feed.cursor", "utf8"));
  const page = await (await fetch(`${API}/v2/feed?${params}`, { headers: HEADERS })).json();
  for (const s of page.data) {
    appendFileSync("statements.jsonl", JSON.stringify(s) + "\n");
    console.log("ALERT", s.published_at.slice(0, 16), s.statement, `(${s.source_domain})`);
  }
  writeFileSync("feed.cursor", page.next_cursor);
  if (page.data.length < 100) await new Promise((r) => setTimeout(r, 150_000));
}

While catching up, full pages come back immediately; once you are current, the loop sleeps between polls. The Energy filter's first page, as the loop prints it:

Output · captured 1 Oct 2026 11:34 UTC
ALERT 2026-09-30T10:07 BNZ selected Sitetracker to support scalable multitechnology renewable energy growth in Southern Europe (businesswire.com)
ALERT 2026-09-30T10:06 Inflação acelera em setembro para 3,6% puxada pelos combustíveis (jornaldenegocios.pt)
ALERT 2026-09-30T10:00 GasEntec is selected to supply regasification modules for an LNG carrier-to-FSRU conversion project with EXMAR (businesswire.com)
ALERT 2026-09-30T11:31 Rezolv secured a €561 million loan for a solar park in Romania (reuters.com)
ALERT 2026-09-30T09:31 The Italian business ministry announced that average fuel prices are down following price caps set by Eni, IP, and Q8. (ansa.it)

An empty page is normal

When nothing new matched your filters, the feed answers "data": [] with the same cursor you sent. That is not an error: keep it and poll again later. A new snapshot is built about every 2.5 minutes, so polling faster only returns the same empty page.

JSON
{"data": [], "next_cursor": "WzI2MDI3OSwiNDk3YTg3…", "snapshot": {"built_at": "…", "lag_days": 0.0}}

How fresh is fresh?

indexed_at − published_at is the delay between an article appearing and its statements being available:

Median 11 min, 90th percentile 22 min from publication to the API (100 statements).indexed_at − published_at of the 100 newest statements, GET /v2/statements?since=<6 h ago>&limit=100 · captured 2026-10-01 11:34 UTC
Data table
minutesstatements
0–56
5–1038
10–1530
15–2012
20–3014
30–450
45–600
60–900
90–1200
120–2400
240+0

Fetching, extraction and clustering take minutes, not seconds. Finance Pulse is for knowing what the market is reading within the quarter hour, not for trading the first second of a headline.

Run this yourself: get a free API key on RapidAPI ↗. The free plan is enough for every example in this guide.