Dartmouth Class Search API

The JSON backend of Dartmouth Class Search, the institution's public timetable of class meetings. Keyless: an unauthenticated POST returned 1393 sections for term 202609 on 2026-08-30. Two routes — search and details — selected by query parameter, with a JSON criteria body. Dartmouth operates it on its own host and does not publish it as an API, document it, or offer any stability commitment; the OpenAPI here is a probed description, not a contract Dartmouth authored. Errors arrive inside HTTP 200 as a `fatal` member.

Operations 1

POST /api/ Search or describe class sections #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/class-search"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

dartmouth-class-search-api-openapi.yml Raw ↑
# authorship: written by API Evangelist tooling from LIVE PROBES of the
# public Dartmouth Class Search endpoint on 2026-08-30. Dartmouth publishes
# no OpenAPI for this service; the contract below is a description of
# observed request/response behaviour, not a document Dartmouth authored.
x-method: probed
x-operator: institution
x-source: https://courses.dartmouth.edu/api/?page=fose&route=search
x-generated: '2026-08-30'
openapi: 3.1.0
info:
  title: Dartmouth Class Search API
  version: '2026-08-30'
  summary: Keyless JSON search over the Dartmouth College timetable of class meetings.
  description: >-
    The JSON backend of Dartmouth Class Search (https://courses.dartmouth.edu), the
    institution's public timetable of class meetings. It is operated by Dartmouth
    College on Dartmouth's own host and requires no API key, no account and no
    institutional affiliation.

    This document is DESCRIPTIVE. Dartmouth does not publish an OpenAPI, does not
    document this endpoint as a public API, and offers no stability or support
    commitment for it. The shapes below were observed by calling the live service
    on 2026-08-30 (term srcdb 202609, 1393 sections returned) and may change without
    notice. Treat it as a probed observation, not as a contract Dartmouth has offered.

    The service follows the FOSE course-search convention also used by several other
    US institutions: a single POST endpoint whose behaviour is selected by the `page`
    and `route` query parameters and whose body is a JSON criteria object.
  contact:
    name: Dartmouth Arts & Sciences Registrar
    url: https://registrar.dartmouth.edu/
  termsOfService: https://home.dartmouth.edu/privacy
servers:
  - url: https://courses.dartmouth.edu
    description: Dartmouth Class Search (institution-operated, keyless)
tags:
  - name: ClassSearch
    description: Search and detail operations over the Dartmouth timetable of class meetings.
paths:
  /api/:
    post:
      tags:
        - ClassSearch
      operationId: classSearch
      summary: Search or describe class sections
      description: >-
        Single entry point for the class-search service. `route=search` returns a page of
        matching sections for a term; `route=details` returns the full record for one
        section identified by CRN. No authentication is sent or accepted.
      parameters:
        - name: page
          in: query
          required: true
          description: Application selector. Only `fose` was observed to respond.
          schema:
            type: string
            enum: [fose]
        - name: route
          in: query
          required: true
          description: Operation selector.
          schema:
            type: string
            enum: [search, details]
      requestBody:
        required: true
        description: >-
          Criteria object. For `route=search`, `criteria` is a list of field/value filters
          (`subject`, and an empty list returns the whole term). For `route=details`, the
          body identifies a single section by `srcdb` and `key`/`matched` CRN.
        content:
          application/json:
            schema:
              oneOf:
                - $ref: '#/components/schemas/SearchRequest'
                - $ref: '#/components/schemas/DetailsRequest'
            examples:
              wholeTerm:
                summary: Every section in the current term
                value:
                  other: { srcdb: '' }
                  criteria: []
              bySubject:
                summary: Sections for one subject code
                value:
                  other: { srcdb: '' }
                  criteria:
                    - field: subject
                      value: COSC
              details:
                summary: Full record for one section
                value:
                  group: 'code:COSC 001'
                  key: 'crn:91925'
                  srcdb: '202609'
                  matched: 'crn:91925'
      responses:
        '200':
          description: >-
            A search page or a section detail record. Note that a malformed body also
            returns HTTP 200 with a `fatal` member — the service does not use status
            codes to signal request errors.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/SearchResponse'
                  - $ref: '#/components/schemas/SectionDetail'
                  - $ref: '#/components/schemas/FatalResponse'
components:
  schemas:
    SearchRequest:
      type: object
      required: [criteria]
      properties:
        other:
          type: object
          description: Term selector. An empty `srcdb` selects the current term.
          properties:
            srcdb:
              type: string
              description: Term code, e.g. `202609`. Empty string means current term.
        criteria:
          type: array
          description: Filters to apply. An empty array returns the whole term.
          items:
            type: object
            required: [field, value]
            properties:
              field:
                type: string
                description: Field to filter on. `subject` observed.
              value:
                type: string
    DetailsRequest:
      type: object
      required: [srcdb, key]
      properties:
        group:
          type: string
          description: Course grouping key, e.g. `code:COSC 001`.
        key:
          type: string
          description: Section key, e.g. `crn:91925`.
        srcdb:
          type: string
          description: Term code, e.g. `202609`.
        matched:
          type: string
          description: The matched key echoed back, e.g. `crn:91925`.
    SearchResponse:
      type: object
      required: [srcdb, count, results]
      properties:
        srcdb:
          type: string
          description: Term the results belong to.
        count:
          type: integer
          description: Number of sections returned.
        results:
          type: array
          items:
            $ref: '#/components/schemas/SectionSummary'
    SectionSummary:
      type: object
      description: One class section as returned by `route=search`.
      properties:
        key: { type: string }
        code: { type: string, description: 'Course code, e.g. COSC 001.' }
        title: { type: string }
        crn: { type: string, description: Course reference number, the section identifier. }
        no: { type: string, description: Section number. }
        schd: { type: string, description: Schedule type code (L lecture, etc.). }
        stat: { type: string, description: 'Status code (A open, F full).' }
        isCancelled: { type: string }
        meets: { type: string, description: Human-readable meeting pattern, contains HTML. }
        meetingTimes:
          type: string
          description: >-
            JSON-encoded STRING (not a nested object) holding an array of
            `{meet_day,start_time,end_time}` records. Must be parsed a second time.
        instr: { type: string, description: Instructor of record. }
        start_date: { type: string, format: date }
        end_date: { type: string, format: date }
        section: { type: string }
        srcdb: { type: string }
        grid__enroll: { type: string }
        grid__max_enroll: { type: string }
        grid__wait_count: { type: string }
        grid__credit_hours: { type: string }
        grid__term_description: { type: string }
        grid__attribute_codes: { type: string }
        grid__status_code: { type: string }
        cart_opts:
          type: string
          description: JSON-encoded string of registration cart options.
    SectionDetail:
      type: object
      description: >-
        Full record for one section from `route=details`. Many members carry
        rendered HTML rather than structured data.
      properties:
        crn: { type: string }
        code: { type: string }
        section: { type: string }
        title: { type: string }
        description: { type: string }
        hours_html: { type: string }
        seats: { type: string, description: Enrollment and availability, as HTML. }
        status: { type: string }
        instmode: { type: string, description: Instructional mode. }
        meeting_html: { type: string }
        instructordetail_html: { type: string }
        registration_restrictions: { type: string }
        registration_options: { type: string }
        learning_objectives: { type: string }
        required_materials: { type: string }
        course_coreqs: { type: string }
        section_coreqs: { type: string }
        section_attributes: { type: string }
        clssnotes: { type: string }
        all_sections: { type: string }
    FatalResponse:
      type: object
      description: >-
        Returned with HTTP 200 when the request body cannot be parsed. The only
        error signal the service emits.
      required: [fatal]
      properties:
        fatal:
          type: string
          example: Could not parse incoming payload as JSON