# API Sources

`axm-bib` integrates three academic APIs. This page explains what each provides and how they complement each other.

## Semantic Scholar

**URL:** `https://api.semanticscholar.org/graph/v1`

The primary search engine. Covers 200M+ papers from all fields.

| Feature | Details |
|---|---|
| **Search** | Full-text relevance ranking |
| **Fields** | Title, authors, year, abstract, DOI, arXiv ID, citations, venue, OA PDF |
| **Rate limit** | ~100 req / 5 min (public), 1 req/sec (with API key) |
| **Auth** | Optional `x-api-key` header |

**Used by:** `BibPipeline.search()` (primary)

---

## CrossRef

**URL:** `https://api.crossref.org`

The authoritative source for DOI metadata. Covers 140M+ DOI records.

| Feature | Details |
|---|---|
| **DOI resolution** | Full metadata + BibTeX formatting |
| **Search** | Title-based search (fallback for S2) |
| **Rate limit** | Generous (polite pool with `mailto` header) |
| **Auth** | None required |

**Used by:**

- `BibPipeline.doi_to_bibtex()` — DOI → BibTeX
- `BibPipeline.search()` — Fallback when Semantic Scholar fails

---

## Unpaywall

**URL:** `https://api.unpaywall.org/v2`

Finds open-access versions of papers. Covers 30M+ OA articles.

| Feature | Details |
|---|---|
| **OA lookup** | Returns list of OA locations per DOI |
| **Priority** | Repositories (arXiv) before publishers |
| **Rate limit** | 100K req/day |
| **Auth** | Email address required (`?email=...`) |

**Used by:** `BibPipeline.download_pdf()`

### OA Location Priority

Unpaywall returns multiple OA locations. `axm-bib` sorts them:

1. **Repository** (arXiv, PubMed Central) — reliable, no 403s
2. **Publisher** — may return 403 Forbidden

If a URL returns 403, the next one is tried automatically.

---

## Fallback Strategy

```mermaid
graph LR
    Search["Search"] --> S2["Semantic Scholar"]
    S2 -->|fails| CR["CrossRef"]

    DOI["DOI → BibTeX"] --> CR2["CrossRef"]

    PDF["PDF Download"] --> UW["Unpaywall"]
    UW --> Repo["Repository URL"]
    Repo -->|403| Pub["Publisher URL"]
    Pub -->|403| Err["Error"]
```
