Backfill a year of US stock news with REST
Page GET /v1/news with from, to, sort, and cursor to pull the last year of Pro history.

On Pro, GET /v1/news can page the last year of US stock news, press releases, and legal notices. Send from, to, sort=published_asc, and the cursor from the previous page. Store the article id so a retry does not insert the same row twice.
Which plan can see a year
Free is the last 30 days. If you ask for older dates, the window is clamped and meta.notice says why. Pro, including the 7-day trial, searches the last year. Pro is $15 a month, or $162 a year. The 7-day trial includes the live feed, and a card is required. Free stays at 100 requests a day, delayed 15 minutes, with 30 days of history.
This is a news archive, not a price archive. You get headlines, sources, timestamps, tickers, summaries, and links. Press releases also include the full wire text. Publisher stories and legal notices do not include the publisher's full body.
The request
Filters combine with AND. Comma-separated tickers inside tickers are OR, up to 50 symbols. limit is 1 to 100. Sort ascending when you are filling a database from oldest to newest.
curl "https://api.marketnewsapi.com/v1/news?tickers=AAPL,MSFT&from=2025-11-01&to=2025-11-30&sort=published_asc&limit=100" \
-H "Authorization: Bearer $MARKETNEWSAPI_KEY"
Read meta.next_cursor. Pass it back as cursor until the field is absent. Keep from, to, tickers, and sort the same on every page. Changing them mid-walk gives you a different result set.
What to store
- Article
id, so a second run is an upsert. published_at, the title, the summary, the tickers, the source, and the originalurl.- The type:
news,press_release, orlegal. - Press-release body when the field is present. Do not expect that field on a publisher story or a legal notice.
When you show a third-party article, a press release, or a legal notice to an end user, keep the source and a working link. The terms do not let you present that item as your own reporting.
How fast to walk the archive
Every account can burst to 20 requests per second. A backfill does not need that rate. One request, then the next cursor, is enough, and it leaves room for the live app on the same key. A 429 comes with Retry-After. Wait that long. Calls to /usage and /status do not count toward the Free daily cap, but a year of pages will, so run it on Pro.
Walk one month at a time
A single from with no to is a legal request, and it is a bad job. Split the year into calendar months. Finish one month, checkpoint it, then start the next. If the process dies on 12 March you rerun March, not the whole year. Keep the checkpoint in your database, not in a log line.
for month in 2025-11 2025-12 2026-01; do
# from is the first day, to is the last day, sort is published_asc
# repeat with cursor until meta.next_cursor is empty
echo "$month"
done
Inside the month, the page size of 100 is the one to use for a backfill. The default page is smaller and only adds round trips. Hold the cursor opaquely. Do not decode it or build the next page yourself.
Try it for 7 days. Signup starts Pro. A card is required. Real-time REST, WebSocket, and MCP, with no request cap. After that it's $15/month, or Free if you stop.
What Free will do if you point it at last year
Free clamps the window to the last 30 days and explains that in meta.notice. The HTTP call still succeeds, which is how a backfill script can look healthy while it stores three weeks. Read X-Plan before the loop. If it says free, stop. The daily cap is 100 requests per UTC day, shared by every key, and a month of pages will hit 429 daily_limit_reached long before the year is done.
Pro is the plan that can see the last year. The 7-day trial can too, which is enough to prove the loop on one ticker and one month before you leave it running. Pro is $15 a month, or $162 a year. The 7-day trial includes the live feed, and a card is required. Free stays at 100 requests a day, delayed 15 minutes, with 30 days of history.
Ids, order, and the live handoff
Upsert on article id. A press release that also ran on a second wire is stored once: the first copy is kept and the symbols are merged, so you should not write your own cross-wire dedupe on top. You still need id dedupe for your own retries and for the overlap between the last REST page and the first socket message.
When the month walk reaches today, record the newest published_at, open the WebSocket, and fill any hole with one more REST call using that timestamp as from. After that, REST is for search, not for the tail. The parameter list is on GET /news, and the handoff is the one in REST vs WebSocket.