Skip to content

Latest commit

Β 

History

29 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

DOIphin 🐬

DOI Metadata Aggregator

Given a DOI, query 14 scholarly APIs in parallel (12 Phase 1 + 2 Phase 3), normalize the results, detect cross-source conflicts, and return unified metadata with derived analyses.

Sources: CrossRef, DataCite, OpenAlex, Semantic Scholar, Unpaywall, Europe PMC, OpenAIRE, NIH Reporter, Zenodo, Dryad, ORCID, Entrez/PubMed + Phase 3: Europe PMC Annotations, ClinicalTrials.gov

Quick Start

Requirements: Python 3.11+

# Clone and install
git clone https://github.com/Kaimen-Inc/doi-metadata.git
cd doi-metadata
pip install -e ".[dev]"

# Configure API credentials
cp .env.example .env
# Edit .env with your email/keys (see Configuration below)

# CLI lookup
doi-metadata lookup 10.1038/sdata.2016.18
doi-metadata lookup 10.1038/nature11247 --format json --include-raw

# Start REST API
uvicorn doi_metadata.api:app --host 0.0.0.0 --port 8000

# Query the API
curl http://localhost:8000/v1/lookup/10.1038/sdata.2016.18

Configuration

Copy .env.example to .env and fill in at minimum the three email fields β€” most APIs work without keys but require an email for polite/authenticated access:

# Required (email-based, no signup needed)
CROSSREF_EMAIL=your@email.com
UNPAYWALL_EMAIL=your@email.com
OPENALEX_EMAIL=your@email.com

Optional keys for higher rate limits or additional data:

Variable Where to get it Why
OPENALEX_API_KEY openalex.org/settings/api Required after Feb 13, 2026
SEMANTIC_SCHOLAR_API_KEY semanticscholar.org/product/api Dedicated 1 req/s pool
OPENAIRE_API_KEY aai.openaire.eu Higher rate limits
ORCID_CLIENT_ID / ORCID_CLIENT_SECRET orcid.org/developer-tools Author disambiguation
ENTREZ_EMAIL Recommended for NCBI E-utilities NCBI contact email
ENTREZ_API_KEY ncbi.nlm.nih.gov/account 10 req/s with key, 3 req/s without

All other APIs (DataCite, Europe PMC, NIH Reporter, Zenodo, Dryad, ClinicalTrials.gov) are fully public and need no credentials.

Usage

CLI

# Human-readable summary
doi-metadata lookup 10.1038/nature11247

# Full JSON output
doi-metadata lookup 10.1038/nature11247 --format json

# Include raw API responses from each source
doi-metadata lookup 10.1038/nature11247 --format json --include-raw

# Skip link-following phase (faster, less data)
doi-metadata lookup 10.5061/dryad.8sf3tx0h5 --no-follow

# Debug logging
doi-metadata lookup 10.1038/nature11247 --verbose

REST API

# Start the server
doi-metadata-api
# or: uvicorn doi_metadata.api:app --host 0.0.0.0 --port 8000

# Query
curl http://localhost:8000/v1/lookup/10.1038/s41586-023-06647-8

# Interactive docs
open http://localhost:8000/docs

Python Library

import asyncio
from doi_metadata import lookup

result = asyncio.run(lookup("10.1038/s41586-023-06647-8"))

# Per-source data
for name, src in result.sources.items():
    if src.found:
        print(f"{name}: {src.citation_count} citations, {len(src.authors)} authors")

# Identifier crosswalk (PMID, PMCID, ORCIDs, etc.)
print(result.crosswalk.pmid, result.crosswalk.pmcid)

# Derived analyses
print(result.analyses.impact)    # citation counts, FWCI, percentiles
print(result.analyses.funding)   # merged funding from all sources
print(result.analyses.oa_audit)  # cross-source OA verification
print(result.analyses.authors)   # disambiguated author network
print(result.analyses.topics)    # unified subject mapping

# Conflicts between sources
for c in result.conflicts.conflicts:
    print(f"{c.field}: {c.values}")

How It Works

DOI (input)
 |
 +--> Phase 1: Fetch all 12 APIs in parallel
 |    CrossRef, DataCite, OpenAlex, Semantic Scholar, Unpaywall,
 |    Europe PMC, OpenAIRE, NIH Reporter, Zenodo, Dryad, ORCID,
 |    Entrez/PubMed
 |    (404s are expected -- not every DOI exists in every source)
 |
 +--> Phase 2: Build identifier crosswalk
 |    Harvest PMID, PMCID, arXiv, ORCIDs, ROR IDs, grant numbers, NCT IDs
 |
 +--> Phase 3: Follow discovered links
 |    DataCite reverse search for linked datasets
 |    Europe PMC Annotations (text-mined genes, diseases, organisms via PMCID)
 |    ClinicalTrials.gov (trial details via NCT IDs from CrossRef)
 |
 +--> Phase 4: Reconcile + Analyze
      Detect conflicts, run 7 derived analyses

When sources disagree (e.g., citation counts), all values are preserved with provenance rather than picking a winner.

14 Data Sources

Source Unique Value
CrossRef References, funders, clinical trials, Crossmark corrections
DataCite Dataset version chains, geolocations, related identifiers
OpenAlex FWCI, concept hierarchy, citation percentiles, institutional data
Semantic Scholar Citation intents, TLDR summaries, influential citation flags
Unpaywall OA status per location, version tracking (published/accepted/submitted)
Europe PMC MeSH headings, chemicals, text-mined accessions, grants
OpenAIRE EU project linkages, BIP! impact indicators, FOS/SDG classifications
NIH Reporter NIH grant-publication linkages, relative citation ratio
Zenodo Files with checksums, download stats, version chains, communities
Dryad Dataset methods, usage notes, ROR-linked affiliations
ORCID Author disambiguation, employment/education history
Entrez/PubMed Authoritative PMID, publication types, gene symbols, databank accessions
Europe PMC Annotations Text-mined gene/protein, disease, organism, chemical entities (Phase 3)
ClinicalTrials.gov Full trial protocol, sponsor, enrollment, outcomes (Phase 3)

7 Derived Analyses

Each lookup produces these cross-source analyses:

  • Impact Profile -- FWCI, citation trends, influential citation ratio
  • Funding Landscape -- Merged funders from CrossRef + Europe PMC + OpenAIRE + NIH + Zenodo + Entrez
  • Dataset Reuse -- DataCite reverse search, related software/data counts
  • Author Network -- ORCID coverage, institutional breakdown, country distribution
  • Grant Siblings -- Other publications under the same NIH grants
  • OA Audit -- Cross-check OA status across Unpaywall, OpenAlex, OpenAIRE, Europe PMC
  • Topic Profile -- Fields of study, MeSH terms, SDG mappings, keywords

API

GET /v1/lookup/{doi}

Full metadata lookup. Returns unified JSON with all source results, crosswalk, conflicts, linked datasets, and analyses.

Query params:

  • include_raw=true -- Include raw API responses per source
  • follow_links=false -- Skip Phase 3 link following

Example response structure:

{
  "doi": "10.1038/sdata.2016.18",
  "registration_agency": "crossref",
  "sources": {
    "crossref": {"found": true, "title": "...", "citation_count": 12733, "...": "..."},
    "openalex": {"found": true, "citation_count": 16440, "...": "..."},
    "openaire": {"found": true, "citation_count": 12213, "...": "..."}
  },
  "crosswalk": {
    "doi": "10.1038/sdata.2016.18",
    "pmid": "26978244",
    "pmcid": "PMC4792175",
    "orcids": ["0000-0001-6960-357x", "..."]
  },
  "conflicts": {
    "conflict_count": 6,
    "conflicts": [
      {"field": "citation_count", "risk": "high",
       "values": {"crossref": 12733, "openalex": 16440, "semantic_scholar": 14131}}
    ]
  },
  "datacite_linked_datasets": ["..."],
  "analyses": {
    "impact": {"fwci": 319.42, "citation_comparison": {"...": "..."}},
    "funding": {"total_funders": 5, "funding_agencies": ["..."]},
    "oa_audit": {"consensus_status": "gold", "consensus_is_oa": true}
  }
}

GET /health

Health check. Returns {"status": "ok"}.

Test Results

We tested with 9 DOIs spanning data papers, consortium papers, datasets, software, preprints, and regular research articles. See tests/api_results/analysis.md for the full report.

Paper Type Sources Found Conflicts Linked Datasets
FAIR Principles Edge case 8/11 6 25
ENCODE (Nature) Consortium 8/11 7 25
pandas (Zenodo) Software 4/10 3 25
MIMIC-CXR Data paper 8/11 6 7
AlphaFold Methods 7/10 5 25
UK Biobank Resource 8/11 5 25

Key findings:

  • CrossRef articles consistently hit 7-8 sources
  • Citation counts diverge 30-170% across sources (OpenAlex highest, Europe PMC lowest)
  • DataCite DOIs get sparser coverage (1-4 sources)

Per-paper reports: tests/api_results/

Project Structure

doi_metadata/
β”œβ”€β”€ api.py              # FastAPI REST API
β”œβ”€β”€ cli.py              # Typer CLI
β”œβ”€β”€ client.py           # Python client
β”œβ”€β”€ config.py           # Settings from .env
β”œβ”€β”€ models.py           # Pydantic models (50+ types)
β”œβ”€β”€ orchestrator.py     # 4-phase pipeline
β”œβ”€β”€ resolver.py         # DOI registration agency detection
β”œβ”€β”€ crosswalk.py        # Identifier crosswalk builder
β”œβ”€β”€ output.py           # Output formatters
β”œβ”€β”€ fetchers/           # 14 API fetchers (12 Phase 1 + 2 Phase 3)
β”‚   β”œβ”€β”€ base.py         # Shared HTTP client with retry/backoff
β”‚   β”œβ”€β”€ crossref.py
β”‚   β”œβ”€β”€ datacite.py
β”‚   β”œβ”€β”€ openalex.py
β”‚   β”œβ”€β”€ semantic_scholar.py
β”‚   β”œβ”€β”€ unpaywall.py
β”‚   β”œβ”€β”€ europe_pmc.py
β”‚   β”œβ”€β”€ europe_pmc_annotations.py
β”‚   β”œβ”€β”€ openaire.py
β”‚   β”œβ”€β”€ nih_reporter.py
β”‚   β”œβ”€β”€ zenodo.py
β”‚   β”œβ”€β”€ dryad.py
β”‚   β”œβ”€β”€ orcid.py
β”‚   β”œβ”€β”€ entrez.py
β”‚   └── clinical_trials.py
β”œβ”€β”€ reconciliation/     # Cross-source conflict detection
β”‚   └── engine.py
└── analyses/           # 7 derived analysis modules
    β”œβ”€β”€ impact_profile.py
    β”œβ”€β”€ funding_landscape.py
    β”œβ”€β”€ dataset_reuse.py
    β”œβ”€β”€ author_network.py
    β”œβ”€β”€ grant_siblings.py
    β”œβ”€β”€ oa_audit.py
    └── topic_profile.py

Development

pip install -e ".[dev]"
pytest
ruff check .
mypy doi_metadata/

Documentation

Design Principles

  • Never pick a winner -- When sources disagree, surface all values with provenance. Let the consumer decide.
  • 404 is not an error -- Not every DOI exists in every source. A DataCite 404 for a CrossRef article is expected.
  • Parallel everything -- All 12 Phase 1 API calls run concurrently via asyncio.gather.
  • Schema-first -- 50+ Pydantic models ensure type safety and serialization.

License

See LICENSE for details.

About

All you need to know about doi

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages