# Academic Search API (`truefetch/academic-search-api`) Actor

Academic Search API is a research paper search API that queries OpenAlex, Crossref, PubMed and DOAJ in one call and returns 19 normalized fields per paper: DOI, title, abstract, authors, venue, year, citations, open-access flag and PDF link, merged on DOI across indexes. No API key. $0.0025 a paper.

- **URL**: https://apify.com/truefetch/academic-search-api.md
- **Developed by:** [TrueFetch](https://apify.com/truefetch) (community)
- **Categories:** Developer tools, AI, Integrations
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.88 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

**Academic Search API is a research paper search API that sends one query to twelve open bibliographic indexes, folds the answers to one row per work and returns 20 normalized fields per paper, built for developers and data teams who need a citable reading list from a single call.**

- **Twelve indexes behind one endpoint.** OpenAlex, Crossref, PubMed, DOAJ, arXiv, Europe PMC, OpenAIRE, CORE, DataCite, OpenReview, Semantic Scholar and CQVIP each receive the same query string and each is paged until your per-index count is met.
- **20 fields on every row**: DOI, title, abstract, author list, venue, publication year and date, citation count, open-access flag, PDF link, work URL, work type, language, licence, subject terms, author affiliations, the index's own record id and two run stamps.
- **Folding on two keys.** The DOI folds a work carried by several indexes into one row; where an index publishes no DOI, the normalized title plus publication year does, which is what lets an arXiv preprint meet its OpenReview submission.
- **No API key for any index.** Every index this API reads answers a public endpoint, so a run needs only your Apify token.

[**Run a one-result test**](https://apify.com/truefetch/academic-search-api) · [**View API**](https://apify.com/truefetch/academic-search-api/api)

The smallest useful test is one paper from one index: `max_results: 1` with a single entry in `sources` costs $0.0025 for the row plus $0.01 for the Actor Start, $0.0125 in total on the FREE tier. `max_results` is a per-index budget, so leaving `sources` empty multiplies that count by twelve.

### What does Academic Search API do?

Academic Search API turns one search string into a folded table of scholarly works drawn from twelve open bibliographic indexes at once. It resolves the query against a cross-discipline works catalogue (OpenAlex), DOI registration metadata (Crossref), biomedical literature (PubMed, Europe PMC), open-access journals (DOAJ), preprints and conference submissions (arXiv, OpenReview), repository and dataset records (CORE, OpenAIRE, DataCite), a citation graph (Semantic Scholar) and the Chinese-language journal record (CQVIP). Each index is paged until your per-index budget is met, records that share a DOI or a normalized title and year are folded into one row, and every row carries the same 20 fields whichever index answered.

The scope is bibliographic metadata about published works: identifiers, titles, abstracts, people, venues, dates, counts, licences and links. Full text stays with the publisher or repository that hosts it, and `pdf_url` is the link that index itself publishes to it.

### How do I run Academic Search API?

Send a keyword and a per-index result budget; everything else has a working default.

1. Set `keyword` to your search string — words, a phrase, an author name or a bare DOI.
2. Set `max_results` to how many papers you want **from each index**, minimum 1.
3. Leave `sources` empty to query all twelve, or list the indexes your field actually uses.
4. Start the run, then read the default dataset.

The smallest runnable input, and the scenario used throughout this page:

```json
{
  "keyword": "large language model hallucination",
  "max_results": 2
}
```

That input returned 20 rows in a measured run on 2026-09-07. The budget applies per index rather than per run, so the row count is roughly `max_results` times the number of indexes selected, less the works that fold together — and every row that reaches the dataset is one billed Result event.

### What data does Academic Search API return?

One row is one work, carrying 20 fields, published exactly as the index returned them.

| Field | Type | Description |
| --- | --- | --- |
| `title` | string | Title as the index published it |
| `source` | string | Which of the twelve indexes supplied this row |
| `work_url` | string | The record's own address on that index |
| `doi` | string | The DOI, and the first key works are folded on |
| `pdf_url` | string | Direct link to the open-access file |
| `published_year` | integer | Publication year |
| `published_date` | string | Publication date as `YYYY-MM-DD` |
| `citations` | integer | Citation count as that index counts it |
| `is_open` | boolean | Whether the index records the work as openly readable |
| `venue` | string | Journal, conference or publisher |
| `work_type` | string | Article, review, preprint, dataset, chapter and so on |
| `language` | string | Language code or name |
| `license` | string | Licence the index records |
| `authors` | array | Author list as the index published it |
| `category` | array | Subject, topic or keyword terms |
| `affiliations` | array | Institution names the index published for the authors |
| `abstract` | string | Abstract as the index published it |
| `source_id` | string | That index's own identifier for the record |
| `processor` | string | The Actor that produced the row |
| `processed_at` | string | UTC timestamp of the run |

A value the index did not publish stays empty rather than being filled with `unknown` or `0`, so an empty column is a fact about the source. One illustrative row, abbreviated:

```json
{
  "source": "openalex",
  "source_id": "https://openalex.org/W2556159813",
  "doi": "10.1038/nature.2016.20988",
  "title": "CRISPR gene-editing tested in a person for the first time",
  "published_year": 2016,
  "published_date": "2016-11-15",
  "authors": ["David Cyranoski"],
  "venue": "Nature",
  "citations": 443,
  "is_open": false,
  "work_url": "https://openalex.org/W2556159813",
  "work_type": "article",
  "language": "en",
  "category": ["Biotechnology and Related Fields", "CRISPR", "Genome editing"],
  "processor": "https://apify.com/",
  "processed_at": "2026-09-08T02:37:51+00:00"
}
```

### What inputs can I configure?

Three inputs, two of them required, in schema order.

| Input | Type | Required | Notes |
| --- | --- | --- | --- |
| `keyword` | string | Required | Free text sent to every selected index's own search endpoint: words, a phrase, an author name or a DOI |
| `max_results` | integer | Required | Papers from **each** selected index, minimum 1, no maximum |
| `sources` | array of enum | Optional | 12 values; empty means all twelve |

`sources` selects which indexes run rather than filtering what they return, so it is applied before the request and every value in the enum is served by the index it names. What each index contributes, measured over 462 rows from one twelve-index run on 2026-09-07:

| Index | `doi` | `abstract` | `citations` | `is_open` | `pdf_url` | `affiliations` |
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
| OpenAlex | 98% | 68% | 100% | 100% | 72% | 78% |
| Crossref | 100% | 30% | 100% | — | 5% | — |
| PubMed | 100% | 95% | 42% | — | — | — |
| DOAJ | 95% | 98% | — | 100% | 5% | — |
| arXiv | 20% | 100% | — | 100% | 100% | — |
| Europe PMC | 100% | 82% | 100% | 100% | 32% | 80% |
| OpenAIRE | — | 97% | 100% | 54% | — | — |
| CORE | 62% | 96% | 100% | 62% | 62% | — |
| DataCite | 100% | 92% | 100% | — | — | — |
| OpenReview | — | 90% | — | 100% | 100% | — |
| Semantic Scholar | 88% | 65% | 100% | 30% | 30% | — |
| CQVIP | 76% | 98% | 100% | 98% | — | 84% |

A dash marks a column that index publishes nothing into. Select on the columns you need: `europe_pmc` and `openalex` for affiliations, `arxiv` and `openreview` for a PDF link on every row, `crossref` and `datacite` for a DOI on every row.

### What platforms and markets does Academic Search API cover?

Twelve indexes, covering the cross-discipline record (OpenAlex, Crossref, Semantic Scholar), biomedicine (PubMed, Europe PMC), open-access journals (DOAJ), preprints and peer review (arXiv, OpenReview), repositories and research outputs (CORE, OpenAIRE, DataCite), and Chinese-language journals (CQVIP).

Coverage is worldwide and multilingual: `language` carries the index's own code or name, and CQVIP returns the Chinese journal record with its own titles, venues and subject terms in the same columns as the rest. The indexes document their own scope — OpenAlex describes its works entity at [docs.openalex.org](https://docs.openalex.org/api-entities/works) and NCBI documents the PubMed E-utilities at [ncbi.nlm.nih.gov](https://www.ncbi.nlm.nih.gov/books/NBK25497/).

### Why use Academic Search API?

| Capability | What it saves you |
| --- | --- |
| One query across twelve indexes | Twelve response shapes, twelve paging schemes and twelve field vocabularies collapse into one flat table your pipeline reads the same way every time |
| Folding on DOI, then title and year | A screening sheet with one row per work, including the preprint-and-submission pairs a DOI-only merge leaves duplicated |
| 20 fields on every row | `is_open`, `license` and `pdf_url` are on the row itself, so a redistribution decision is a filter rather than a second lookup |
| Per-index selection | A biomedical pipeline runs `["pubmed","europe_pmc"]` and pays for those rows alone |

The trade-off worth naming: the budget is per index, so a wide `sources` selection multiplies both the rows returned and the run's cost. Narrow `sources` when you want the count you typed.

### Who is Academic Search API for?

Developers and data teams building on the scholarly record.

- **RAG and citation pipelines** that need every retrieved document to carry a DOI, a work URL and an open-access flag before it is quoted.
- **Systematic review tooling** that runs one query across every index a protocol names and needs the duplicates already folded.
- **Research analytics** comparing `citations` within a `source` over scheduled runs to see which work in a topic is accelerating.
- **Bilingual literature work** that needs the Chinese-language record beside the English-language one in the same schema.

### How can I use Academic Search API through the API or MCP?

The Actor ID is `2L9ojnGNYk3bg0sgb`, and the `truefetch/academic-search-api` name form resolves through the same API routes wherever an ID is expected.

Start the run, poll it until `status` is `SUCCEEDED`, then read the dataset. The start call answers at once with `data.id` and `data.defaultDatasetId`; an `ACTOR.RUN.SUCCEEDED` webhook replaces the polling step in production.

```bash
## 1. Start the run
curl -X POST "https://api.apify.com/v2/acts/truefetch~academic-search-api/runs?token=APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"keyword":"large language model hallucination","max_results":2}'

## 2. Poll until data.status is SUCCEEDED
curl "https://api.apify.com/v2/actor-runs/RUN_ID?token=APIFY_TOKEN"

## 3. Read the rows
curl "https://api.apify.com/v2/datasets/DATASET_ID/items?token=APIFY_TOKEN"
```

Python, with the client waiting for the run to finish:

```python
from apify_client import ApifyClient

client = ApifyClient("APIFY_TOKEN")
run = client.actor("truefetch/academic-search-api").call(run_input={
    "keyword": "large language model hallucination",
    "max_results": 2,
})
for paper in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(paper["source"], paper["doi"], paper["title"])
```

For MCP, point your client at `https://mcp.apify.com` with your Apify token and ask it to call `truefetch/academic-search-api` with the same input; setup is in the [Apify MCP server guide](https://docs.apify.com/platform/integrations/mcp). Generated SDK and OpenAPI examples for every language are on the [API page](https://apify.com/truefetch/academic-search-api/api).

### How much does Academic Search API cost?

A paper costs $0.0025 on the FREE tier and each run adds a $0.01 Actor Start, so the smallest useful test — one paper from one index — totals $0.0125.

| Event | FREE | BRONZE | SILVER | GOLD | PLATINUM | DIAMOND |
| --- | --- | --- | --- | --- | --- | --- |
| Actor Start (per run) | $0.01 | $0.01 | $0.01 | $0.01 | $0.01 | $0.01 |
| Result (per paper) | $0.00250 | $0.00225 | $0.00200 | $0.00188 | $0.00188 | $0.00188 |

The billing unit is one row in the default dataset, and `max_results` is counted per index, so the number you type is multiplied by the number of indexes you selected. Measured across all twelve on 2026-09-07: `max_results: 10` returned 109 rows and `max_results: 200` returned 2,116. A single-index call is exact — `{"keyword":"...","max_results":25,"sources":["pubmed"]}` is 25 rows.

The Actor Start is charged once per gigabyte of run memory with a minimum of one event, and this Actor runs in half a gigabyte, so every run is charged exactly one Actor Start. Result events are charged only for rows that reach the dataset: a work two indexes both return is one row and one charge, and an index that fails to answer costs nothing. Prices can change; the current figures are on the [pricing page](https://apify.com/truefetch/academic-search-api/pricing).

### How does Academic Search API compare with alternatives?

**Against the indexes' own APIs.** Most of these indexes publish a free, documented, key-free API, and they are the authority on their own data. Going direct is better when you want one index's own facets beside the search — institution filters, citation graphs, funder rollups — or when your work lives inside a single index. This API is the better fit when you want all twelve in one call, folded to one row per work, in one field vocabulary.

**Against wiring the integrations yourself.** Twelve endpoints is twelve paging schemes, twelve identifier vocabularies, a hydration payload to parse on one of them, and the folding logic on top. That is a maintained component; here it is a JSON body.

**Against a general scholarly platform.** Discovery platforms and reference managers add full-text search, PDF storage and library management. They also carry a subscription and keep the library inside their product; this returns a per-row export keyed on DOI that your own pipeline owns.

### What are the limits and troubleshooting steps?

- **Row count is higher than `max_results` → the budget is per index.** Twelve indexes at 25 is up to 300 rows before folding. Narrow `sources` for an exact count.
- **A CQVIP selection stops at 20 rows → that is the route's whole page.** The CQVIP search page carries exactly twenty records and serves the same twenty for every page parameter, so twenty is what one run of that index returns however high `max_results` goes.
- **CORE returns fewer rows than the others → its anonymous tier limits by request count.** Measured 2026-09-07: 24 rows where other indexes returned 40, and the same request succeeded minutes later. Re-run, or leave `core` out of `sources` when the count must be predictable.
- **`citations` is empty on some rows → that index publishes no count.** arXiv, DOAJ and OpenReview publish none. Compare counts within a single `source`, because each index counts over its own reference corpus.
- **The log names an index that did not answer → it was briefly unavailable.** The rows the other indexes returned are still delivered and charged; the missing index costs nothing.

The smallest reproducible input is `{"keyword":"large language model hallucination","max_results":1,"sources":["openalex"]}`. Report a problem on the [Issues tab](https://apify.com/truefetch/academic-search-api/issues) with the run ID, the exact input JSON and one row that shows it.

### Frequently asked questions

#### Is there a research paper search api without api key?

Yes — this one. Every index it reads answers a public endpoint, so the input carries no key, no OAuth step and no credential; your Apify token starts the run and that is the whole authentication story.

#### Can I search research papers across multiple databases in one call?

Yes. One `keyword` goes to every index in `sources`, or to all twelve when `sources` is empty, and each is paged independently until its own `max_results` budget is met. Works carried by more than one index fold into a single row, and `source` records which index supplied it.

#### Is there a free research paper API?

The indexes themselves are free to query and each is linked from its own documentation. What this charges for is the twelve-index fan-out, the folding, the paging and one field vocabulary — $0.0025 a row on the FREE tier plus a $0.01 Actor Start per run.

#### Can I schedule runs to monitor a research topic over time?

Yes. Apify's scheduler runs the same input on a cron expression, and each run writes its own dataset, so comparing the `doi` sets and `citations` between two runs shows what is new and what is gaining attention.

#### How are duplicates folded?

On the DOI first — lowercased and stripped of any `https://doi.org/` prefix — and on the normalized title plus publication year where an index publishes no DOI. Case, punctuation and accents are removed before that comparison, so a title spelled two ways still matches.

#### Which fields carry author affiliations?

`affiliations` does, and three indexes fill it: Europe PMC on 80% of its rows, OpenAlex on 78% and CQVIP on 84%, measured 2026-09-07. Select those indexes in `sources` when institution data is what the run is for.

#### What does a row cost if I select every index?

`max_results` times twelve, less the works that fold, times $0.0025, plus one $0.01 Actor Start. The measured points are 109 rows at `max_results: 10` ($0.29 with the start event) and 2,116 rows at 200 ($5.30).

### Related TrueFetch Actors

- **[Multi Engine Search API](https://apify.com/truefetch/multi-engine-search-api)** — the same one-query-many-sources shape over ten web search engines, for the questions that live outside the scholarly record.
- **[Medium API](https://apify.com/truefetch/medium-api)** — long-form articles on a topic, the practitioner writing that sits between a paper and a blog post.
- **[Reddit Search API](https://apify.com/truefetch/reddit-search-api)** — what practitioners say about a paper or a method, with comments, once the reading list exists.

### Support

- [Store page](https://apify.com/truefetch/academic-search-api) · [API](https://apify.com/truefetch/academic-search-api/api) · [Issues](https://apify.com/truefetch/academic-search-api/issues)
- Community and direct support: [TrueFetch on Telegram](https://t.me/TrueFetch)

[**Run a one-result test**](https://apify.com/truefetch/academic-search-api) · [**View API**](https://apify.com/truefetch/academic-search-api/api)

**Last Updated:** September 7, 2026

# Actor input Schema

## `keyword` (type: `string`):

Words, a phrase, an author name or a DOI. Every index you select receives this same query.

## `max_results` (type: `integer`):

Papers to publish from each index you select — a per-index budget, so all 12 indexes at 25 return up to 300 rows and bill for every one. Minimum 1. Duplicates fold on DOI first and on the normalized title plus year where an index publishes no DOI, so a paper two indexes both carry is charged once.

## `sources` (type: `array`):

Which of the 12 indexes to query: openalex, crossref, pubmed, doaj, arxiv, europe\_pmc, openaire, core, datacite, openreview, semantic\_scholar and cqvip. Leave it empty to query all 12.

## Actor input object example

```json
{
  "keyword": "large language model hallucination",
  "max_results": 2
}
```

# Actor output Schema

## `results` (type: `string`):

Table view of every returned record with its source and record type.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "keyword": "large language model hallucination",
    "max_results": 2
};

// Run the Actor and wait for it to finish
const run = await client.actor("truefetch/academic-search-api").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "keyword": "large language model hallucination",
    "max_results": 2,
}

# Run the Actor and wait for it to finish
run = client.actor("truefetch/academic-search-api").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "keyword": "large language model hallucination",
  "max_results": 2
}' |
apify call truefetch/academic-search-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,truefetch/academic-search-api"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/2L9ojnGNYk3bg0sgb/builds/X7BDhKnQDFInAA1Z8/openapi.json
