Discover/JSTOR API
live

JSTOR APIjstor.org

Access JSTOR's academic content via API. Search articles, retrieve full metadata, browse journal issues, and list subject categories across millions of scholarly works.

Endpoints
5
Updated
2mo ago

What is the JSTOR API?

The JSTOR API provides 5 endpoints covering academic article search, full article metadata, journal and issue lookup, and subject browsing. The search endpoint returns paginated results with fields like DOI, authors, publisher, citation, open-access status, and access rights, making it straightforward to query JSTOR's catalog of peer-reviewed research programmatically.

Try it
Page number for pagination.
Sort order: 'rel' for relevance, 'new' for newest, 'old' for oldest.
Search query string.
api.parse.bot/scraper/b54cfcb7-298c-4413-9f6b-8f47f56ef1d1/<endpoint>
Ready to send
Fill in the parameters and hit sign in to send to see live response data here.
Call it over HTTPgrab a free API key at signup
curl -X GET 'https://api.parse.bot/scraper/b54cfcb7-298c-4413-9f6b-8f47f56ef1d1/search?page=2&sort=rel&query=machine+learning' \
  -H 'X-API-Key: $PARSE_API_KEY'
Python SDK · recommended

Typed, relational, agent-ready

A generated client with real types, enums, and the links between objects — the structure a flat JSON response can't carry. Autocompletes in your editor and reads cleanly to coding agents.

  • Fully typed · autocompletes
  • Objects link to objects
  • Typed errors & pagination

Typed Python client. Set up the SDK in your uv project, then pull this API’s typed client:

uv add parse-sdk
uv run parse init
uv run parse add --marketplace jstor-org-api

uv run parse add --marketplace pulls a pinned snapshot of this canonical API — it won’t change underneath you. To customize it, subscribe and swap to your own copy.

"""
JSTOR Content API Client

Search and browse academic content on JSTOR, including articles, journals, and issues.
Get your API key from: https://parse.bot/settings
"""

import os
import requests
from typing import Any, Dict, List, Optional


class ParseClient:
    """Client for the JSTOR Content API via Parse.bot"""

    def __init__(self, api_key: Optional[str] = None):
        """
        Initialize the Parse client.

        Args:
            api_key: API key for Parse.bot. If not provided, reads from PARSE_API_KEY env var.
        """
        self.base_url = "https://api.parse.bot"
        self.scraper_id = "b54cfcb7-298c-4413-9f6b-8f47f56ef1d1"
        self.api_key = api_key or os.getenv("PARSE_API_KEY")

        if not self.api_key:
            raise ValueError("API key not provided and PARSE_API_KEY environment variable not set")

    def _call(self, endpoint: str, method: str = "POST", **params) -> Dict[str, Any]:
        """
        Make a request to the Parse API.

        Args:
            endpoint: The endpoint name (e.g., 'search', 'get_article')
            method: HTTP method ('GET' or 'POST')
            **params: Query/body parameters for the endpoint

        Returns:
            Response JSON as a dictionary
        """
        url = f"{self.base_url}/scraper/{self.scraper_id}/{endpoint}"
        headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}

        if method == "GET":
            response = requests.get(url, headers=headers, params=params)
        elif method == "POST":
            response = requests.post(url, headers=headers, json=params)
        else:
            raise ValueError(f"Unsupported HTTP method: {method}")

        response.raise_for_status()
        return response.json()

    def search(
        self, query: str, sort: str = "rel", page: int = 1
    ) -> Dict[str, Any]:
        """
        Search for articles, books, and other content on JSTOR.

        Args:
            query: Search query string
            sort: Sort order ('rel' for relevance, 'new' for newest, 'old' for oldest)
            page: Page number for pagination

        Returns:
            Search results with total count and article metadata
        """
        return self._call("search", method="GET", query=query, sort=sort, page=page)

    def get_article(self, article_id: str) -> Dict[str, Any]:
        """
        Retrieve full metadata for a specific article or book chapter by its JSTOR UUID.

        Args:
            article_id: The JSTOR UUID of the article

        Returns:
            Full article metadata including abstract, authors, and publication details
        """
        return self._call("get_article", method="GET", article_id=article_id)

    def get_issue(self, issue_id: str) -> Dict[str, Any]:
        """
        Retrieve the table of contents for a specific journal issue.

        Args:
            issue_id: The DOI-style stable ID of the issue

        Returns:
            Issue metadata and list of articles in the issue
        """
        return self._call("get_issue", method="GET", issue_id=issue_id)

    def get_journal(self, journal_id: str) -> Dict[str, Any]:
        """
        Retrieve metadata for a specific journal by its ID slug.

        Args:
            journal_id: The journal ID slug (e.g., 'aejapplecon')

        Returns:
            Journal metadata including title, publisher, ISSN, and description
        """
        return self._call("get_journal", method="GET", journal_id=journal_id)

    def browse_subjects(self) -> Dict[str, Any]:
        """
        List all browseable academic subjects on JSTOR.

        Returns:
            List of subjects with codes, names, and URLs
        """
        return self._call("browse_subjects", method="GET")


if __name__ == "__main__":
    # Initialize the client
    client = ParseClient()

    print("=" * 80)
    print("JSTOR Content API - Academic Research Discovery Workflow")
    print("=" * 80)

    # Step 1: Browse available research subjects
    print("\n[1] Discovering Research Subjects...")
    print("-" * 80)
    
    subjects_response = client.browse_subjects()
    subjects = subjects_response.get("data", [])
    
    print(f"Available subjects: {len(subjects)}")
    for subject in subjects[:5]:
        print(f"  • {subject['name']} ({subject['code']})")
    if len(subjects) > 5:
        print(f"  ... and {len(subjects) - 5} more")

    # Step 2: Search for recent articles on climate change
    print("\n[2] Searching for Recent Climate Change Research...")
    print("-" * 80)
    
    search_results = client.search(query="climate change", sort="new", page=1)
    
    print(f"Search Query: '{search_results['query']}'")
    print(f"Total Results Available: {search_results['total_results']}")
    print(f"Results on Current Page: {len(search_results['results'])}")
    
    # Step 3: Analyze and fetch details for top results
    print("\n[3] Analyzing Top Research Articles...")
    print("-" * 80)
    
    results_to_analyze = search_results["results"][:3]
    article_details_list = []
    
    for idx, article in enumerate(results_to_analyze, 1):
        print(f"\nArticle {idx}: {article['title'][:70]}")
        print(f"  Authors: {', '.join(article['authors'][:2])}")
        print(f"  Type: {article['type']} | Year: {article['publication_year']}")
        print(f"  Open Access: {article['is_open_access']} | Access Available: {article['has_access']}")
        print(f"  DOI: {article.get('doi', 'N/A')[:40]}")
        
        # Fetch full article details
        try:
            article_detail = client.get_article(article['id'])
            article_details_list.append(article_detail)
            
            print(f"  Publisher: {article_detail.get('publisher', 'N/A')}")
            if article_detail.get('abstract'):
                abstract_preview = article_detail['abstract'][:100]
                print(f"  Abstract Preview: {abstract_preview}...")
            print(f"  Permanent URL: {article_detail['stable_url']}")
            
        except Exception as e:
            print(f"  ⚠ Could not fetch full details: {str(e)[:50]}")

    # Step 4: Aggregate findings
    print("\n[4] Research Summary...")
    print("-" * 80)
    
    print(f"\nSuccessfully retrieved {len(article_details_list)} detailed articles")
    
    if article_details_list:
        # Analyze publication years
        years = [int(a.get('year', 0)) for a in article_details_list if a.get('year')]
        if years:
            avg_year = sum(years) / len(years)
            print(f"Average Publication Year: {avg_year:.1f}")
            print(f"Year Range: {min(years)} - {max(years)}")
        
        # Analyze authors
        all_authors = []
        for article in article_details_list:
            all_authors.extend(article.get('authors', []))
        
        print(f"Total Authors Across Results: {len(all_authors)}")
        if all_authors:
            print(f"Prolific Authors: {', '.join(set(all_authors[:3]))}")
        
        # Content types
        content_types = set(a.get('type', 'Unknown') for a in article_details_list)
        print(f"Content Types Found: {', '.join(content_types)}")

    print("\n" + "=" * 80)
    print("Research discovery workflow complete!")
    print("=" * 80)
All endpoints · 5 totalmissing one? ·

Search for articles, books, and other content on JSTOR. Returns paginated results grouped by relevance or date.

Input
ParamTypeDescription
pageintegerPage number for pagination.
sortstringSort order: 'rel' for relevance, 'new' for newest, 'old' for oldest.
queryrequiredstringSearch query string.
Response
{
  "type": "object",
  "fields": {
    "page": "integer, current page number",
    "query": "string, the search query echoed back",
    "results": "array of objects with id, doi, title, authors, type, stable_url, publication_year, publisher, citation, is_open_access, has_access",
    "total_results": "integer, total number of results"
  },
  "sample": {
    "data": {
      "page": 1,
      "query": "climate change",
      "results": [
        {
          "id": "14f6392b-b9d2-31e3-887f-6e9424215c96",
          "doi": "10.7249/j.ctt17mvhfj.13",
          "type": "Book Chapter",
          "title": "Climate Change",
          "authors": [
            "James Dobbins",
            "Richard H. Solomon",
            "Michael S. Chase"
          ],
          "citation": null,
          "publisher": [
            "RAND Corporation"
          ],
          "has_access": true,
          "stable_url": "https://www.jstor.org/stable/10.7249/j.ctt17mvhfj.13",
          "is_open_access": true,
          "publication_year": 2015
        }
      ],
      "total_results": 0
    },
    "status": "success"
  }
}

About the JSTOR API

Search and Discovery

The search endpoint accepts a required query string and optional page and sort parameters (rel for relevance, new for newest, old for oldest). Each result object includes id, doi, title, authors, type, stable_url, publication_year, publisher, citation, is_open_access, and has_access. The total_results field lets you paginate through the full result set. This is typically the entry point for locating specific content before passing identifiers to other endpoints.

Article and Issue Detail

The get_article endpoint takes a JSTOR UUID (obtainable from search results) and returns extended metadata: abstract, rights, source, journal, year, type, and a full authors array. Note that some content types such as book chapters may not be available and will return an upstream error. The get_issue endpoint accepts a DOI-style stable ID (e.g. 10.2307/i40228945) and returns the full table of contents for that journal issue, including volume, issue, date, publisher, and an articles array with per-article id, doi, title, authors, and pages.

Journal Metadata and Subject Browsing

The get_journal endpoint retrieves metadata for a specific journal by its slug identifier, returning title, issn, eissn, publisher, and description. The browse_subjects endpoint requires no inputs and returns the complete list of JSTOR subject categories, each with a name, code, and url. This is useful for building subject-filtered browsing flows or mapping JSTOR's taxonomy to your own classification system.

Reliability & maintenance

The JSTOR API is a managed, monitored endpoint for jstor.org — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when jstor.org changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.

This isn't an official jstor.org API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.

Will this API break when the source site changes?+
It's built not to. Every endpoint is health-checked on a schedule with automated test probes. When the source site changes and a check fails, the API is automatically queued for repair and re-verified — that's the self-healing layer. Each API page shows when its endpoints were last verified. And because marketplace APIs are shared, any fix reaches everyone using it.
Is this an official API from the source site?+
No — Parse APIs are independent, managed REST wrappers over publicly available data. That is the point: where a site has no official API (or only a limited one), Parse gives you a maintained, monitored endpoint for that data and keeps it working as the site changes — so you get a stable contract over a source that never promised one.
Can I fix or extend this API myself if I need a new endpoint or field?+
Yes — and you don't have to wait on us. This API was generated by the Parse agent, which stays attached. Describe the change in plain English ("add an endpoint that returns reviews", "fix the price field") in the revise box on the API page or via the revise_api MCP tool, and the agent rebuilds it against the live site in minutes. Contributing the change back to the public API is free.
What happens if I call an endpoint that has an issue?+
Errors are machine-readable: a bad call returns a clean status with the list of available endpoints and a repair hint, so an agent (or you) can recover or trigger a fix instead of failing silently. Confirmed failures feed the automatic repair queue.
Common use cases
  • Building a literature discovery tool that queries JSTOR by topic and surfaces open-access articles via the is_open_access field
  • Generating bibliographic citations for academic papers using the citation, doi, authors, and publication_year fields from search results
  • Populating a journal directory with ISSN, publisher, and description data from the get_journal endpoint
  • Constructing a table-of-contents reader for a specific journal issue using the get_issue articles array with pages and doi
  • Mapping JSTOR's subject taxonomy to an internal classification system using browse_subjects codes and names
  • Checking access rights for a set of article IDs using the has_access and is_open_access fields in search results
  • Aggregating article abstracts and metadata by author name across multiple search pages for academic profiling
Pricing & limitsSee full pricing →
TierPriceCredits/monthRate limit
Free$0/mo1005 req/min
Hobby$30/mo1,00020 req/min
Developer$100/mo5,000100 req/min

One credit = one API call regardless of which marketplace API you call. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.

Frequently asked questions
Does JSTOR have an official developer API?+
JSTOR offers a text data mining program called JSTOR Data for Research (dfr.jstor.org), which is intended for bulk dataset access under specific agreements. It is not a general-purpose REST API for real-time metadata lookup.
What does the `search` endpoint return beyond basic title and author data?+
Each result includes doi, stable_url, publication_year, publisher, citation, type (article, book chapter, etc.), is_open_access, and has_access. The has_access and is_open_access flags are particularly useful for filtering results to content a user can actually read.
Are full article PDFs or full text available through this API?+
Not currently. The API returns metadata, abstracts, DOIs, and stable URLs, but does not deliver full article text or PDF content. You can fork this API on Parse and revise it to add an endpoint targeting full-text sources where available.
Are there any content types that may not work with `get_article`?+
Yes. The endpoint is designed primarily for journal articles. Book chapters may return an upstream error when queried by UUID. If you encounter this, the search endpoint's type field can help you identify content type before making a detail call.
Does the API support filtering search results by discipline, date range, or journal?+
The search endpoint supports sorting by relevance, newest, or oldest via the sort parameter, but does not expose filters for discipline, journal name, or date range directly. The browse_subjects endpoint returns subject codes and URLs that can inform query construction. You can fork this API on Parse and revise it to add subject or journal-scoped filtering as a dedicated endpoint.
Page content last updated . Spec covers 5 endpoints from jstor.org.
Related APIs in EducationSee all →
springer.com API
Search and retrieve metadata for millions of articles, books, and journals from Springer Nature's research library using DOI or ISBN lookups, with powerful filtering and pagination options. Get detailed information about academic publications including journal details, article metadata, and book information to power your research tools and discovery applications.
royalsocietypublishing.org API
Search and browse scientific articles, journals, and issues from the Royal Society Publishing platform, including filtering by subject, year, and latest publications. Access detailed information about specific articles, journals, and current issues to stay updated on peer-reviewed research.
mdpi.com API
Access MDPI's open-access academic content programmatically. Search across thousands of peer-reviewed articles, retrieve full structured text, extract key findings, and browse journal metadata including impact factors and CiteScores.
aeaweb.org API
Search for academic papers across American Economic Association journals to instantly access abstracts, author information, JEL classifications, and citation metrics. Retrieve detailed article information to stay current with the latest economic research and citations from premier sources like the American Economic Review.
arxiv.org API
Search and discover academic research papers on arXiv using keywords, authors, titles, categories, and dates, then access detailed metadata for any paper. Browse the complete arXiv category taxonomy to explore research across different scientific disciplines.
magzter.com API
Browse and search millions of magazines, newspapers, and stories from Magzter's digital library, then dive into specific publications, issues, and articles by category. Discover detailed information about any magazine or newspaper edition to find exactly what you want to read.
ieeexplore.ieee.org API
Search for scientific papers and retrieve their metadata, abstracts, references, and citations from IEEE Xplore's collection of journals and conferences. Look up author profiles, browse journals, and access paper details and full text sections all programmatically.
pmc.ncbi.nlm.nih.gov API
Search millions of full-text biomedical research articles and access their metadata, citations, and related papers from PubMed Central. Find articles by topic, discover similar research, explore journal collections, and retrieve detailed citation information to support your literature review and research.