Research Papers
Research adapters return ResearchPaper records: ordinary NewsItem fields (with kind: "analysis") plus a research object with authors, institution, series, DOI, JEL codes, categories, version, and PDF/license links when the upstream supplies them. You can call each source directly or let research providers join company and topic feeds.
xnews returns metadata and links. A pdfUrl is a pointer to the source, not a license to redistribute the paper.
Sources at a glance
| Provider id | Standalone API | Key needed | Native search | Paging |
|---|---|---|---|---|
arxiv | fetchArxivPapers, fetchArxivAnnouncements | No | arXiv query syntax | start |
openalex | fetchOpenAlexWorks | Yes (apiKey) | Full text, filters, sort | cursor / nextCursor |
bis-research | fetchBisWorkingPapers | No | Local filtering of the full snapshot | None |
bis-research-hub | fetchBisResearchHub, fetchBisResearchHubRecent | No | query, institutions | None |
nber | fetchNberWorkingPapers, fetchNberRecentPapers | No | q | page, perPage |
ssrn | fetchSsrnPapers | No | None (titles matched locally in feeds) | index, count |
crossref | fetchCrossrefWorks | No (mailto recommended) | Query, filters, select, sort | cursor / nextCursor |
world-bank | fetchWorldBankDocuments | No | Query, docTypes, languages, dates | rows, offset |
biorxiv, medrxiv | fetchBioRxivPapers | No | Date window, categories | cursor |
europe-pmc | fetchEuropePmcPapers | No | Europe PMC query language | cursorMark |
hf-papers | fetchHfDailyPapers | No | None (filtered locally in feeds) | date |
osf-preprints | fetchOsfPreprints | No | providers, date bounds | nextUrl |
Every standalone function also has a pure parser (for example parseArxivPapers, parseCrossrefWorks) and, where the endpoint is URL-addressable, a URL builder in @xbbg/xnews/catalog.
Standalone discovery
import {
fetchArxivAnnouncements,
fetchArxivPapers,
fetchBisResearchHub,
fetchBisWorkingPapers,
fetchOpenAlexWorks,
} from "@xbbg/xnews";
const arxivTopic = await fetchArxivPapers('all:"monetary policy"', {
sortBy: "submittedDate",
sortOrder: "descending",
limit: 10,
});
const arxivCategories = await fetchArxivAnnouncements(["econ.EM", "q-fin.EC"], { limit: 10 });
const openAlex = await fetchOpenAlexWorks("monetary policy", {
apiKey: process.env.OPENALEX_API_KEY!,
sort: "publication_date:desc",
perPage: 10,
});
const bisWorkingPapers = await fetchBisWorkingPapers({ limit: 10 });
const researchHub = await fetchBisResearchHub({
query: "inflation expectations",
institutions: ["European Central Bank"],
limit: 10,
});
console.log(
arxivTopic[0]?.research.authors,
arxivCategories[0]?.research.categories,
openAlex.items[0]?.research.doi,
bisWorkingPapers[0]?.research.issue,
researchHub[0]?.research.institution,
);fetchArxivPaperssearches arXiv's legacy API with arXiv query syntax (all:,ti:,au:,cat:, boolean operators).fetchArxivAnnouncementsreads the current announcement feed for one or more categories.fetchOpenAlexWorksreturns a page:items,count,nextCursor, andperPage.fetchBisWorkingPapersreads the complete BIS Working Papers snapshot.fetchBisResearchHubsearches the multi-institution Central Bank Research Hub snapshot;fetchBisResearchHubRecentreads its recent-additions RSS feed.
The remaining sources need no API key:
import {
fetchBioRxivPapers,
fetchCrossrefWorks,
fetchEuropePmcPapers,
fetchHfDailyPapers,
fetchNberWorkingPapers,
fetchOsfPreprints,
fetchSsrnPapers,
fetchWorldBankDocuments,
} from "@xbbg/xnews";
const nber = await fetchNberWorkingPapers({ q: "inflation", limit: 10 });
const ssrn = await fetchSsrnPapers("fen", { limit: 10 }); // fen | arn | ern | numeric binding id
const crossref = await fetchCrossrefWorks("market liquidity", {
filters: { type: "journal-article", "from-pub-date": "2026-01-01" },
mailto: "research@example.com", // joins Crossref's polite pool
limit: 10,
});
const prwp = await fetchWorldBankDocuments("inflation", {
docTypes: ["Policy Research Working Paper"],
limit: 10,
});
const medrxiv = await fetchBioRxivPapers({ server: "medrxiv", categories: ["endocrinology"] });
const biomed = await fetchEuropePmcPapers("glp-1 AND SRC:PPR", { resultType: "core", limit: 10 });
const aiPapers = await fetchHfDailyPapers({ date: "2026-08-06" });
const socarxiv = await fetchOsfPreprints({ providers: ["socarxiv"], publishedSince: "2026-08-01" });
console.log(nber.length, ssrn.length, crossref.totalResults, prwp.length);
console.log(medrxiv.length, biomed.hitCount, aiPapers.length, socarxiv.nextUrl);- NBER:
fetchNberWorkingPapersuses the site's listing API (q,page,perPage) and includes abstracts;fetchNberRecentPapersreads the official new-papers RSS feed. - SSRN:
fetchSsrnPaperslists a network's newest approved papers.SSRN_NETWORKSmapsfen(Financial Economics),arn(Accounting Research), andern(Economics Research) to binding ids; any numeric binding id also works. Listings have no abstracts. - Crossref:
fetchCrossrefWorksexposesfilters,select,sort/order,rows/offset, and cursor paging, and returnsitems,totalResults, andnextCursor. - World Bank:
fetchWorldBankDocumentspasses through Documents & Reports facets:docTypes,languages,since/until(dates),fields, and rawextraParams. - bioRxiv/medRxiv:
fetchBioRxivPaperswalks a date window (from/to, default the last 7 days) with cursor paging and optional category filtering. The upstream can take tens of seconds to answer. - Europe PMC:
fetchEuropePmcPaperspasses the Europe PMC query language through untouched and pages bycursorMark(nextCursorMarkon the result). - Hugging Face:
fetchHfDailyPaperslists the community-curated daily papers (arXiv-hosted) for a date. - OSF:
fetchOsfPreprintsfilters OSF preprint servers (SocArXiv, PsyArXiv, and others) by provider and publication date, newest first, and returnsnextUrl.
Research in company and topic feeds
All research providers are opt-in. Add them to sources and configure them with feed-level options:
import { buildTopicNewsFeedResult } from "@xbbg/xnews";
const papers = await buildTopicNewsFeedResult({
query: "inflation expectations",
sources: ["arxiv", "openalex", "bis-research", "bis-research-hub", "nber", "crossref"],
openAlexApiKey: process.env.OPENALEX_API_KEY!,
arxivCategories: ["econ.EM", "q-fin"],
bisInstitutions: ["European Central Bank"],
crossrefFilters: { type: "journal-article" },
since: "2026-01-01",
limit: 40,
});
for (const paper of papers.items) {
console.log(paper.provider, paper.publishedAt, paper.title, paper.research?.doi ?? "");
}| Option | Applies to | Effect |
|---|---|---|
openAlexApiKey | openalex | Required. Without it the provider reports disabled |
arxivCategories | arxiv | Leaf ids (econ.EM) match exactly; archives (econ, q-fin) include every subcategory |
bisInstitutions | bis-research, bis-research-hub | Exact institution names, for example "European Central Bank" |
ssrnNetworks | ssrn | "fen", "arn", "ern", or numeric binding ids; default ["fen"] |
crossrefFilters | crossref | Merged into Crossref's filter parameter |
worldBankDocTypes | world-bank | Restricts document types |
bioRxivCategories | biorxiv, medrxiv | Restricts subject categories |
osfProviders | osf-preprints | Restricts OSF preprint servers, for example "socarxiv" |
Sources without native search (bis-research, ssrn, biorxiv, medrxiv, hf-papers, osf-preprints) are fetched in bulk and filtered locally: every query token must appear in the title, summary, authors, institution, series, categories, or JEL codes (SSRN listings carry titles only). A date window is forwarded to arXiv (submitted date), OpenAlex, Crossref, Europe PMC (FIRST_PDATE), World Bank, bioRxiv/medRxiv, and OSF, and enforced locally for every provider.
When two research items share a canonical URL, the feed keeps one and records both providers in seenInProviders and provenance. Crossref, Europe PMC, bioRxiv/medRxiv, OSF, World Bank, and OpenAlex use https://doi.org/ plus the DOI as the canonical URL when a DOI is known, so the same paper from two of them can merge. Different URLs stay separate even when the metadata looks related; use the DOI or research.externalId when you need stronger cross-catalog deduplication (recipe below).
Recipes
Respect arXiv's request interval
arXiv asks legacy API clients to leave at least three seconds between consecutive requests and to use one connection at a time. xnews exports the interval but does not sleep for you:
import { setTimeout as sleep } from "node:timers/promises";
import { ARXIV_MIN_REQUEST_INTERVAL_MS, fetchArxivPapers } from "@xbbg/xnews";
const queries = ['all:"yield curve"', 'all:"term premium"', "cat:q-fin.PR"];
for (const query of queries) {
const papers = await fetchArxivPapers(query, {
sortBy: "submittedDate",
sortOrder: "descending",
limit: 25,
});
console.log(query, papers.length);
await sleep(ARXIV_MIN_REQUEST_INTERVAL_MS); // 3,000 ms
}The same rule applies to feeds: a watchlist that includes arxiv sends one arXiv request per subject concurrently, so keep arXiv watchlists small or pace them.
Page through OpenAlex
import { fetchOpenAlexWorks, OPENALEX_INITIAL_CURSOR, type ResearchPaper } from "@xbbg/xnews";
const collected: ResearchPaper[] = [];
let cursor: string | undefined = OPENALEX_INITIAL_CURSOR;
while (cursor !== undefined && collected.length < 500) {
const page = await fetchOpenAlexWorks("central bank digital currency", {
apiKey: process.env.OPENALEX_API_KEY!,
filters: { from_publication_date: "2025-01-01" },
perPage: 100,
cursor,
});
collected.push(...page.items);
cursor = page.items.length > 0 ? page.nextCursor : undefined;
}OpenAlex requires an API key, meters each key against a daily budget, and returns rate-limit headers that are authoritative for short-term scheduling (PROVIDER_POLICIES.openalex). Crossref (cursor / nextCursor, starting from CROSSREF_INITIAL_CURSOR) and Europe PMC (cursorMark / nextCursorMark) page the same way.
Deduplicate across catalogs by DOI
import { normalizeDoi, type ResearchPaper } from "@xbbg/xnews";
function paperKey(paper: ResearchPaper): string {
const doi = paper.research.doi ? normalizeDoi(paper.research.doi) : undefined;
return doi ? `doi:${doi}` : `url:${paper.canonicalUrl ?? paper.url}`;
}
function dedupePapers(papers: readonly ResearchPaper[]): ResearchPaper[] {
const byKey = new Map<string, ResearchPaper>();
for (const paper of papers) {
if (!byKey.has(paperKey(paper))) byKey.set(paperKey(paper), paper);
}
return [...byKey.values()];
}normalizeDoi returns the bare, lower-cased 10.x/y form. research.externalId (arXiv id, OpenAlex id, and so on) is another stable key within one catalog.
The research metadata
| Field | Meaning |
|---|---|
authors | Author names as supplied |
institution, country | Publishing institution and its country, when the source states them (for example BIS and Research Hub records) |
series, issue | Working-paper series and number |
doi | DOI, when known |
jelCodes | JEL classification codes |
categories | Subject categories (arXiv categories, bioRxiv subjects, and so on) |
externalId | The catalog's own identifier |
version | Version label (arXiv v2) |
submittedAt, updatedAt, announcedAt, announceType | Lifecycle dates and announcement type, when supplied |
pdfUrl, licenseUrl | Source links. xnews does not download or redistribute the paper |
Every field is optional. See Data Model for the surrounding NewsItem fields.
Usage policies
- arXiv: at least three seconds between legacy API requests (
ARXIV_MIN_REQUEST_INTERVAL_MS), one connection at a time. API metadata is CC0, but PDFs and source files are not generally redistributable unless the paper's license permits it. Link to arXiv by default. - OpenAlex: the adapter requires
apiKey; see OpenAlex authentication and pricing. Data is CC0, but budgets and rate limits apply; honor the response headers. - BIS and Research Hub: metadata and source links only. RePEc indexing or public download access does not grant commercial redistribution rights. Review the BIS terms and request permission where your use requires it.
- NBER and SSRN: both listing endpoints are the sites' own undocumented APIs (NBER's RSS feed is the stable official surface) and may change without notice. Both return metadata and landing links only.
- Crossref and World Bank: free public APIs. Pass
mailtoto join Crossref's polite pool; abstracts are publisher-supplied and may carry publisher rights. Most World Bank publications are CC BY 4.0, but each record's license statement is authoritative. - bioRxiv/medRxiv, Europe PMC, and OSF: free, keyless APIs with per-record content licenses; only the metadata is openly reusable across the board. OSF throttles unauthenticated traffic.
- Hugging Face daily papers: an undocumented but widely used endpoint over community-curated arXiv listings; treat availability and shape as best-effort.
The same facts are machine-readable in PROVIDER_POLICIES (Provider Policies).
Related
- Central Banks: 13 central-bank working-paper feeds.
- Catalogs & Documents: download a PDF you are licensed to read and extract its text.
- Economic Data Releases: FRED and other structured series.
