SFOLN

Catalogue / Web toolkit for agents

Academic Paper Search – arXiv, PubMed, DOI

sfoln/academic-paper-search · AI, Developer tools, Automation On request

Search research papers across Crossref, arXiv, PubMed and Europe PMC in one call, or look up DOIs, arXiv ids and PMIDs. One merged, de-duplicated row per paper: title, authors, year, venue, DOI, abstract, citation count, open-access PDF link. $1 per 1,000 papers.

About

What it does

Search research papers across Crossref, arXiv, PubMed and Europe PMC in one call and get one clean, de-duplicated row per paper: title, authors, year, publication date, journal or venue, DOI, arXiv id, PMID, abstract, citation count, open-access flag with the best free PDF link, and subjects. Or paste DOIs, arXiv ids, PMIDs or PMCIDs and get the same record for each. Built for literature reviews, research assistants and AI agents that need reliable paper metadata without scraping Google Scholar. $1 per 1,000 papers.

Price

Price per delivered record

EventPricePer 1,000Charged for
Research paper
paper
$0.001$1 / 1,000One paper delivered: a search result row (merged from Crossref, arXiv, PubMed and Europe PMC) or the record of a DOI, arXiv id, PMID or PMCID you looked up.

Apify free plan: up to 10 items per run. Paid plans have no per-run cap; set maxTotalChargeUsd to cap spend.

Run

Call it from code, an agent or the Console

This API is private on Apify for now. Email us and we will publish it for you, usually within two working days. The calls below work once it is public. contact@sfoln.com

curl · synchronous run, rows in the response
curl -X POST "https://api.apify.com/v2/actors/sfoln~academic-paper-search/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"queries":["crispr gene editing"],"maxResultsPerQuery":5}'
mcp.json · hosted Apify MCP server
{
  "mcpServers": {
    "apify": {
      "type": "http",
      "url": "https://mcp.apify.com?tools=sfoln/academic-paper-search"
    }
  }
}
asynchronous run · for large batches
POST https://api.apify.com/v2/actors/sfoln~academic-paper-search/runs?maxTotalChargeUsd=1
GET  https://api.apify.com/v2/actor-runs/{runId}            # until status is SUCCEEDED
GET  https://api.apify.com/v2/datasets/{defaultDatasetId}/items?format=json

Authenticate with an Apify API token. MCP clients can instead sign in with OAuth when prompted. Example prompt for an agent: Find the 5 most relevant papers on "crispr gene editing" published since 2022 and list their titles, authors, journals, DOIs and citation counts.

Input

Input fields

Search research papers across Crossref, arXiv, PubMed and Europe PMC, or look up papers by DOI, arXiv id, PMID or PMCID. Each paper is one dataset row; each query also gets one summary record.

FieldTypeDefaultMeaning
queriesarray—Search queries
Topics or keywords to search, one query per line (e.g. "crispr gene editing"). Words must all appear; put a phrase in double quotes. A line that is a DOI, an arXiv id or URL, or "PMID: …" is looked up instead. Accounts on the Apify free plan can process up to 10 items per run (queries and identifiers together) and 20 papers per query.
idsarray—DOIs, arXiv ids, PMIDs or PMCIDs
Papers to look up, one per line: DOIs (10.1038/s41586-021-03819-2 or a doi.org link), arXiv ids or links (1706.03762, arXiv:hep-th/9901001), PubMed ids (34968414) or PubMed Central ids (PMC8371605). Each returns one record.
maxResultsPerQueryinteger25Max papers per query
How many papers each search query returns at most (merged across the sources, best first). Range 1–1000.
sourcesarray—Sources
Where to search: crossref (all disciplines, citation counts), arxiv (physics, maths, computer science preprints), pubmed (biomedical literature, MeSH terms), europepmc (life sciences incl. preprints, open-access full text), openalex (only when available on this Actor). Leave empty for all of them.
yearFrominteger—Published from (year)
Only papers published in or after this year. Range 1000–2999.
yearTointeger—Published until (year)
Only papers published in or before this year. Range 1000–2999.
typestring"any"Publication type
Only this kind of publication. Sources without such records are skipped (arXiv only has preprints). One of "any", "journal-article", "preprint", "review", "conference-paper", "book".
openAccessOnlybooleanfalseOpen access only
Only papers that are free to read (open-access licence, arXiv, PubMed Central, Europe PMC full text).
sortstring"relevance"Sort by
relevance: papers several sources rank high come first; date: newest first; citations: most cited first. One of "relevance", "date", "citations".
enrichbooleantrueAdd citation counts by DOI
For papers with a DOI that Crossref did not return in the search, fetch the Crossref record (citation count, licence, publisher). No extra charge.
deduplicatebooleantrueSkip papers already delivered in this run
A paper found by several queries is delivered (and charged) once, for the first query.
maxItemsinteger100Max items
Safety cap on how many queries and identifiers are processed in this run; the rest are reported as ignored. Range 1–10000.
concurrencyinteger3Concurrency
Queries and lookups processed in parallel. arXiv and Crossref limits are shared by the whole run, so more rarely helps. Range 1–6.
includeRawbooleanfalseInclude raw source records
Attach each source's unmodified record to every paper (larger output; with queries of 500+ papers give the run 1 GB of memory).
Example input
{
  "queries": [
    "crispr gene editing"
  ],
  "maxResultsPerQuery": 5
}

Output

One record per input item

Records land in the run's dataset; a synchronous call returns them directly. Each has a status (ok is charged; everything else is free) and a charged flag. The run's OUTPUT record totals items and charges.

FieldTypeMeaning
inputstring | objectInput
The search query or identifier this record belongs to.
recordTypestringRecord type
paper (one paper; charged) or summary (one per search query: counts, sources, warnings; never charged).
positionintegerPosition
Rank of the paper in its query's results (1 = first).
statusstringStatus
ok | not_found | error | skipped_invalid | skipped_budget | skipped_free_plan | skipped_unmetered e.g. "ok"
chargedbooleanCharged
Whether this record incurred a pay-per-event charge.
chargedEventstringCharged event
Pay-per-event event charged for this record (present only when charged).
chargedCountintegerEvents charged
Events actually charged when the charge came back short of the requested count (present only then; a warning explains it).
sourcestringSource
Paper rows: the sources searched (crossref+arxiv+pubmed+europepmc); lookups: the source that answered (crossref, arxiv, pubmed, europepmc, doi).
fetchedAtstringFetched at
ISO timestamp.
titlestring | nullTitle
Paper title.
authorsarrayAuthors
Author names as published, in order.
yearinteger | nullYear
Publication year.
publishedDatestring | nullPublished
Publication date: YYYY-MM-DD, YYYY-MM or YYYY (earliest of online and print).
venuestring | nullVenue
Journal, proceedings, book or preprint server (arXiv: the journal reference when published, else arXiv).
publisherstring | nullPublisher
Publisher (from Crossref or OpenAlex).
typestring | nullType
journal-article, preprint, review, conference-paper, book, book-chapter, dataset, dissertation, report or other.
doistring | nullDOI
DOI in lower case, without https://doi.org/.
arxivIdstring | nullarXiv id
arXiv identifier without version (e.g. 1706.03762).
pmidstring | nullPMID
PubMed id.
pmcidstring | nullPMCID
PubMed Central id (free full text).
openAlexIdstring | nullOpenAlex id
OpenAlex work id (W…), when OpenAlex was used.
abstractstring | nullAbstract
Abstract as plain text, when a source provides it.
citationCountinteger | nullCitations
Times cited: Crossref is-referenced-by-count, else OpenAlex or Europe PMC.
openAccessboolean | nullOpen access
Free to read: open-access licence, arXiv, PubMed Central or Europe PMC full text. null = unknown.
pdfUrlstring | nullPDF
Best free PDF link (arXiv, Europe PMC, publisher under an open licence).
urlstring | nullURL
Landing page: where the paper can be read when it is open access, else the publisher's page.
subjectsarraySubjects
MeSH headings and keywords (PubMed, Europe PMC), arXiv categories, OpenAlex topics.
languagestring | nullLanguage
Language code, when a source states it.
sourcesarrayFound in
Sources that returned this paper (crossref, pubmed, europepmc, arxiv, openalex, doi).
idTypestringIdentifier type
Lookups: doi, arxiv, pmid or pmcid.
lookupIdstringIdentifier
Lookups: the identifier in canonical form.
querystringQuery
Summary records: the search query.
resultsDeliveredintegerPapers delivered
Summary records: papers delivered (and charged) for the query.
stopReasonstringStop reason
Summary records: limit, free_plan, end, budget, aborted, deadline or error.
sourcesSearchedarraySources searched
Summary records: the sources asked.
sourceTotalsobjectHits per source
Summary records: total matches each source reported (null when unknown or failed).
duplicatesSkippedintegerDuplicates skipped
Summary records: papers skipped because an earlier query of the run delivered them (not charged).
errorobjectError
{ code, message, provider?, status? } when status is not ok. Codes set by the runtime: budget_exhausted, free_plan_limit, unmetered, aborted, charge_failed, record_too_large, invalid_record, dataset_push_failed; upstream codes: http_error (with the source's HTTP status), timeout, network, tls_error, invalid_json, too_large, rate_limit, server, client, invalid_response, not_found; invalid_input for an identifier that is not a DOI, arXiv id, PMID or PMCID.
warningsarrayWarnings
Notes about this record: sources that failed or were skipped, free-plan or budget limits, skipped duplicates.
rawobjectRaw
Each source's unmodified record, keyed by source (only with includeRaw).
Example record
{
  "input": "crispr gene editing",
  "recordType": "paper",
  "position": 2,
  "title": "CRISPR-Cas9 system: A new-fangled dawn in gene editing",
  "authors": [
    "Darshana Gupta",
    "Oindrila Bhattacharjee",
    "Drishti Mandal"
  ],
  "year": 2019,
  "publishedDate": "2019-09",
  "venue": "Life Sciences",
  "publisher": "Elsevier BV",
  "type": "review",
  "doi": "10.1016/j.lfs.2019.116636",
  "arxivId": null,
  "pmid": "31295471",
  "pmcid": null,
  "openAlexId": null,
  "abstract": "Till date, only three techniques namely Zinc Finger Nuclease (ZFN), Transcription-Activator Like Effector Nucleases (TALEN) …",
  "citationCount": 299,
  "openAccess": null,
  "pdfUrl": null,
  "url": "https://linkinghub.elsevier.com/retrieve/pii/S0024320519305624",
  "subjects": [
    "Animals",
    "CRISPR-Cas Systems",
    "Gene Editing",
    "Genome editing"
  ],
  "language": "en",
  "sources": [
    "crossref",
    "pubmed"
  ],
  "status": "ok",
  "charged": true,
  "chargedEvent": "paper",
  "source": "crossref+pubmed+europepmc+arxiv",
  "fetchedAt": "2026-10-14T10:00:00.000Z"
}

FAQ

Questions

Which sources are searched?
Crossref (all disciplines, 170M+ DOI records), arXiv (preprints in physics, maths and computer science), PubMed (biomedical literature) and Europe PMC (life sciences, preprints and open-access full text). Results are merged: a paper found by several sources is one row, with the best fields from each (abstract from PubMed or arXiv, citation count from Crossref, open-access PDF from arXiv or Europe PMC). The `sources` field says where each paper was found.
Can I look up papers I already know?
Yes: put DOIs, arXiv ids, PMIDs or PMCIDs in `ids` (or links to them). Each returns one record and costs one `paper` event; identifiers that are not found are free. DOIs outside Crossref (DataCite, e.g. Zenodo or arXiv DOIs) are resolved through doi.org.
Do I get the full text?
No, the Actor returns metadata and abstracts. For open-access papers it gives the free PDF or full-text link (`pdfUrl`, `url`); pass those to a PDF or URL-to-markdown Actor for the text.

Machine-readable

This page for agents