Skip to main content

OAI-PMH

The Open Archives Initiative Protocol for Metadata Harvesting (OAI-PMH) is a standard protocol used by libraries, discovery services, institutional repositories, and academic indexes to collect publication metadata.

Academic Stack provides an OAI-PMH 2.0 endpoint for published journal articles. The endpoint exposes Dublin Core metadata and supports both complete and incremental harvesting.

Metadata Only

OAI-PMH distributes bibliographic metadata. It does not transfer article PDFs or replace DOI registration, Crossref deposits, sitemaps, or Google Scholar metadata.

Example Domains

This guide uses https://www.publisher.com as the example publisher domain and https://www.yourjournal.com as the example journal domain. Replace these domains—and placeholders such as {journal_slug}—with the actual domain and journal slug for your deployment.

Repository URLs

The available repository URL depends on the Academic Stack deployment type.

Enterprise / Single-Publisher Deployment

The publisher-level repository includes articles from all public journals:

https://www.publisher.com/oai

Each public journal also has an independent repository:

https://www.publisher.com/journal/{journal_slug}/oai

For example:

https://www.publisher.com/journal/nature-science/oai

The publisher-level repository uses OAI sets (setSpec) to separate journals. The journal-level repository contains only the selected journal.

PaaS / SaaS Deployment

Each journal domain represents an independent OAI-PMH repository:

https://www.yourjournal.com/oai

Only articles belonging to the journal resolved from the current domain are returned. A journal ID or slug cannot be supplied to access another journal.

There is no publisher-level or platform-wide repository in the PaaS/SaaS deployment.

Quick Verification

Open the following URLs in a browser or OAI-PMH validation tool:

https://www.yourjournal.com/oai?verb=Identify
https://www.yourjournal.com/oai?verb=ListMetadataFormats
https://www.yourjournal.com/oai?verb=ListRecords&metadataPrefix=oai_dc

A successful response is XML with an <OAI-PMH> root element and an HTTP content type of:

Content-Type: application/xml; charset=UTF-8

Supported OAI-PMH Requests

Academic Stack supports all six OAI-PMH 2.0 verbs.

VerbPurposeRequired / Allowed arguments
IdentifyReturns repository name, base URL, administrator email, datestamp policy, and protocol information.None
ListMetadataFormatsLists metadata formats supported by the repository.Optional identifier
ListSetsLists journal sets in a publisher-level repository.None
ListIdentifiersReturns record headers without Dublin Core metadata.metadataPrefix or resumptionToken
ListRecordsReturns record headers and Dublin Core metadata.metadataPrefix or resumptionToken
GetRecordReturns one record by its OAI identifier.identifier, metadataPrefix

Both HTTP GET and POST requests are supported.

Metadata Format

Academic Stack currently supports:

metadataPrefix=oai_dc

The oai_dc response uses the standard Dublin Core namespace:

http://www.openarchives.org/OAI/2.0/oai_dc/

Field Mapping Reference

Article metadata is mapped as follows:

Academic Stack fieldDublin Core element
Article titledc:title
Each authordc:creator (one element per author)
Each keyworddc:subject (one element per keyword)
Abstractdc:description
Publisher namedc:publisher
Publication or online datedc:date
Article typedc:type
DOI URLdc:identifier
Article landing-page URLdc:identifier
Journal, volume, issue, and pagesdc:source
Journal languagedc:language

Note: Only public, non-deleted articles belonging to public journals are exposed.

OAI Identifiers

Each article receives a stable OAI identifier:

oai:{PROJECT_NAME}:article:{article_id}

For example:

oai:academic_stack:article:345

The identifier is independent of:

  • Journal domains
  • Journal slugs
  • DOI changes
  • Volume and issue assignments
  • Article landing-page URLs

An OAI identifier identifies the metadata record. It is not the DOI or the article URL. DOI and landing-page URLs are provided separately as dc:identifier values.

Example request:

https://www.yourjournal.com/oai?verb=GetRecord&metadataPrefix=oai_dc&identifier=oai:academic_stack:article:345

Datestamps and Incremental Harvesting

The OAI header <datestamp> represents the article record's metadata update time, in UTC:

<datestamp>2026-07-30T08:30:00Z</datestamp>

The repository uses second-level granularity:

YYYY-MM-DDThh:mm:ssZ

Harvesters can request records updated within a date range:

https://www.yourjournal.com/oai?verb=ListRecords&metadataPrefix=oai_dc&from=2026-07-01T00:00:00Z
https://www.yourjournal.com/oai?verb=ListRecords&metadataPrefix=oai_dc&from=2026-07-01T00:00:00Z&until=2026-07-30T23:59:59Z

The from and until boundaries are inclusive. Both values must use the repository's full UTC timestamp format, and from cannot be later than until.

Metadata updates may cause an existing record to appear in a later incremental harvest. The OAI identifier remains unchanged.

Pagination and Resumption Tokens

ListRecords and ListIdentifiers return up to 100 records per response.

When more records are available, the response contains a resumptionToken:

<resumptionToken cursor="0">
eyJ2ZXJiIjoiTGlzdFJlY29yZHMi...
</resumptionToken>

Use the returned token in the next request:

https://www.yourjournal.com/oai?verb=ListRecords&resumptionToken=eyJ2ZXJiIjoiTGlzdFJlY29yZHMi...

When using a resumptionToken:

  • Send only verb and resumptionToken.
  • Do not repeat metadataPrefix, from, until, or set.
  • Continue requesting pages until no resumptionToken is returned.
  • Use the token within one hour.

The token preserves the repository scope and all filters from the original request.

Sets

Sets are available only from the Enterprise / single-publisher publisher-level repository.

List all journal sets:

https://www.publisher.com/oai?verb=ListSets

Example set:

<set>
<setSpec>journal:nature-science</setSpec>
<setName>Nature Science</setName>
</set>

Harvest one journal from the publisher repository:

https://www.publisher.com/oai?verb=ListRecords&metadataPrefix=oai_dc&set=journal:nature-science

Records returned by the publisher-level repository include the journal set in their headers:

<header>
<identifier>oai:academic_stack:article:345</identifier>
<datestamp>2026-07-30T08:30:00Z</datestamp>
<setSpec>journal:nature-science</setSpec>
</header>

Journal-level repositories do not use sets. A ListSets request to a journal-level repository returns noSetHierarchy.

Deleted Records

The repository currently declares:

<deletedRecord>no</deletedRecord>

Deleted or unpublished articles are not included in OAI responses, and the repository does not expose persistent deleted-record headers.

Harvesters should treat this repository according to the OAI-PMH deletedRecord=no policy.

Protocol Errors

Invalid requests return an OAI-PMH XML error rather than JSON or an HTML application error.

Common error codes include:

Error codeMeaning
badVerbThe verb is missing or unsupported.
badArgumentA required argument is missing, malformed, or not allowed.
cannotDisseminateFormatThe requested metadata format is unsupported.
idDoesNotExistThe identifier does not exist in the current repository.
noRecordsMatchNo records match the date, set, or repository filters.
noSetHierarchyThe journal-level repository does not support sets.
badResumptionTokenThe token is invalid, expired, or belongs to another request scope.

Example:

<error code="cannotDisseminateFormat">
Only oai_dc is supported.
</error>

For an initial full harvest:

  1. Send Identify.
  2. Send ListMetadataFormats.
  3. If using a publisher-level repository, send ListSets.
  4. Start ListRecords with metadataPrefix=oai_dc.
  5. Follow every resumptionToken until the final page.
  6. Store each record's OAI identifier and datestamp.

For later incremental harvests:

  1. Record the end time of the previous successful harvest.
  2. Send ListRecords with an overlapping from timestamp to avoid missing updates near the boundary.
  3. Follow all resumptionToken pages.
  4. Update existing records by OAI identifier.
  5. Save the new successful harvest time.
Use a Small Overlap

When scheduling incremental harvesting, use a small overlap between runs—for example, request from several minutes before the last successful harvest time. OAI identifiers are stable, so duplicate results can be safely updated by identifier.

Troubleshooting

SymptomRecommended check
noRecordsMatchConfirm that the journal and articles are public and that the date range uses UTC second-level timestamps.
cannotDisseminateFormatUse metadataPrefix=oai_dc.
badResumptionTokenRestart the harvest from the original request; tokens expire after one hour.
idDoesNotExistConfirm that the identifier belongs to the current journal repository and that the article remains public.
noSetHierarchyUse sets only with the single-publisher publisher-level /oai endpoint.
Article URL returns 404Confirm that the article is public and its volume, issue, and article number are valid.
Metadata changes are not visibleConfirm the article was saved after editing, then repeat the incremental request using its updated datestamp.

Before submitting an OAI-PMH endpoint to an indexing service, verify Identify, ListRecords, pagination, article URLs, authors, dates, DOI values, and journal metadata.