# Scholarly Record Reconciler (`flintglade/scholarly-record-reconciler`) Actor

Reconcile DOI, PMID, and bibliographic queries across Crossref, PubMed, and OpenAlex with explicit conflicts, provenance, and optional raw evidence.

- **URL**: https://apify.com/flintglade/scholarly-record-reconciler.md
- **Developed by:** [Flintglade](https://apify.com/flintglade) (community)
- **Categories:** Developer tools, Other, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 reconciled records

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use 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

## Scholarly Record Reconciler

Reconcile DOI, PMID, or bounded bibliographic queries across structured Crossref, NCBI PubMed, and OpenAlex metadata while preserving provider disagreements.

### What this does not do

- No full-text retrieval.
- No citation-count ranking or quality score.
- No medical or legal interpretation.
- No automatic correction of provider records.
- No title-only mass search beyond the strict candidate cap.
- No claim that a canonical candidate is legal or scholarly ground truth.

### Sources and authorization

Crossref REST and NCBI E-utilities are public structured metadata services. OpenAlex currently requires an API key; provide it through the secret input field. A missing or invalid key becomes visible partial coverage and is never exposed. There is no HTML scraping or hidden fallback.

### Input

Each of 1-100 `records` contains exactly one `doi`, `pmid`, or `query`. Queries require `title` and may include `firstAuthor`, `year`, and `venue`. Select at least two sources. Example:

```json
{"records":[{"doi":"10.1038/s41586-021-03819-2"}],"sources":["crossref","ncbi","openalex"],"includeRaw":false,"maxCandidatesPerSource":3,"concurrency":1}
````

### Output

Each record produces provider terminal states, normalized provider records, field comparisons, explicit conflicts, a canonical candidate only when a unique deterministic rule succeeds, and the rationale. Ambiguous candidates are retained without canonicalization. Abstract text is never copied to the dataset; only availability is recorded. Optional raw JSON is bounded and written to the run KVS with a checksum manifest.

### Pricing

`reconciled-record` costs **$0.01 per terminal reconciled record**. A result is charged only when at least two selected providers reach a terminal state and deliver reconciliation, ambiguity, or definitive absence evidence. Invalid input or fewer than two terminal providers is uncharged. Platform usage is additional.

### State

The Actor is stateless. Canonical hashes exclude timestamps, run IDs, retries, and platform metadata.

### Partial and negative results

Authentication failures, exhausted rate limits, timeouts, and malformed provider responses remain visible. Two terminal providers can still deliver a charged partial reconciliation; fewer than two cannot. Definitive cross-source absence for an exact identifier is useful terminal evidence and is charged.

### Limits

Maximum 100 records, 10 candidates per provider, and concurrency 6. Launch resources are 256-1024 MB (512 MB default) with a 300-second timeout.

### Privacy and deletion

The OpenAlex key is secret and never echoed. Crossref contact email is reduced to a provided/not-provided flag. Raw provider records are stored only when requested in the run KVS. Delete the run dataset and KVS to remove outputs.

### Source rights and attribution

Provider metadata remains attributed by source and evidence locator. NCBI's disclaimer and copyright notice apply; copyrighted abstracts are not retained. See `SOURCE_POLICY.md`.

### Limitations

Exact identifiers and exact normalized title plus author/year evidence can support a candidate. Fuzzy title similarity never establishes identity. Provider metadata can be incomplete, delayed, or conflicting.

### Support and changelog

Email support@flintglade.com with the run ID, build ID, and stable error code, but never send API keys or private raw records. See `CHANGELOG.md`.

# Actor input Schema

## `inputSchemaVersion` (type: `integer`):

Versioned runtime contract.

## `records` (type: `array`):

Each object must contain exactly one DOI, PMID, or bounded query; runtime validation enforces exclusivity.

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

Select at least two structured metadata providers.

## `mailto` (type: `string`):

Optional non-secret contact for Crossref polite-pool behavior. It is never emitted.

## `openAlexApiKey` (type: `string`):

Optional secret key required for current OpenAlex API access. Without it, OpenAlex is reported as unavailable. Runtime validation limits its length.

## `includeRaw` (type: `boolean`):

Store bounded raw JSON in the run KVS with hashes; never inline it in dataset rows.

## `maxCandidatesPerSource` (type: `integer`):

Bounded candidates for query mode.

## `concurrency` (type: `integer`):

Maximum records reconciled concurrently.

## Actor input object example

```json
{
  "inputSchemaVersion": 1,
  "records": [
    {
      "doi": "10.1038/s41586-021-03819-2"
    }
  ],
  "sources": [
    "crossref",
    "ncbi",
    "openalex"
  ],
  "includeRaw": false,
  "maxCandidatesPerSource": 5,
  "concurrency": 3
}
```

# Actor output Schema

## `defaultDataset` (type: `string`):

No description

## `rawArtifacts` (type: `string`):

No description

# 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 = {
    "records": [
        {
            "doi": "10.1038/s41586-021-03819-2"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("flintglade/scholarly-record-reconciler").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 = { "records": [{ "doi": "10.1038/s41586-021-03819-2" }] }

# Run the Actor and wait for it to finish
run = client.actor("flintglade/scholarly-record-reconciler").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "records": [
    {
      "doi": "10.1038/s41586-021-03819-2"
    }
  ]
}' |
apify call flintglade/scholarly-record-reconciler --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=flintglade/scholarly-record-reconciler",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Scholarly Record Reconciler",
        "description": "Reconcile DOI, PMID, and bibliographic queries across Crossref, PubMed, and OpenAlex with explicit conflicts, provenance, and optional raw evidence.",
        "version": "0.1",
        "x-build-id": "lRzkIRwS8xZROCdpX"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/flintglade~scholarly-record-reconciler/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-flintglade-scholarly-record-reconciler",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/flintglade~scholarly-record-reconciler/runs": {
            "post": {
                "operationId": "runs-sync-flintglade-scholarly-record-reconciler",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/flintglade~scholarly-record-reconciler/run-sync": {
            "post": {
                "operationId": "run-sync-flintglade-scholarly-record-reconciler",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "records"
                ],
                "properties": {
                    "inputSchemaVersion": {
                        "title": "Input schema version",
                        "minimum": 1,
                        "maximum": 1,
                        "type": "integer",
                        "description": "Versioned runtime contract.",
                        "default": 1
                    },
                    "records": {
                        "title": "Records",
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "description": "Each object must contain exactly one DOI, PMID, or bounded query; runtime validation enforces exclusivity.",
                        "items": {
                            "type": "object"
                        }
                    },
                    "sources": {
                        "title": "Sources",
                        "minItems": 2,
                        "maxItems": 3,
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Select at least two structured metadata providers.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "crossref",
                                "ncbi",
                                "openalex"
                            ],
                            "enumTitles": [
                                "Crossref",
                                "NCBI PubMed",
                                "OpenAlex"
                            ]
                        },
                        "default": [
                            "crossref",
                            "ncbi",
                            "openalex"
                        ]
                    },
                    "mailto": {
                        "title": "Crossref contact email",
                        "maxLength": 254,
                        "type": "string",
                        "description": "Optional non-secret contact for Crossref polite-pool behavior. It is never emitted."
                    },
                    "openAlexApiKey": {
                        "title": "OpenAlex API key",
                        "type": "string",
                        "description": "Optional secret key required for current OpenAlex API access. Without it, OpenAlex is reported as unavailable. Runtime validation limits its length."
                    },
                    "includeRaw": {
                        "title": "Retain raw provider records",
                        "type": "boolean",
                        "description": "Store bounded raw JSON in the run KVS with hashes; never inline it in dataset rows.",
                        "default": false
                    },
                    "maxCandidatesPerSource": {
                        "title": "Maximum candidates per source",
                        "minimum": 1,
                        "maximum": 10,
                        "type": "integer",
                        "description": "Bounded candidates for query mode.",
                        "default": 5
                    },
                    "concurrency": {
                        "title": "Concurrency",
                        "minimum": 1,
                        "maximum": 6,
                        "type": "integer",
                        "description": "Maximum records reconciled concurrently.",
                        "default": 3
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
