Books — entry 006 of 22
Crossref Metadata Search
Crossref's REST API is a keyless way to search and retrieve bibliographic metadata — titles, authors, funders, references, licensing — for the 160-million-plus scholarly works it has assigned DOIs to, spanning journal articles, books, chapters, and datasets. Anonymous requests land in a low-throughput default pool; adding a mailto contact parameter moves you into a faster, still-free "polite" pool, and a paid Metadata Plus subscription removes the concurrency cap for production integrations. It's run directly by the Crossref non-profit rather than a third party.
Crossref's REST API is a keyless way to search 160-million-plus scholarly works by bibliographic string and get back trimmed JSON metadata -- title, DOI, type -- via a `select=` parameter that shrinks the payload to only the fields asked for. A live GET this run against `/works?query.bibliographic=atlas+of+api&rows=1&select=title,DOI,type` returned a genuine 300 B single-result record; the byte-identical query with `select=` removed returned 1,915 B, so the trimming is real rather than cosmetic.
GreatAPIs Score
Auth quickstart
- No API key, signup, or credit card required for the base search -- a live GET this run returned real results with zero credentials. Adding a `mailto=` query parameter (any real contact address) moves the same request into Crossref's faster "polite pool": a live GET this run with `mailto=test@example.com` on the identical query returned `x-rate-limit-limit: 3` / `x-api-pool: polite-array`, versus `x-rate-limit-limit: 1` / `x-api-pool: public-array` on the anonymous request moments before -- both still fully free, no key ever issued.
Your key is stored only in this browser (localStorage) and sent directly to the API — never to greatapis.
Search scholarly works by bibliographic string, trimmed to three fields
GEThttps://api.crossref.org/works?query.bibliographic=atlas+of+api&rows=1&select=title,DOI,type
{"status":"ok","message-type":"work-list","message-version":"1.0.0","message":{"facets":{},"total-results":177895,"items":[{"title":["atlas: Stanford 'ATLAS' Search Engine API"],"DOI":"10.32614\/cran.package.atlas","type":"dataset"}],"items-per-page":1,"query":{"start-index":0,"search-terms":null}}}`select=title,DOI,type` is what keeps this 300 B -- dropping it from this exact query, and changing nothing else, returned 1,915 B on a live GET this run. Separately, and not a `select=` comparison since that route rejects the parameter outright (see the gotchas): the single-work route returns each record in full by default -- abstract, references, funders, license terms -- which is why a live GET this run against `/works/10.1371/journal.pone.0000308` ran 11,960 B for that one work.
Try it
Developer reference
https://api.crossref.org1 request/second anonymously (`x-rate-limit-limit: 1`, confirmed live this run); adding a `mailto=` contact parameter to enter the free "polite pool" raises this to 3 requests/second (`x-rate-limit-limit: 3`), confirmed live the same run. A separate `/works/{doi}` single-work lookup draws from its own pool at 5 requests/second.
- GET/works
- GET/works/{doi}
Gotchas & limits
- Anonymous and polite-pool requests carry genuinely **different rate limits in their own headers** -- confirmed live this run on the identical query: the anonymous call returned `x-rate-limit-limit: 1` / `x-rate-limit-interval: 1s` / `x-api-pool: public-array`, while adding `mailto=test@example.com` returned `x-rate-limit-limit: 3` / `x-api-pool: polite-array` -- three times the throughput for one added query parameter, no signup required.
- A single-DOI lookup (`/works/{doi}`) draws from a **third, separate pool** -- a live GET this run against `/works/10.1371/journal.pone.0000308` returned `x-rate-limit-limit: 5` / `x-api-pool: public-single`, a different limit and pool name than either search variant above.
- `select=` genuinely shrinks the payload, not just which keys are visible -- confirmed live this run with a like-for-like pair on one identical query: `/works?query.bibliographic=atlas+of+api&rows=1&select=title,DOI,type` returned **300 B**, while the same request with `select=` simply removed returned **1,915 B**. About a 6x saving on a single-result query, and it compounds as `rows=` grows.
- `select=` is **rejected outright on the single-work route** -- a live GET this run against `/works/10.1371/journal.pone.0000308?select=title,DOI,type` returned a genuine **HTTP 400** with a 164-byte `{"status":"failed","message-type":"validation-failure","message":[{"type":"parameter-not-allowed","value":"select","message":"This route does not support select"}]}`. That same record fetched the only way that route allows -- no `select=` -- ran **11,960 B** live this run, so a per-DOI lookup is both fat and untrimmable. To get one work trimmed, query it through the search route instead: a live GET this run against `/works?filter=doi:10.1371/journal.pone.0000308&rows=1&select=title,DOI,type` returned the same work at **336 B**.
- A DOI's own slash (e.g. `10.1371/journal.pone.0000308`) is passed as a **literal, unencoded path segment** after `/works/` -- confirmed live this run -- Crossref's own route parses everything after `/works/` as the DOI, so it doesn't need URL-encoding.