ReadingList API Documentation

Public REST API · v1 · CORS open · No auth required (free tier)

What this API serves

ReadingList exposes a free, public, read-only REST API over its source-cited K-12 reading-list dataset. Six endpoints serve book metadata, curriculum and state reading lists, and grade-appropriate recommendations. The API is designed for AI tutors integrating grade-level book suggestions, ed-tech apps building reading-companion features, library systems doing collection development, and researchers studying assigned reading.

Every response references the classification standard — the public 6-dimension methodology that documents how each field is sourced and verified.

Authentication & rate limits

Free tier (current). No authentication required. Recommended client-side rate limit: ≤100 requests per day per IP. Server-side rate limit enforcement is not yet live; please honor the cap so the free tier remains available to everyone.

Paid tiers (coming). Pro tier (1,000/day) and Enterprise tier (10,000+/day with SLA) ship alongside auth in a future release. Token-based authentication via Bearer headers; pricing will be published on the pricing page when tiers go live.

Rate limit headers appear on every response: X-RateLimit-Tier, X-RateLimit-Daily-Limit, X-RateLimit-Pro-Tier-Daily, X-RateLimit-Enterprise-Tier-Daily.

Conventions

  • All endpoints respond with application/json. No XML, no HTML, no GraphQL.
  • CORS is open (Access-Control-Allow-Origin: *) so the API can be called directly from browser-side code.
  • Responses are edge-cached; Cache-Control headers indicate freshness (typically 1 hour browser, 1 day edge).
  • Errors return a JSON envelope with { error, message, documentation_url } plus the appropriate HTTP status (400 / 404 / 500).
  • Slugs are lowercase, hyphenated, and stable. The slug for a book / curriculum / state / grade matches its canonical page URL on the site.
  • Field semantics follow the classification standard. When a book has no data for a dimension, the field is empty or null — never fabricated.

Quick start — code samples

Integrate the recommendation endpoint in any language. The examples below all hit /api/v1/recommend with the same filter (grade 9, Common Core, exclude-banned, 5 books) and parse the JSON response. Other endpoints follow the same pattern — swap the path, rebuild the query string.

Bash (curl + jq)

# Pretty-print recommendations for grade 9 Common Core, exclude banned
curl -s 'https://readinglist.school/api/v1/recommend?grade=9&curriculum=common-core&exclude_banned=true&limit=5' \
  | jq '.books[] | { title, author, lexile, permalink }'

Python (requests)

import requests

BASE = "https://readinglist.school/api/v1"

def recommend(grade, curriculum=None, state=None, lexile_max=None,
              exclude_banned=False, limit=10):
    """Fetch grade-appropriate book recommendations.

    Returns a list of dicts with title/author/lexile/permalink/etc.
    See https://readinglist.school/standard for classification methodology.
    """
    params = {"grade": grade, "limit": limit}
    if curriculum: params["curriculum"] = curriculum
    if state: params["state"] = state
    if lexile_max is not None: params["lexile_max"] = lexile_max
    if exclude_banned: params["exclude_banned"] = "true"

    r = requests.get(f"{BASE}/recommend", params=params, timeout=10)
    r.raise_for_status()
    return r.json()["books"]

books = recommend(grade="9", curriculum="common-core",
                  exclude_banned=True, limit=5)
for b in books:
    print(f"{b['title']:30s}  Lexile {b['lexile']:>4}L  {b['permalink']}")

Node.js / JavaScript (fetch)

// Works in modern Node (18+) and any browser. No dependencies.
async function recommend({ grade, curriculum, state, lexileMax,
                            excludeBanned = false, limit = 10 }) {
  const params = new URLSearchParams({ grade, limit: String(limit) });
  if (curriculum) params.set('curriculum', curriculum);
  if (state) params.set('state', state);
  if (lexileMax != null) params.set('lexile_max', String(lexileMax));
  if (excludeBanned) params.set('exclude_banned', 'true');

  const url = `https://readinglist.school/api/v1/recommend?${params}`;
  const res = await fetch(url);
  if (!res.ok) throw new Error(`API ${res.status}: ${await res.text()}`);
  const data = await res.json();
  return data.books;
}

const books = await recommend({
  grade: '9',
  curriculum: 'common-core',
  excludeBanned: true,
  limit: 5,
});
for (const b of books) {
  console.log(`${b.title.padEnd(30)}  Lexile ${b.lexile}L  ${b.permalink}`);
}

TypeScript (typed client)

// Generate full typed bindings from /api/openapi via openapi-typescript:
//   npx openapi-typescript https://readinglist.school/api/openapi -o api.d.ts
// Then import:

import type { components } from "./api";
type Book = components["schemas"]["Book"];
type RecommendResponse = components["schemas"]["RecommendResponse"];

async function recommend(
  filters: { grade: string; curriculum?: string; limit?: number }
): Promise<Book[]> {
  const params = new URLSearchParams(filters as Record<string, string>);
  const res = await fetch(
    `https://readinglist.school/api/v1/recommend?${params}`
  );
  const data: RecommendResponse = await res.json();
  return data.books;
}

The full OpenAPI 3.1 spec at /api/openapi auto-generates clients in 50+ languages via openapi-generator (Java, Go, Ruby, PHP, Rust, C#, Swift, etc.).

Endpoints

Six endpoints. The newest (and most flexible) is /api/v1/recommend.

GET /api/v1/recommend

Grade-appropriate book recommendations with optional filters

Returns up to 50 books matching grade × optional curriculum × optional state × optional Lexile range × optional banned-state exclusion. Designed for AI tutors integrating grade-level reading suggestions.

Parameters

graderequired
Grade slug — K, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, or 12.
stateoptional
State slug (e.g. california, texas, new-york). Filters to books cited in that state's ELA framework or DOE list (national curricula included).
curriculumoptional
Curriculum slug (e.g. common-core, ap-literature, ib-dp-english-literature, cambridge-igcse-english-lit).
lexile_minoptional
Minimum Lexile measure (non-negative integer). Books below this filtered out.
lexile_maxoptional
Maximum Lexile measure (non-negative integer). Books above this filtered out.
exclude_bannedoptional
Set to 'true' to exclude books with any documented banning or removal record per PEN America's Index.
limitoptional
Maximum books returned. Default 10, max 50. Higher values silently capped at 50.

Example

curl 'https://readinglist.school/api/v1/recommend?grade=9&curriculum=common-core&exclude_banned=true&limit=5'

Response shape

{
  "version": "v1",
  "generated_at": "2026-04-30T...",
  "filters": { "grade": "9", "curriculum": "common-core", "state": null,
               "lexile_min": null, "lexile_max": null,
               "exclude_banned": true, "limit": 5 },
  "methodology_url": "https://readinglist.school/standard",
  "methodology_summary": "Recommendations derive from the 6-dimension classification standard...",
  "rate_limit": { "tier": "free", "daily_limit": 100, ... },
  "count": 5,
  "books": [
    {
      "slug": "lord-of-the-flies",
      "title": "Lord of the Flies",
      "author": "William Golding",
      "isbn13": "9780399501487",
      "lexile": 770,
      "lexile_range_min": 770,
      "lexile_range_max": 770,
      "grade_min": 9,
      "grade_max": 12,
      "themes": ["civilization", "human nature", "morality"],
      "banned_in_states": [],
      "permalink": "https://readinglist.school/book/lord-of-the-flies",
      "api_url": "https://readinglist.school/api/book/lord-of-the-flies"
    },
    { ... }
  ]
}

GET /api/book/{slug}

Single-book detail with all assignments + sources

Returns the full book record (title, author, ISBNs, Lexile, grade band, themes, banning records, cover URL) and every documented assignment (curriculum, state, grade, source URL).

Parameters

{slug}required
Book slug from the canonical book URL, e.g. to-kill-a-mockingbird.

Example

curl 'https://readinglist.school/api/book/to-kill-a-mockingbird'

Response shape

{
  "book": { "slug", "title", "author", "isbn13", "lexile", ... },
  "assignments": [ { "curriculum_slug", "state_slug", "grade_slug",
                     "source_url", "source_document", "context" }, ... ]
}

GET /api/curriculum/{slug}

Books cited in a curriculum framework (all grades)

Returns every book cited under the named curriculum, aggregated across all grade levels. Use this to seed a curriculum-aligned reading list at any grade.

Parameters

{slug}required
Curriculum slug — common-core, ap-literature, ap-language, ib-dp-english-literature, cambridge-igcse-english-lit, etc.

Example

curl 'https://readinglist.school/api/curriculum/common-core'

Response shape

{
  "curriculum": { "slug", "name", "type", "publisher", ... },
  "count": N,
  "books": [ { "slug", "title", "author", "lexile", "grade_min",
               "grade_max", ... }, ... ]
}

GET /api/curriculum/{slug}/grade/{gradeSlug}

Curriculum × grade intersection

Narrower than the curriculum-only endpoint. Returns books cited under the curriculum at the specific grade level.

Parameters

{slug}required
Curriculum slug.
{gradeSlug}required
Grade slug — K through 12.

Example

curl 'https://readinglist.school/api/curriculum/ap-literature/grade/11'

Response shape

{
  "curriculum": {...}, "grade": {...}, "count": N, "books": [...]
}

GET /api/state/{stateSlug}

Books cited at the state level (all grades)

Returns books documented in a US state's ELA framework, summer-reading list, or DOE guidance. Aggregated across all grades.

Parameters

{stateSlug}required
State slug — california, texas, florida, new-york, etc.

Example

curl 'https://readinglist.school/api/state/california'

Response shape

{
  "state": { "slug", "abbr", "name", "standards_name", "doe_url" },
  "count": N,
  "books": [...]
}

GET /api/state/{stateSlug}/grade/{gradeSlug}

State × grade intersection (includes national curricula)

Books cited at the state level for the specific grade, including national curricula (Common Core, AP, IB, Cambridge) that apply nationally — these are surfaced alongside state-tagged rows.

Parameters

{stateSlug}required
State slug.
{gradeSlug}required
Grade slug — K through 12.

Example

curl 'https://readinglist.school/api/state/california/grade/9'

Response shape

{
  "state": {...}, "grade": {...}, "count": N, "books": [...]
}

Error reference

All error responses share the same JSON envelope:

{
  "error": "stable_error_code",
  "message": "Human-readable explanation.",
  "documentation_url": "https://readinglist.school/standard#section"
}

The error field is a stable code suitable for programmatic branching (it never changes for a given failure mode). The message field is for humans and may evolve. The documentation_url points to the relevant classification standard section explaining the methodology behind the failing dimension.

Stable error codes

HTTPerror codeWhen it firesFix
400missing_required_paramRequired query parameter absent. Currently only grade on /api/v1/recommend.Add ?grade= to the URL with a valid grade slug (K, 1, ..., 12).
400invalid_lexile_paramlexile_min or lexile_max provided but not a non-negative integer.Pass an integer ≥0 (typical 0L-2000L). Strings or negatives reject.
404grade_not_foundGrade slug doesn’t match any record. Valid slugs: K, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12.Use one of the documented slugs. Remember K not 0 for kindergarten.
404state_not_foundState slug doesn’t match. Valid slugs come from /api/state (50 US states + Washington DC).Use lowercase hyphenated state name — california, not CA or California.
404curriculum_not_foundCurriculum slug doesn’t match. Valid slugs: common-core, ap-literature, ap-language, ib-dp-english-literature, cambridge-igcse-english-lit, etc.Look up the canonical slug at /curriculum.
404Book not foundReturned by /api/book/{slug} when the book slug doesn’t match a tracked record.Look up the canonical slug at /book pages or via /api/v1/recommend first to discover slugs.
5xx(transient)Upstream database hiccup or platform-level outage. Rare; not envelope-formatted (Vercel / Next.js default error page).Retry with exponential backoff (1s → 2s → 4s). If persistent >5 min, check Vercel status or contact us via /contact.
429(future)Rate limit exceeded. Server-side enforcement ships with auth in Phase 3 (Pro / Enterprise tiers). Currently free-tier limits are client-honor only.Reduce request rate to ≤100/day. Pro tier (1k/day) and Enterprise (10k+/day) become available alongside auth in a future release.

Programmatic handling

Branch on error field, not on message string content. Example:

async function recommend(filters) {
  const params = new URLSearchParams(filters);
  const res = await fetch(
    `https://readinglist.school/api/v1/recommend?${params}`
  );
  if (res.ok) return (await res.json()).books;

  const err = await res.json();
  switch (err.error) {
    case 'missing_required_param':
      throw new Error('Bug — grade param missing in client code');
    case 'grade_not_found':
    case 'state_not_found':
    case 'curriculum_not_found':
      // User typed an invalid filter. Surface inline, not as crash.
      return { invalidFilter: err.error, message: err.message };
    case 'invalid_lexile_param':
      throw new Error('Coerce lexile to integer before passing');
    default:
      // 5xx or unknown — retry with backoff
      throw new Error(`API ${res.status}: ${err.message}`);
  }
}

Machine-readable spec

The full API contract is published as an OpenAPI 3.1 specification at /api/openapi. Run it through Postman / Stoplight Studio / openapi-generator / Swagger Codegen to auto-generate a client in any language. Stable contract under /api/v1/; breaking changes will land under /api/v2/ with a 12-month deprecation window.

Versioning

The newer recommendation endpoint is namespaced /api/v1/ to allow forward-compatible evolution. Breaking changes will land under /api/v2/ with a deprecation window for v1 (typically 12 months). The non-versioned endpoints (/api/book, /api/curriculum, /api/state) are treated as stable v1 contracts and changes follow the same policy.

Citation

Researchers, journalists, ed-tech developers, and AI tutors are welcome to cite this API in derivative work. Suggested citation: ReadingList (readinglist.school) Classification Standard v1.0, 2026, accessed via /api/v1/recommend. The canonical methodology URL is https://readinglist.school/standard.

Bug reports, feature requests, and integration questions go through the contact page.