documentation · version 1.0 · rest · json
newsmetry api
market news in one api: a real-time feed with full text, a link to the original and publication time.
01overview
base url for every endpoint: https://api.newsmetry.xyz/api/v1
stories reach the api the moment they are fully collected. on the newsmetry website the same events open 15 minutes later.
openapi spec and interactive console: swagger ↗
02quickstart
- get a key: request access. it looks like
nag_…and is shown only once — store it safely. - send it in the header
Authorization: Bearer <key>. - request the feed — that is it.
curl -H "Authorization: Bearer $NEWS_API_KEY" \
"https://api.newsmetry.xyz/api/v1/news?limit=5"import os, requests
API = "https://api.newsmetry.xyz/api/v1"
headers = {"Authorization": f"Bearer {os.environ['NEWS_API_KEY']}"}
r = requests.get(API + "/news?limit=5", headers=headers, timeout=30)
r.raise_for_status()
print(r.json())const API = "https://api.newsmetry.xyz/api/v1";
const res = await fetch(API + "/news?limit=5", {
headers: { Authorization: `Bearer ${process.env.NEWS_API_KEY}` },
});
if (!res.ok) throw new Error((await res.json()).error.message);
console.log(await res.json());03keys and authorization
every request except /health needs a key. either header works:
Authorization: Bearer nag_…
X-API-Key: nag_…send the key from your server only, never from a browser.
04limits and plans
every key is limited in three ways. all three show up in response headers; going over returns 429 with Retry-After.
| plan | quota / day | per second | per minute | concurrent | items per page |
|---|---|---|---|---|---|
| Freetrial: 5 requests a day | 5 | 1 | 5 | 1 | 50 |
| Proproduction: 1,000 requests a day | 1 000 | 5 | 120 | 4 | 500 |
only news requests spend quota (/news, /news/{id}). /me and /health are free. a request that fails with a 5xx error is refunded.
05pagination and polling
the feed is paged by cursor, not page number: the response contains next_cursor — pass it as cursor to get the next batch. while has_more = true, there is more.
to fetch only new stories, read with order=asc and keep next_cursor — it is returned on the last page too. start from it next time and you get only stories that appeared since.
import os, time, requests
API = "https://api.newsmetry.xyz/api/v1"
session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['NEWS_API_KEY']}"
cursor = None # keep it between runs — in a file or a database
while True:
params = {"order": "asc", "limit": 50}
if cursor:
params["cursor"] = cursor
r = session.get(f"{API}/news", params=params, timeout=30)
if r.status_code == 429: # rate limit or quota — wait as told
time.sleep(int(r.headers.get("Retry-After", "60")))
continue
r.raise_for_status()
page = r.json()
for item in page["items"]:
print(item["published_at"], item["title"])
cursor = page["next_cursor"] or cursor
if not page["has_more"]:
time.sleep(60)a story enters the feed and gets its id once it is complete, with full text. if a story has no text and never will (a short flash), it arrives with body_status = "empty".
06the news object
id stringstory id. grows with every new story — the cursor follows it.title stringheadline.summary string | nulllead or short description.body string | nullfull text.body_status stringfull — text present; empty — no text and there will be none (a short flash).url string | nulllink to the original.image_url string | nullimage.lang string | nulllanguage: en, ru.tags string[]sections.published_at iso 8601publication time, utc.collected_at iso 8601when the story appeared in newsmetry.updated_at iso 8601last change to the record.{
"id": "48213",
"title": "Fed holds rates steady, signals two cuts in 2027",
"summary": "The Federal Reserve left its benchmark rate unchanged on Wednesday…",
"body": "WASHINGTON — The Federal Reserve held interest rates steady…",
"body_status": "full",
"url": "https://www.reuters.com/markets/us/fed-holds-rates-2026-10-12/",
"image_url": "https://www.reuters.com/resizer/…/fed.jpg",
"lang": "en",
"tags": [],
"published_at": "2026-10-12T18:02:11Z",
"collected_at": "2026-10-12T18:07:40Z",
"updated_at": "2026-10-12T18:07:40Z"
}every id is a string: javascript loses precision on numbers this long. times are iso 8601 in utc with the Z suffix.
07errors
every error is json of the same shape:
{
"error": {
"code": "quota_exceeded",
"message": "daily quota exhausted (1000 requests), resets at 00:00 UTC"
}
}400 invalid_parameterinvalid parameter: message says which and what was expected, details lists the fields.401 unauthorizedthe key is missing, unknown or was reissued.403 forbiddenaccess was disabled by an administrator or the key expired.404 not_foundno such story or path.429 rate_limitedtoo fast: the per-second or per-minute limit was exceeded. wait Retry-After seconds.429 throttledtoo many concurrent requests on one key. retry in a second.429 quota_exceededdaily quota exhausted. it resets at 00:00 utc, in Retry-After seconds.503 unavailabletemporarily unavailable. retry in Retry-After seconds.08response headers
X-RateLimit-Limitrequests per minute allowed by the plan.X-RateLimit-Remainingrequests left in the current minute.X-RateLimit-Resetwhen the window frees up (unix time, seconds).X-Quota-Limitdaily quota (only on requests that spend it).X-Quota-Remainingquota left today.X-Quota-Resetquota reset — the next utc midnight (unix time).Retry-Afterseconds to wait before retrying — on 429 and 503 responses.09news feed
GET/newsspends quota
stories, newest first.
limit integer · default 50how many stories to return: from 1 up to the plan ceiling.cursor stringnext_cursor from the previous response — the next page.order desc | asc · default descdesc — newest to oldest, asc — oldest to newest (for polling “what is new”).lang stringlanguage: en, ru.q stringheadline substring, case-insensitive (up to 200 characters).from iso 8601published at or after, e.g. 2026-10-12T00:00:00Z.to iso 8601published at or before.curl -H "Authorization: Bearer $NEWS_API_KEY" \
"https://api.newsmetry.xyz/api/v1/news?limit=5"{
"items": [
{
"id": "48213",
"title": "Fed holds rates steady, signals two cuts in 2027",
"summary": "The Federal Reserve left its benchmark rate unchanged on Wednesday…",
"body": "WASHINGTON — The Federal Reserve held interest rates steady…",
"body_status": "full",
"url": "https://www.reuters.com/markets/us/fed-holds-rates-2026-10-12/",
"image_url": "https://www.reuters.com/resizer/…/fed.jpg",
"lang": "en",
"tags": [],
"published_at": "2026-10-12T18:02:11Z",
"collected_at": "2026-10-12T18:07:40Z",
"updated_at": "2026-10-12T18:07:40Z"
}
],
"has_more": true,
"next_cursor": "48213",
"meta": {
"quota_limit": 1000,
"quota_remaining": 987
}
}10single story
GET/news/{id}spends quota
a story by id.
id string · requiredstory id from the feed.curl -H "Authorization: Bearer $NEWS_API_KEY" \
"https://api.newsmetry.xyz/api/v1/news/48213"{
"id": "48213",
"title": "Fed holds rates steady, signals two cuts in 2027",
"summary": "The Federal Reserve left its benchmark rate unchanged on Wednesday…",
"body": "WASHINGTON — The Federal Reserve held interest rates steady…",
"body_status": "full",
"url": "https://www.reuters.com/markets/us/fed-holds-rates-2026-10-12/",
"image_url": "https://www.reuters.com/resizer/…/fed.jpg",
"lang": "en",
"tags": [],
"published_at": "2026-10-12T18:02:11Z",
"collected_at": "2026-10-12T18:07:40Z",
"updated_at": "2026-10-12T18:07:40Z"
}11my key and quota
GET/mefree
plan, limits and requests left today. free — handy for monitoring.
curl -H "Authorization: Bearer $NEWS_API_KEY" \
"https://api.newsmetry.xyz/api/v1/me"{
"id": "17",
"name": "Trading bot",
"key_prefix": "nag_q8Jx2LmA",
"key_expires_at": null,
"plan": {
"code": "pro",
"name": "Pro",
"daily_quota": 1000,
"rate_per_second": 5,
"rate_per_minute": 120,
"max_concurrency": 4,
"max_page_size": 500,
"unlimited": false
},
"quota": {
"used": 13,
"remaining": 987,
"reset_at": "2026-10-13T00:00:00Z"
}
}12service health
GET/healthno key
whether the api is up and collection is running. no key needed.
curl "https://api.newsmetry.xyz/api/v1/health"{
"status": "ok",
"service": "newsmetry",
"version": "1.0",
"time": "2026-10-12T18:08:12Z",
"db": "ok",
"redis": "ok",
"worker": "running"
}