# DOI Metadata & Bibliography Enrichment (`cliqtomedia/doi-bibliography-enrichment`) Actor

Turn a list of DOIs into clean citation metadata from the official Crossref, DataCite and JaLC APIs: title, authors with ORCID, journal or book, exact dates, pages, ISSN/ISBN, license, citation counts, and an honest not-found status.

- **URL**: https://apify.com/cliqtomedia/doi-bibliography-enrichment.md
- **Developed by:** [Cliqto Media](https://apify.com/cliqtomedia) (community)
- **Categories:** Developer tools, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 doi metadata records

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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

Paste a list of DOIs and get one clean citation record per DOI. This bulk DOI metadata lookup checks each DOI at doi.org, reads the metadata from the official Crossref, DataCite or JaLC API, and returns title, authors, journal or book, exact dates, volume, pages, ISSN/ISBN, license and citation counts.

Use it to fill a reference list, check a bibliography or enrich a spreadsheet of papers and datasets. The smallest run is one DOI, and three DOIs finish in about 2 seconds.

![DOI Metadata & Bibliography Enrichment: paste DOIs, check the registration agency, get a clean citation record from Crossref, DataCite or JaLC](https://api.apify.com/v2/key-value-stores/vIG0cVmUJkoG1PBEi/records/README-BANNER-20261011.png)

### Table of contents

- [What it does](#what-it-does)
- [Quick start](#quick-start)
- [Use cases](#use-cases)
- [Input](#input)
- [Output](#output)
- [Pricing and limits](#pricing-and-limits)
- [API, export and integrations](#api-export-and-integrations)
- [Troubleshooting](#troubleshooting)
- [FAQ](#faq)
- [Data sources and licence](#data-sources-and-licence)
- [Support](#support)

### What it does

A DOI (Digital Object Identifier) is a permanent ID for a paper, book chapter, dataset or other work, for example `10.1038/nature12373`. Each DOI is registered with one registration agency. This Actor:

1. Cleans your input. It accepts `10.…`, `doi:10.…`, `https://doi.org/10.…` and `dx.doi.org` links, in any letter case.
2. Asks doi.org which agency registered each DOI.
3. Reads the record from that agency: Crossref (most journals and books), DataCite (datasets, software, repositories) or JaLC (Japan).
4. Writes one Dataset row for each input value, in your input order, with a clear `status`.

#### Good fit

- Turn a list of DOIs into a table of titles, authors, journals, years and pages.
- Check a reference list: find DOIs that are not registered or have a typo.
- Add ISSN, ISBN, publisher, license and citation counts to a list of papers.
- Mix journal articles and research datasets in one run (Crossref and DataCite).

#### Not a fit / limits

- No search by title or author. You need the DOI.
- No PDFs, full text or abstracts. The Actor reads only bibliographic metadata.
- No Open Access links (for example from Unpaywall).
- DOIs from other agencies (for example mEDRA) are only identified. The row has `status: unsupported_agency` and the agency name, but no title or authors.
- No BibTeX or RIS file. You get structured fields that you can export as JSON, CSV or Excel.
- Up to 500 DOIs per run.

### Quick start

1. Open the **Input** tab.
2. Keep the three example DOIs in **DOIs** (`dois`) or paste your own, one per line.
3. Leave **Contact email** empty, or add your own email for large runs.
4. Click **Start**.
5. Open the **Output** tab, view **Citations**. Check `status` and `title` in the first row.

Expected result: one row per DOI. With the example input you get three `complete` rows: a Nature article (Crossref), a Dryad dataset (DataCite) and a book chapter (Crossref).

### Use cases

| Buyer job | Input path | Output entity | Key fields | Next integration |
| --- | --- | --- | --- | --- |
| Build a reference table | `dois` | One citation record per DOI | `title`, `authors`, `containerTitle`, `issuedDate`, `pages` | Export CSV/Excel, or read the Dataset by API |
| Clean a bibliography | `dois` | Status per DOI | `status`, `statusReason`, `errorCode`, `doi` | Filter rows where `status` is not `complete` |
| Enrich a paper list | `dois` | Identifiers and counts | `issn`, `isbn`, `publisher`, `licenses`, `citedByCount` | Join on `doi` (always lower case) |
| Catalogue research data | `dois` | DataCite dataset record | `resourceTypeGeneral`, `publisher`, `publicationYear`, `language` | Export or API |

### Input

#### Input fields

| Field | Plain name | Type | Required | Default / prefill | Allowed values | Effect | Example | Recommendation |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| `dois` | DOIs | array of strings (one per line in the form) | yes | Prefill: 3 example DOIs. No runtime default. | 1–500 values, each up to 1,000 characters | Each value becomes one output row | `10.1038/nature12373` | Paste DOIs in any common form. Split lists longer than 500 into several runs. |
| `contactEmail` | Contact email for Crossref and DataCite | string | no | empty | A plain email address, up to 254 characters | Sent only in the request User-Agent (`mailto`) to Crossref, DataCite and doi.org. Crossref uses it to put requests in its "polite" pool. | `name@example.org` | Add it for runs of hundreds of DOIs. It is never logged or saved in the output. |

How `dois` is read:

- Accepted forms: `10.1038/nature12373`, `doi:10.1038/nature12373`, `https://doi.org/10.1038/nature12373`, `http://dx.doi.org/…` and percent-encoded links. Spaces around a value are removed. Empty lines are skipped.
- Letter case does not matter: DOIs are case-insensitive, and the output `doi` is always lower case.
- A repeated DOI (also in another form or case) gets its own row with the same data, but it is charged only once.
- A value that is not a DOI gets a free row with `status: invalid`.
- An empty list or more than 500 values is rejected before the run starts.

#### Input examples

##### Mixed list of papers and data

```json
{
  "dois": [
    "10.1038/nature12373",
    "10.5061/dryad.8515",
    "10.1007/978-3-319-24277-4_9"
  ]
}
```

Expected behavior: doi.org returns Crossref for the first and third DOI and DataCite for the second. One batch request goes to each API.
Expected output: three `complete` rows with `title`, `authors`, `containerTitle`, `issuedDate` and `agency`.
Limit or cost note: 3 found DOIs = 3 `doi-metadata` events plus the run start.

##### Reference list check with problems

```json
{
  "dois": [
    "https://doi.org/10.1038/NATURE12373",
    "10.9999/notexist",
    "not a doi",
    "doi:10.1038/nature12373"
  ],
  "contactEmail": "name@example.org"
}
```

Expected output: row 1 is `complete`; row 2 is `not_found` with `errorCode: DOI_NOT_REGISTERED`; row 3 is `invalid` (free); row 4 is a duplicate of row 1 (`complete`, free).

### Output

Each input value gives exactly one row in the default Dataset, in input order. The **Citations** view shows the main columns; the **Identifiers** view shows IDs and links. A run summary is saved as `RUN_SUMMARY` in the default Key-value store.

#### Status values

| `status` | Meaning | Charged as |
| --- | --- | --- |
| `complete` | The DOI is registered and the record has a title. | `doi-metadata` |
| `partial` | The DOI is registered, but the record has no title (`NO_TITLE`, for example a journal issue or a figure) or the agency API has no record for it yet (`RECORD_NOT_INDEXED`). Read `statusReason`. | `doi-metadata` for `NO_TITLE`; `doi-check` for `RECORD_NOT_INDEXED` |
| `not_found` | doi.org says the DOI is not registered (`DOI_NOT_REGISTERED`). | `doi-check` |
| `unsupported_agency` | The DOI is registered with another agency. `agency` names it (`UNSUPPORTED_AGENCY`). | `doi-check` |
| `invalid` | The value is not a DOI (`INVALID_DOI`). | free |
| `error` | A source failed after retries, or the run reached its time limit. Existence is unknown; the row never says "not found" in this case. | free |

#### Output fields

| Field | Meaning | Type | Can be empty? | Example / enum | Source / notes |
| --- | --- | --- | --- | --- | --- |
| `input` | Your input value exactly as given | string | no | `https://doi.org/10.1038/NATURE12373` | Input |
| `doi` | DOI in lower case | string | null for `invalid` | `10.1038/nature12373` | Cleaned input |
| `doiUrl` | Resolvable link | string | null for `invalid` | `https://doi.org/10.1038/nature12373` | Built from `doi` |
| `status` | Result type | string | no | see Status values | Actor |
| `statusReason` | Plain-English reason for any status other than `complete` | string | null for `complete` | `doi.org reports that this DOI does not exist …` | Actor |
| `agency` | Registration agency | string | null for `invalid`, `not_found`, `error` | `Crossref`, `DataCite`, `JaLC`, `mEDRA` | doi.org |
| `type` | Work type as the agency names it | string | yes | `journal-article`, `book-chapter`, `dataset` | Agency |
| `resourceTypeGeneral` | DataCite general type | string | null outside DataCite | `Dataset`, `Software`, `Text` | DataCite |
| `title` | Title, markup removed, entities decoded | string | null for `partial` and non-found rows | `Nanometre-scale thermometry in a living cell` | Agency |
| `subtitle` | Subtitle | string | yes | | Agency |
| `authors` | Authors in record order: `given`, `family`, `name`, `orcid`, `affiliations` | array | empty when the record has none | `[{"given":"G.","family":"Kucsko",…}]` | Agency. `orcid` only when the source lists it. `affiliations` is copied as the source has it and can include contact details. |
| `editors` | Editors, same shape | array | often empty | | Agency |
| `containerTitle` | Journal, book or proceedings that contains the work | string | yes | `Nature`, `ggplot2` | Agency. For a book chapter: the book. |
| `containerTitles` | All container titles as the agency lists them | array | yes | `["Use R!","ggplot2"]` | Agency |
| `seriesTitle` | Book series | string | yes | `Use R!` | Crossref |
| `publisher` | Publisher | string | yes | `Springer Science and Business Media LLC` | Agency |
| `issuedDate` | Publication date at the source precision | string | yes | `2013-07-31`, `2013-08`, `2016` | Agency. Never padded to a full date. |
| `publishedOnlineDate` | Online date | string | yes | `2013-07-31` | Crossref |
| `publishedPrintDate` | Print date | string | yes | `2013-08` | Crossref |
| `publicationYear` | Year | integer | yes | `2013` | Agency |
| `volume` | Volume | string | yes | `500` | Agency |
| `issue` | Issue | string | yes | `7460` | Agency |
| `pages` | Page range | string | yes | `54-58` | Agency |
| `articleNumber` | Article number (journals without pages) | string | yes | `e06495` | Crossref |
| `issn` | ISSNs: `value`, `type` (`print`/`electronic`/null) | array | yes | `[{"value":"0028-0836","type":"print"}]` | Agency |
| `isbn` | ISBNs, same shape | array | yes | `[{"value":"9783319242750","type":null}]` | Agency |
| `licenses` | License statements: `url`, `name`, `contentVersion`, `startDate` | array | yes | `[{"url":"http://www.springer.com/tdm",…}]` | Crossref license / DataCite rightsList |
| `referencesCount` | References deposited with the record | integer | yes | `30` | Crossref |
| `citedByCount` | Citations known to the agency | integer | yes | `1845` | Crossref is-referenced-by-count / DataCite citationCount. Other indexes count differently. |
| `language` | Language code | string | null for Crossref | `en`, `ja` | DataCite, JaLC |
| `landingUrl` | Publisher landing page | string | yes | `https://www.nature.com/articles/nature12373` | Agency |
| `sourceUpdatedAt` | When the agency last indexed or updated the record | string | yes | `2026-10-11T02:44:13Z` | Agency |
| `authorsCount` | Number of authors | integer | no (0 when none) | `8` | Actor |
| `provider` | API the row came from | string | yes | `Crossref REST API` | Actor |
| `sourceUrl` | API request the metadata was read from | string | yes | `https://api.crossref.org/works?filter=doi:…` | Actor |
| `fetchedAt` | When the row was made (ISO 8601) | string | no | `2026-10-11T09:31:37.688Z` | Actor |
| `errorCode` | Machine code | string | null for `complete` | `INVALID_DOI`, `DOI_NOT_REGISTERED`, `UNSUPPORTED_AGENCY`, `RECORD_NOT_INDEXED`, `NO_TITLE`, `SOURCE_UNAVAILABLE`, `RATE_LIMITED`, `DEADLINE_REACHED` | Actor |

`null` means the agency record does not have this value. The Actor never invents a value, for example a day or month that the source does not give.

#### Output entities and surfaces

| Situation | Where | Result shape | User action |
| --- | --- | --- | --- |
| Normal item | Dataset, view **Citations** | `complete` row with metadata | Export or use the fields |
| DOI not registered | Dataset | `not_found` row, metadata fields null | Check the DOI for a typo |
| Partial result | Dataset | `partial` row with `statusReason` | Read `statusReason`; try again later for `RECORD_NOT_INDEXED` |
| Technical failure | Dataset + `RUN_SUMMARY` | `error` row with `SOURCE_UNAVAILABLE`, `RATE_LIMITED` or `DEADLINE_REACHED` | Run these DOIs again later; error rows are free |
| Run overview | Key-value store `RUN_SUMMARY` | counts by status and agency, HTTP stats, warnings, sources | Check `status` and `counts` |

#### Output example

```json
{
  "input": "10.1038/nature12373",
  "doi": "10.1038/nature12373",
  "doiUrl": "https://doi.org/10.1038/nature12373",
  "status": "complete",
  "statusReason": null,
  "agency": "Crossref",
  "type": "journal-article",
  "title": "Nanometre-scale thermometry in a living cell",
  "authors": [
    { "given": "G.", "family": "Kucsko", "name": "G. Kucsko", "orcid": null, "affiliations": [] }
  ],
  "containerTitle": "Nature",
  "publisher": "Springer Science and Business Media LLC",
  "issuedDate": "2013-07-31",
  "publishedPrintDate": "2013-08",
  "publicationYear": 2013,
  "volume": "500",
  "issue": "7460",
  "pages": "54-58",
  "issn": [
    { "value": "0028-0836", "type": "print" },
    { "value": "1476-4687", "type": "electronic" }
  ],
  "authorsCount": 8,
  "provider": "Crossref REST API",
  "errorCode": null
}
```

This example is trimmed: it shows one row from the first input example, with one of eight authors and some fields left out. Counts such as `citedByCount` change over time.

#### Field names compared with other DOI tools

If you move from another DOI tool, these names may help:

| Common name elsewhere | Field here |
| --- | --- |
| `journal` | `containerTitle` |
| `publishedDate` | `issuedDate` |
| `publishedYear` | `publicationYear` |
| `page` | `pages` |
| `citationCount` | `citedByCount` |
| `url` | `doiUrl` (DOI link) or `landingUrl` (publisher page) |
| `authors` as one string | `authors[].name` |

### Pricing and limits

#### Pricing unit

This Actor uses pay-per-event pricing. You pay for each DOI result and once for each run start. Platform usage is included.

| Event | When it is charged | Free plan | Bronze | Silver | Gold |
| --- | --- | ---: | ---: | ---: | ---: |
| `doi-metadata` | A `complete` row, or a `partial` row with metadata (`NO_TITLE`) | $0.0018 | $0.0017 | $0.0016 | $0.0015 |
| `doi-check` | A `not_found`, `unsupported_agency` or `RECORD_NOT_INDEXED` row | $0.0005 | $0.0005 | $0.0005 | $0.0005 |
| Actor start | Once per run (memory is 256 MB, so always one event) | $0.001 | $0.001 | $0.001 | $0.001 |

Free: `invalid` rows, `error` rows and repeated DOIs. A run where no value is a DOI fails with a clear message and charges only the start.

#### Cost examples (Free plan prices)

| Scenario | Input scope | Expected events | Base charge | Total |
| --- | --- | --- | ---: | ---: |
| Example input | 3 DOIs, all found | 3 × `doi-metadata` | $0.001 start | $0.0064 |
| Small list | 100 DOIs, all found | 100 × `doi-metadata` | $0.001 start | $0.181 |
| Reference check | 100 DOIs: 90 found, 5 not registered, 5 invalid | 90 × `doi-metadata`, 5 × `doi-check` | $0.001 start | $0.1655 |
| Full run | 500 DOIs, all found | 500 × `doi-metadata` | $0.001 start | $0.901 |

#### Spending limit

If you set a maximum cost per run, the Actor stops before it goes over the limit. Rows already saved stay in the Dataset; DOIs after the limit get no row, and `RUN_SUMMARY.status` is `CAPPED`.

#### Limits

- Up to 500 DOIs per run. In tests, 500 DOIs finished in about 24 seconds and 100 DOIs in about 6 seconds.
- The Actor reads sources for up to 240 seconds. DOIs not processed in time get a free `error` row with `DEADLINE_REACHED`.
- It sends batch requests (up to 50 DOIs each) and retries temporary failures. It respects source rate limits.

### API, export and integrations

- **API:** start the Actor with the Apify API and read the Dataset items. The `doi` field is lower case, so you can join on it.
- **Export:** download the Dataset as JSON, CSV, Excel, XML or RSS from the Output tab.
- **Scheduling:** you can run it on an Apify schedule, for example to refresh citation counts.

#### Use with AI agents (MCP)

AI agents can call this Actor through the Apify MCP server: add `https://mcp.apify.com?tools=cliqtomedia/doi-bibliography-enrichment` to your MCP client (Claude, Cursor, VS Code and others). The MCP server needs your Apify account (OAuth sign-in or an Apify API token); the DOI sources need no key. The agent builds the input from the input schema. The smallest useful input:

```json
{ "dois": ["10.1038/nature12373"] }
```

Key output fields for an agent: `status` (`complete`, `not_found`, …), `title`, `authors`, `containerTitle`, `issuedDate`, `agency`, `errorCode`. A call with 10 DOIs usually finishes in a few seconds and costs about $0.019. Up to 500 DOIs fit in one run. Treat `error` rows as "unknown", not as "does not exist".

### Troubleshooting

| Symptom | Check | Action |
| --- | --- | --- |
| `not_found` for a DOI you trust | `input`, `doi` | Look for a typo or extra characters. doi.org itself says the DOI is not registered. |
| `invalid` row | `input`, `statusReason` | After cleaning, the value is not in the form `10.<prefix>/<suffix>`. Fix the value. |
| `partial` with `RECORD_NOT_INDEXED` | `statusReason` | The DOI is registered, but the agency API does not have the record yet. Try again later. |
| `partial` with `NO_TITLE` | `type` | Records such as journal issues or figures often have no title. This is source data. |
| `unsupported_agency` | `agency` | The DOI belongs to another agency. This Actor does not read its metadata. |
| `error` rows | `errorCode`, `RUN_SUMMARY.warnings` | A source was down or slow. Run only these DOIs again later; they were not charged. |
| Run rejected at start | Input | `dois` is empty or has more than 500 values. |

### FAQ

#### Do I need an API key?

No. Crossref, DataCite, JaLC and doi.org are open. You only need your Apify account.

#### Why is a date only a year or a month?

The Actor keeps the precision of the source. If the record says `2016`, you get `2016`, not `2016-01-01`.

#### Why is `citedByCount` different from Google Scholar?

It is the count known to the registration agency (Crossref or DataCite). Other indexes count different sources.

#### How fresh is the data?

Each run reads the sources live. Each row has `fetchedAt` (our read time) and `sourceUpdatedAt` (when the agency last updated the record).

#### Can I get abstracts or PDFs?

No. The Actor returns bibliographic metadata only.

### Data sources and licence

- [doi.org](https://www.doi.org/) — registration agency of each DOI.
- [Crossref REST API](https://api.crossref.org) — bibliographic metadata. Abstracts are not exported.
- [DataCite REST API](https://api.datacite.org) — metadata under CC0.
- [JaLC](https://japanlinkcenter.org) — Japanese records, read through doi.org content negotiation.

This Actor is independent and not endorsed by Crossref, DataCite, JaLC or the DOI Foundation.

### Support

Use the **Issues** tab of this Actor. Add the run ID, the DOI and the `status` or `errorCode` you saw. Do not send API tokens or private data.

# Actor input Schema

## `dois` (type: `array`):

Up to 500 DOIs per run, one per line. Accepted forms: 10.1038/nature12373, doi:10.1038/nature12373, https://doi.org/10.1038/nature12373, dx.doi.org links and percent-encoded links. Case does not matter; a repeated DOI gets its own row but is charged once. Values that are not DOIs get an invalid row and are free.

## `contactEmail` (type: `string`):

Optional. Your own email, sent only to Crossref, DataCite and doi.org in the request User-Agent ("mailto"), as they ask of heavy users. Crossref uses it to put requests in its polite pool. It is never logged or written to the output.

## Actor input object example

```json
{
  "dois": [
    "10.1038/nature12373",
    "10.5061/dryad.8515",
    "10.1007/978-3-319-24277-4_9"
  ]
}
```

# Actor output Schema

## `citations` (type: `string`):

Citation rows as a table.

## `identifiers` (type: `string`):

ISSN, ISBN, licenses and counts.

## `runSummary` (type: `string`):

Status, counts by status and agency, charged events, sources and request statistics.

# 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 = {
    "dois": [
        "10.1038/nature12373",
        "10.5061/dryad.8515",
        "10.1007/978-3-319-24277-4_9"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("cliqtomedia/doi-bibliography-enrichment").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 = { "dois": [
        "10.1038/nature12373",
        "10.5061/dryad.8515",
        "10.1007/978-3-319-24277-4_9",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("cliqtomedia/doi-bibliography-enrichment").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 '{
  "dois": [
    "10.1038/nature12373",
    "10.5061/dryad.8515",
    "10.1007/978-3-319-24277-4_9"
  ]
}' |
apify call cliqtomedia/doi-bibliography-enrichment --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,cliqtomedia/doi-bibliography-enrichment"
        }
    }
}
```

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/gToiQUCGzKY15VYBM/builds/4i67m2UcGAhPchH7f/openapi.json
