University of Groningen Ocasys Course Catalog API

The JSON backend behind Ocasys, the University's own course and degree-programme catalog. Verified live 2026-08-30 with no credentials: course search, full course records, the catalog page projection, programme search, faculties and organizational units, controlled option lists and the academic-year list all return 200 to an anonymous GET. Course records are bilingual and carry ECTS credits, study level, assessments, formats, prerequisites, offerings, ENLIGHT alliance status and per-course UN Sustainable Development Goal flags. Enrollment, permission and course-offering paths in the same namespace return 403 without an institutional SAML session and are documented as gated, not as callable. This is the one genuinely institution-engineered API surface in the University's footprint. The OpenAPI below is DERIVED by API Evangelist from live probes — the University publishes none, and does not advertise this interface at all.

Operations 9

GET /year-status List every academic year the catalog holds #
GET /year/next-academic-year-start-date Start date of the next academic year #
GET /orgunit/faculties-and-universities List faculties and the university root organizational unit #
GET /{academicYear}/course Search courses within one academic year #
GET /{academicYear}/course/{courseCode} Get one course by its catalog code #
GET /{academicYear}/course/page/{courseCode} Get the catalog page projection of one course #
GET /{academicYear}/program Search degree programmes within one academic year #
GET /{academicYear}/option-list List the controlled option lists used by course and programme records #
GET /{academicYear}/course-offering List course offerings (institutional session required) #

Documentation

Specifications

Other Resources

🔗
x-openapi-original
https://raw.githubusercontent.com/api-evangelist/university-of-groningen/refs/heads/main/openapi/_original/university-of-groningen-course-catalog-api.yaml
🔗
Website
https://ocasys.rug.nl/
🔗
x-json-schema
https://raw.githubusercontent.com/api-evangelist/university-of-groningen/refs/heads/main/json-schema/university-of-groningen-ocasys-course-schema.json
🔗
x-json-schema
https://raw.githubusercontent.com/api-evangelist/university-of-groningen/refs/heads/main/json-schema/university-of-groningen-ocasys-program-schema.json
🔗
x-json-ld
https://raw.githubusercontent.com/api-evangelist/university-of-groningen/refs/heads/main/json-ld/university-of-groningen-course-context.jsonld
🔗
x-rules
https://raw.githubusercontent.com/api-evangelist/university-of-groningen/refs/heads/main/rules/university-of-groningen-course-catalog-rules.yml
🔗
Vocabulary
https://raw.githubusercontent.com/api-evangelist/university-of-groningen/refs/heads/main/vocabulary/university-of-groningen-course-catalog-vocabulary.yml
🔗
Errors
https://raw.githubusercontent.com/api-evangelist/university-of-groningen/refs/heads/main/errors/university-of-groningen-errors.yml
🔗
x-example
https://raw.githubusercontent.com/api-evangelist/university-of-groningen/refs/heads/main/examples/university-of-groningen-ocasys-course-search-example.json
🔗
x-example
https://raw.githubusercontent.com/api-evangelist/university-of-groningen/refs/heads/main/examples/university-of-groningen-ocasys-get-course-example.json
🔗
x-example
https://raw.githubusercontent.com/api-evangelist/university-of-groningen/refs/heads/main/examples/university-of-groningen-ocasys-program-search-example.json
🔗
x-example
https://raw.githubusercontent.com/api-evangelist/university-of-groningen/refs/heads/main/examples/university-of-groningen-ocasys-faculties-example.json
🔗
x-example
https://raw.githubusercontent.com/api-evangelist/university-of-groningen/refs/heads/main/examples/university-of-groningen-ocasys-problem-detail-example.json
🔗
APIsJSON
https://raw.githubusercontent.com/api-evangelist/university-of-groningen/refs/heads/main/apis.yml

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/ocasys-course-catalog"
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

university-of-groningen-course-catalog-api-openapi.yml Raw ↑
# authorship: derived by API Evangelist from live, unauthenticated probes of the
# Ocasys course-catalog backend operated by the University of Groningen at
# https://ocasys.rug.nl/api. The University publishes no OpenAPI of its own;
# every path, parameter and response below was observed in a real HTTP exchange
# on 2026-08-30. Nothing here is inferred from documentation, because there is none.
x-method: probed
x-generated: '2026-08-30'
x-source:
  - https://ocasys.rug.nl/api/year-status
  - https://ocasys.rug.nl/api/orgunit/faculties-and-universities
  - https://ocasys.rug.nl/api/2026-2027/course?searchTerm=biology
  - https://ocasys.rug.nl/api/2026-2027/course/WMMB015-05
  - https://ocasys.rug.nl/api/2026-2027/course/page/WMMB015-05
  - https://ocasys.rug.nl/api/2026-2027/program?searchTerm=biology
  - https://ocasys.rug.nl/api/2026-2027/option-list
  - https://ocasys.rug.nl/api/year/next-academic-year-start-date
x-operator: institution
openapi: 3.1.0
info:
  title: University of Groningen Ocasys Course Catalog API
  version: '2026-2027'
  summary: Keyless read API behind Ocasys, the University of Groningen course and programme catalog.
  description: >-
    Ocasys (ocasys.rug.nl) is the University of Groningen's own course and degree-programme
    catalog. Its single-page front end is served by a JSON REST backend under /api that answers
    unauthenticated GET requests for academic years, faculties and departments, course search,
    full course descriptions, degree-programme search and the controlled option lists the catalog
    uses. The University does not document or version this interface publicly and does not
    advertise it as a product; this contract was reconstructed from live probes so the surface can
    be catalogued honestly. Write paths, enrollment, permissions and course-offering endpoints
    exist in the same namespace and answer 403 without an institutional session — they are
    described here only as gated, not as callable.
  contact:
    name: University of Groningen — Center for Information Technology
    url: https://www.rug.nl/society-business/center-for-information-technology/
  termsOfService: https://www.rug.nl/info/disclaimer-copyright
  license:
    name: No licence published for the interface or its data
    identifier: NOASSERTION
servers:
  - url: https://ocasys.rug.nl/api
    description: Production Ocasys backend (institution-operated, verified live 2026-08-30)
tags:
  - name: Academic Years
    description: Which academic years the catalog holds and when the next one starts.
  - name: Organization
    description: Faculties and departments used to scope courses and programmes.
  - name: Courses
    description: Course search and full course descriptions.
  - name: Programmes
    description: Degree-programme search.
  - name: Option Lists
    description: Controlled vocabularies used by course and programme records.
paths:
  /year-status:
    get:
      tags: [Academic Years]
      operationId: listAcademicYears
      summary: List every academic year the catalog holds
      description: Returns each academic year with its identifier and whether it is active. Observed 200 with 40+ years, earliest 2010-2011.
      responses:
        '200':
          description: Academic years
          content:
            application/json:
              schema:
                type: object
                properties:
                  years:
                    type: array
                    items: { $ref: '#/components/schemas/AcademicYear' }
  /year/next-academic-year-start-date:
    get:
      tags: [Academic Years]
      operationId: getNextAcademicYearStartDate
      summary: Start date of the next academic year
      description: Returns a bare [year, month, day] array — a Java LocalDate serialized as an array, not an ISO-8601 string.
      responses:
        '200':
          description: Date as a three-element array
          content:
            application/json:
              schema:
                type: array
                items: { type: integer }
                minItems: 3
                maxItems: 3
                examples: [[2026, 8, 31]]
  /orgunit/faculties-and-universities:
    get:
      tags: [Organization]
      operationId: listFacultiesAndUniversities
      summary: List faculties and the university root organizational unit
      responses:
        '200':
          description: Organizational units
          content:
            application/json:
              schema:
                type: array
                items: { $ref: '#/components/schemas/OrganizationalUnit' }
  /{academicYear}/course:
    get:
      tags: [Courses]
      operationId: searchCourses
      summary: Search courses within one academic year
      parameters:
        - $ref: '#/components/parameters/AcademicYear'
        - name: searchTerm
          in: query
          required: true
          description: Free-text term matched against course code and title. Omitting it returns 400 with a problem+json body.
          schema: { type: string }
      responses:
        '200':
          description: Matching course summaries
          content:
            application/json:
              schema:
                type: array
                items: { $ref: '#/components/schemas/CourseSummary' }
        '400':
          $ref: '#/components/responses/ProblemBadRequest'
  /{academicYear}/course/{courseCode}:
    get:
      tags: [Courses]
      operationId: getCourse
      summary: Get one course by its catalog code
      parameters:
        - $ref: '#/components/parameters/AcademicYear'
        - $ref: '#/components/parameters/CourseCode'
      responses:
        '200':
          description: Full course record including goals, description, assessments and offerings
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Course' }
        '404':
          $ref: '#/components/responses/ProblemNotFound'
  /{academicYear}/course/page/{courseCode}:
    get:
      tags: [Courses]
      operationId: getCoursePage
      summary: Get the catalog page projection of one course
      description: Same course, shaped for the public catalog page — faculty and department are expanded to full organizational-unit objects.
      parameters:
        - $ref: '#/components/parameters/AcademicYear'
        - $ref: '#/components/parameters/CourseCode'
      responses:
        '200':
          description: Course page projection
          content:
            application/json:
              schema: { type: object }
        '404':
          $ref: '#/components/responses/ProblemNotFound'
  /{academicYear}/program:
    get:
      tags: [Programmes]
      operationId: searchPrograms
      summary: Search degree programmes within one academic year
      parameters:
        - $ref: '#/components/parameters/AcademicYear'
        - name: searchTerm
          in: query
          required: true
          description: Free-text term matched against programme code and title. Required — omitting it returns 400.
          schema: { type: string }
      responses:
        '200':
          description: Matching programmes
          content:
            application/json:
              schema:
                type: array
                items: { $ref: '#/components/schemas/Program' }
        '400':
          $ref: '#/components/responses/ProblemBadRequest'
  /{academicYear}/option-list:
    get:
      tags: [Option Lists]
      operationId: listOptions
      summary: List the controlled option lists used by course and programme records
      parameters:
        - $ref: '#/components/parameters/AcademicYear'
      responses:
        '200':
          description: Option list entries, bilingual
          content:
            application/json:
              schema:
                type: array
                items: { $ref: '#/components/schemas/Option' }
  /{academicYear}/course-offering:
    get:
      tags: [Courses]
      operationId: listCourseOfferings
      summary: List course offerings (institutional session required)
      description: >-
        Documented as observed, not as callable. Probed 2026-08-30 with no credentials and returned
        403 with an empty body. Access is gated behind the University's SAML single sign-on
        (signon.rug.nl); there is no public key, token or self-service registration for it.
      parameters:
        - $ref: '#/components/parameters/AcademicYear'
        - name: permission
          in: query
          required: false
          schema: { type: string }
      responses:
        '403':
          description: Forbidden without an institutional session
components:
  parameters:
    AcademicYear:
      name: academicYear
      in: path
      required: true
      description: Academic year in YYYY-YYYY form, e.g. 2026-2027. A value that does not parse returns 400.
      schema:
        type: string
        pattern: '^[0-9]{4}-[0-9]{4}$'
    CourseCode:
      name: courseCode
      in: path
      required: true
      description: Catalog course code, e.g. WMMB015-05.
      schema: { type: string }
  responses:
    ProblemBadRequest:
      description: RFC 9457 problem detail
      content:
        application/problem+json:
          schema: { $ref: '#/components/schemas/Problem' }
    ProblemNotFound:
      description: RFC 9457 problem detail
      content:
        application/problem+json:
          schema: { $ref: '#/components/schemas/Problem' }
  schemas:
    LocalizedText:
      type: object
      description: Bilingual string, Dutch and English. The catalog is authored in both languages.
      properties:
        en: { type: string }
        nl: { type: string }
    AcademicYear:
      type: object
      properties:
        id: { type: string, format: uuid }
        year: { type: string, examples: ['2026-2027'] }
        active: { type: boolean }
    OrganizationalUnit:
      type: object
      properties:
        id: { type: string, format: uuid }
        code: { type: string }
        titleEn: { type: string }
        titleNl: { type: string }
        ouClass: { type: string, enum: [UNIVERSITY, FACULTY, DEPARTMENT] }
        parent: { type: [string, 'null'], format: uuid }
    CourseSummary:
      type: object
      properties:
        id: { type: string, format: uuid }
        code: { type: string }
        title: { $ref: '#/components/schemas/LocalizedText' }
        levels:
          type: array
          description: Observed values across the 2026-2027 catalog, in frequency order.
          items:
            type: string
            enum: [MASTER, BACHELOR, EXCHANGE, PRE_MASTER, UNIVERSITY_LEVEL_MINOR, FACULTY_LEVEL_MINOR, POST_GRADUATE]
        credits: { type: number, description: ECTS credits }
        otherPeriods: { type: boolean }
        draft: { type: boolean }
    Course:
      type: object
      description: Full course record as served for a single course code.
      properties:
        id: { type: string, format: uuid }
        year: { type: string }
        code: { type: string }
        facultyCode: { type: string }
        facultyTitle: { $ref: '#/components/schemas/LocalizedText' }
        title: { $ref: '#/components/schemas/LocalizedText' }
        fullTitle: { $ref: '#/components/schemas/LocalizedText' }
        goals: { $ref: '#/components/schemas/LocalizedText' }
        description: { $ref: '#/components/schemas/LocalizedText' }
        prerequisites: { $ref: '#/components/schemas/LocalizedText' }
        credits: { type: number }
        hours: { type: integer, description: Contact hours; -1 where not recorded. }
        levels: { type: array, items: { type: string } }
        formats: { type: array, items: { type: object } }
        assessments: { type: array, items: { type: object } }
        courseTypes: { type: array, items: { type: object } }
        courseOfferings: { type: array, items: { type: object } }
        organizationalUnit: { type: string, format: uuid }
        organizationalUnitTitle: { $ref: '#/components/schemas/LocalizedText' }
        sustainableDevelopmentGoals:
          type: object
          description: Per-course flags for the seventeen UN Sustainable Development Goals.
        enlight:
          type: string
          description: Whether the course is offered through the ENLIGHT European university alliance.
        draft: { type: boolean }
        startYear: { type: string }
        endYear: { type: [string, 'null'] }
        modifiedAt:
          type: array
          items: { type: integer }
          description: Java LocalDateTime serialized as an array of integers.
    Program:
      type: object
      properties:
        id: { type: string, format: uuid }
        code: { type: string }
        title: { $ref: '#/components/schemas/LocalizedText' }
        levels:
          type: array
          items:
            type: string
            enum: [MASTER, BACHELOR, EXCHANGE, PRE_MASTER, UNIVERSITY_LEVEL_MINOR, FACULTY_LEVEL_MINOR, POST_GRADUATE]
        languages:
          type: array
          items: { type: string, enum: [ENGLISH, DUTCH] }
        credits: { type: number }
        term: { type: string }
        duration: { type: integer, description: Nominal duration in years. }
        facultyTitle: { $ref: '#/components/schemas/LocalizedText' }
        organizationalUnitTitle: { $ref: '#/components/schemas/LocalizedText' }
        official: { type: boolean }
        yearVisible: { type: boolean }
        otherPeriods: { type: boolean }
        draft: { type: boolean }
    Option:
      type: object
      properties:
        id: { type: string, format: uuid }
        textEn: { type: string }
        textNl: { type: string }
        position: { type: integer }
        handle: { type: string }
        path: { type: array, items: { type: string, format: uuid } }
        ouIds: { type: array, items: { type: string, format: uuid } }
    Problem:
      type: object
      description: RFC 9457 problem detail, as emitted by the Spring backend.
      properties:
        type: { type: string, examples: ['about:blank'] }
        title: { type: string }
        status: { type: integer }
        detail: { type: string }
        instance: { type: string }