Books — entry 006 of 22

Crossref Metadata Search

Verified Oct 2026

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.

booksacademicdoimetadatacrossref
AuthenticationNone requiredCall it straight away — no key, no signup.
HTTPSSupportedTraffic is encrypted in transit.
CORSEnabledCallable directly from browser JavaScript.
PricingFreemiumA usable free tier exists, with paid plans for more volume.
FormatsJSONResponses can be requested as JSON.

GreatAPIs Score

Score91out of 100
Authentication25/25No authentication required
Pricing17/20Freemium tier available
Docs20/20Machine-readable spec file bundled
Formats9/15Single response format
Freshness20/20Verified within 6 months

Embed this badge

Scored 91 on greatapis.com
<a href="https://greatapis.com/api/crossref-metadata-search/"><img src="https://greatapis.com/badge/crossref-metadata-search.svg" alt="Scored 91 on greatapis.com"></a>

Auth quickstart

  1. 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.
Stored keyNo key stored

Your key is stored only in this browser (localStorage) and sent directly to the API — never to greatapis.

Endpoints

Works3

Endpoints that expose works related data<a name='works'></a>

GET/works
Parameters
NameInRequiredType
rowsquerynointeger
orderquerynostring
facetquerynostring
samplequerynointeger
sortquerynostring
offsetquerynointeger
mailtoquerynostring
selectquerynostring
queryquerynostring
filterquerynostring
cursorquerynostring
Responses
StatusDescriptionSchema
200A list of worksWorksMessage
GET/works/{doi}
Parameters
NameInRequiredType
doipathyesstring
Responses
StatusDescriptionSchema
200The work identified by {doi}.WorkMessage
404The work identified by {doi} does not exist.—
GET/works/{doi}/agency
Parameters
NameInRequiredType
doipathyesstring
Responses
StatusDescriptionSchema
200The agency associated with work identified by {doi}.AgencyMessage
404The work identified by {doi} does not exist.—
Journals3

Endpoints that expose journal related data<a name='journals'></a>

GET/journals
Parameters
NameInRequiredType
cursorquerynostring
queryquerynostring
rowsquerynointeger
mailtoquerynostring
offsetquerynointeger
Responses
StatusDescriptionSchema
200A list of journals.JournalsMessage
GET/journals/{issn}
Parameters
NameInRequiredType
issnpathyesarray
Responses
StatusDescriptionSchema
200The journal identified by {issn}.JournalMessage
404The journal identified by {issn} does not exist.—
GET/journals/{issn}/works
Parameters
NameInRequiredType
rowsquerynointeger
orderquerynostring
facetquerynostring
samplequerynointeger
sortquerynostring
offsetquerynointeger
mailtoquerynostring
selectquerynostring
queryquerynostring
filterquerynostring
cursorquerynostring
issnpathyesarray
Responses
StatusDescriptionSchema
200A list of works.WorksMessage
Funders3

Endpoints that expose funder related data<a name='funders'></a>

GET/funders
Parameters
NameInRequiredType
filterquerynostring
cursorquerynostring
queryquerynostring
rowsquerynointeger
mailtoquerynostring
offsetquerynointeger
Responses
StatusDescriptionSchema
200A list of funders.FundersMessage
GET/funders/{id}
Parameters
NameInRequiredType
idpathyesstring
Responses
StatusDescriptionSchema
200The funder identified by {id}.FunderMessage
404The funder identified by {id} does not exist.—
GET/funders/{id}/works
Parameters
NameInRequiredType
rowsquerynointeger
orderquerynostring
facetquerynostring
samplequerynointeger
sortquerynostring
offsetquerynointeger
mailtoquerynostring
selectquerynostring
queryquerynostring
filterquerynostring
cursorquerynostring
idpathyesstring
Responses
StatusDescriptionSchema
200A list of works.WorksMessage
Members3

Endpoints that expose member related data<a name='members'></a>

GET/members
Parameters
NameInRequiredType
cursorquerynostring
filterquerynostring
queryquerynostring
rowsquerynointeger
mailtoquerynostring
offsetquerynointeger
Responses
StatusDescriptionSchema
200A list of members.MembersMessage
GET/members/{id}
Parameters
NameInRequiredType
idpathyesinteger
Responses
StatusDescriptionSchema
200The prefix data identified by {id}.MemberMessage
404The prefix data identified by {id} does not exist.—
GET/members/{id}/works
Parameters
NameInRequiredType
rowsquerynointeger
orderquerynostring
facetquerynostring
samplequerynointeger
sortquerynostring
offsetquerynointeger
mailtoquerynostring
selectquerynostring
queryquerynostring
filterquerynostring
cursorquerynostring
idpathyesinteger
Responses
StatusDescriptionSchema
200A list of works.WorksMessage
Prefixes2

Endpoints that expose prefix related data<a name='prefixes'></a>

GET/prefixes/{prefix}
Parameters
NameInRequiredType
prefixpathyesstring
Responses
StatusDescriptionSchema
200The prefix data identified by {prefix}.PrefixMessage
404The prefix data identified by {prefix} does not exist.—
GET/prefixes/{prefix}/works
Parameters
NameInRequiredType
rowsquerynointeger
orderquerynostring
facetquerynostring
samplequerynointeger
sortquerynostring
offsetquerynointeger
mailtoquerynostring
selectquerynostring
queryquerynostring
filterquerynostring
cursorquerynostring
prefixpathyesstring
Responses
StatusDescriptionSchema
200A list of works.WorksMessage
Types3

Endpoints that expose type related <a name='types'></a>

GET/types
Parameters
NameInRequiredType
rowsquerynointeger
mailtoquerynostring
offsetquerynointeger
Responses
StatusDescriptionSchema
200A collection of types.TypesMessage
GET/types/{id}
Parameters
NameInRequiredType
idpathyesstring
Responses
StatusDescriptionSchema
200The type identified by {id}.TypeMessage
404The type identified by {id} does not exist.—
GET/types/{id}/works
Parameters
NameInRequiredType
rowsquerynointeger
orderquerynostring
facetquerynostring
samplequerynointeger
sortquerynostring
offsetquerynointeger
mailtoquerynostring
selectquerynostring
queryquerynostring
filterquerynostring
cursorquerynostring
idpathyesstring
Responses
StatusDescriptionSchema
200A list of works.WorksMessage
Licenses1

Endpoints that expose license related data<a name='licenses'></a>

GET/licenses
Parameters
NameInRequiredType
queryquerynostring
cursorquerynostring
rowsquerynointeger
mailtoquerynostring
offsetquerynointeger
Responses
StatusDescriptionSchema
200A list of licenses.LicensesMessage

Try it

Developer reference

Base URLhttps://api.crossref.org
Rate limit

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

Key endpoints
  • 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.

Changelog

  • Aug 2026gained rate limits

See every tracked change ↗ ·Subscribe with RSS ↗