openapi: 3.0.0
info:
  title: NUST LMS API
  version: 1.0.0
  description: |+
    NUST Learning Management System API for developer integrations (Moodle AJAX wrapper).
    Authenticate with your NUST LMS credentials via `POST /auth/login` to receive a bearer token, then call any operation with `Authorization: Bearer <token>`. The NustDevKit gateway logs into the LMS on your behalf and manages the underlying session (cookie + sesskey) server-side, so you never handle the ephemeral sesskey.

    ## Getting Started with the SDKs

    1. **Get the SDK** for your language — download the zip, unzip it, and install it:
       - **TypeScript** — [download](./sdks/nust-lms-api-ts_generic_lib.zip), then run `npm install` in the unzipped folder, then add it to your project.
       - **Python** — [download](./sdks/nust-lms-api-python_generic_lib.zip), then run `pip install -r requirements.txt` in the unzipped folder.
       - **Java** — [download](./sdks/nust-lms-api-java_eclipse_jre_lib.zip), then build the JAR with Gradle and add it to your project.
       - **.NET (C#)** — [download](./sdks/nust-lms-api-cs_net_standard_lib.zip), then add a project reference to the `NustLmsApi.Standard` project.
       - **Go** — [download](./sdks/nust-lms-api-go_generic_lib.zip), then add a local `replace` for the folder in your `go.mod`, then run `go get`.
       - **PHP** — [download](./sdks/nust-lms-api-php_generic_lib_v2.zip), then run `composer install` in the unzipped folder.
       - **Ruby** — [download](./sdks/nust-lms-api-ruby_generic_lib.zip), then run `gem build nust_lms_api.gemspec && gem install nust_lms_api-1.0.0.gem`.
    2. **Get a bearer token** from `POST /auth/login` with your NUST LMS credentials.
    3. **Initialize a client** with that token — see the **SDK Setup** section for the
       per-language code. Every other sample assumes that `client`.

    _Each SDK's own README has fuller, IDE-specific setup if you want it._

    ## Connect an AI assistant (MCP)

    Beyond the SDKs, this API is also an **MCP server**, so AI assistants (Claude
    Desktop, Cursor, VS Code, Claude.ai, ChatGPT) can call it as tools — for example,
    *"what deadlines do I have this week?"*. The login step is never exposed to the
    assistant: you authenticate yourself and hand it a token.

    Every client connects the same way — your server URL plus your bearer token:

    1. Get a token from `POST /auth/login`.
    2. **Desktop / editor clients** (Claude Desktop, Cursor, VS Code) — add it to the MCP config:

       ```json
       { "mcpServers": { "nust-lms": {
           "url": "https://<your-host>/mcp",
           "headers": { "Authorization": "Bearer <token>" } } } }
       ```

    3. **Web clients** (Claude.ai, ChatGPT) — open Settings → Connectors and add the same URL.

    Web clients reach the server from the cloud, so this needs the gateway on a public
    **HTTPS** URL. `http://127.0.0.1:8000/mcp` only works for desktop clients running on
    your own machine.

servers:
  - url: https://api.nustdevkit.com
    description: NustDevKit Gateway
  - url: http://127.0.0.1:8000
    description: NustDevKit Gateway (local development)
security:
  - BearerAuth: []
tags:
  - name: Authentication
    description: Exchange NUST LMS credentials for a gateway bearer token
  - name: Courses
    description: Course listing and enrollment operations
  - name: Calendar
    description: |
      Calendar operations. On NUST LMS, these "action events" are how deadlines are surfaced — assignment, lab, quiz, and other submission due dates each appear as a calendar event on the day the work must be submitted.
  - name: Account
    description: Your identity and account/site information
  - name: Notifications
    description: Notification retrieval operations
  - name: SDK Setup
    description: Install an SDK and initialize a client with your bearer token.
x-tagGroups:
  - name: Getting Started
    tags:
      - Authentication
      - SDK Setup
  - name: Academics
    tags:
      - Courses
      - Calendar
  - name: Profile & Messaging
    tags:
      - Account
      - Notifications
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: |
        Gateway-issued JWT. Obtain it from `POST /auth/login` using your NUST LMS credentials, then send it as `Authorization: Bearer <token>`. The gateway manages the underlying LMS session (cookie + sesskey) server-side, so the ephemeral sesskey never leaves the gateway.
  schemas:
    LoginRequest:
      type: object
      description: NUST LMS credentials used to obtain a gateway bearer token.
      required:
        - username
        - password
      properties:
        username:
          type: string
          description: NUST LMS username.
          example: johndoe.bscs23seecs
        password:
          type: string
          format: password
          description: NUST LMS password.
    TokenResponse:
      type: object
      description: Bearer token issued by the gateway after a successful login.
      required:
        - access_token
        - token_type
      properties:
        access_token:
          type: string
          description: "JWT to send as `Authorization: Bearer <token>` on subsequent requests."
        token_type:
          type: string
          default: bearer
          example: bearer
    CalendarEventVisibility:
      type: integer
      description: Visibility flag for a calendar event. 1 means the event is visible; 0 means it is hidden.
    CourseTimelineClassification:
      type: string
      description: Timeline classification filter for enrolled courses.
      enum:
        - all
        - inprogress
        - past
        - future
        - favourites
        - hidden
        - allincludinghidden
    CourseTimelineSortField:
      type: string
      description: Field used to sort enrolled course results.
      enum:
        - fullname
        - shortname
        - id
        - idnumber
        - timeaccess
    MoodleWarning:
      x-scalar-ignore: true
      type: object
      description: A non-fatal warning returned alongside a successful response.
      properties:
        item:
          type: string
          description: Item identifier related to the warning; empty string if not applicable.
          example: ""
        itemid:
          type: integer
          description: Numeric item ID related to the warning; 0 if not applicable.
          example: 0
        warningcode:
          type: string
          description: Machine-readable warning code; empty string if no code.
          example: ""
        message:
          type: string
          description: Human-readable warning description.
          example: ""
    SiteInfo:
      type: object
      description: |
        Your identity plus basic site information, from Moodle's site-info call. The `userid` here is what other endpoints need (e.g. it is the `useridto` for popup notifications).
      required:
        - userid
        - username
        - fullname
        - sitename
      properties:
        userid:
          type: integer
          description: Your numeric Moodle user ID.
          example: 234567
        username:
          type: string
          description: Your login username.
          example: johndoe.bscs23seecs
        firstname:
          type: string
          description: Your first name.
          example: John
        lastname:
          type: string
          description: Your last name.
          example: Doe
        fullname:
          type: string
          description: Your full display name.
          example: John Doe
        userpictureurl:
          type: string
          format: uri
          description: URL of your profile picture.
          example: https://lms.nust.edu.pk/portal/pluginfile.php/1583361/user/icon/moove/f1
        lang:
          type: string
          description: Your preferred interface language code.
          example: en
        sitename:
          type: string
          description: Name of the LMS site.
          example: NUST LMS
        siteurl:
          type: string
          format: uri
          description: Base URL of the LMS site.
          example: https://lms.nust.edu.pk/portal
        release:
          type: string
          description: Moodle release/version string of the site.
          example: 4.1.2
    MoodleError:
      x-scalar-ignore: true
      type: object
      description: Error returned by the LMS on a failed operation.
      properties:
        errorcode:
          type: string
          description: Machine-readable error code identifier.
          example: invalidrecord
        message:
          type: string
          description: Human-readable error description.
          example: Can't find data record in database table.
        link:
          type: string
          description: Redirect URL for the user; empty string if not applicable.
          example: ""
        moreinfourl:
          type: string
          description: URL to additional error documentation; empty string if not available.
          example: ""
        debuginfo:
          type: string
          description: Additional debug information; empty string when not in debug mode.
          example: ""
    Course:
      type: object
      description: An enrolled course.
      required:
        - id
        - fullname
        - shortname
        - idnumber
        - summary
        - summaryformat
        - startdate
        - enddate
        - visible
        - fullnamedisplay
        - viewurl
        - progress
        - hasprogress
        - isfavourite
        - hidden
        - showshortname
        - coursecategory
      properties:
        id:
          type: integer
          description: Unique course identifier.
          example: 49900
        fullname:
          type: string
          description: Full display name of the course.
          example: CS-212 Object Oriented Programming BSCS-13 2K23 ABC
        shortname:
          type: string
          description: Short course code or abbreviated name.
          example: CS-212-Sp'24 BSCS-13 2K23 ABC
        idnumber:
          type: string
          description: Institution-assigned course ID number; empty string if not set.
          example: ""
        summary:
          type: string
          description: HTML summary of the course.
          example: ""
        summaryformat:
          type: integer
          description: Format of the summary field (1 = HTML).
          example: 1
        startdate:
          type: integer
          description: Course start date as Unix timestamp.
          example: 1706468400
        enddate:
          type: integer
          description: Course end date as Unix timestamp. 0 means no end date.
          example: 1717362000
        visible:
          type: boolean
          description: Whether the course is visible to enrolled students.
          example: true
        fullnamedisplay:
          type: string
          description: Display name of the course (may differ from fullname for context).
          example: CS-212 Object Oriented Programming BSCS-13 2K23 ABC
        viewurl:
          type: string
          format: uri
          description: URL to the course page on the LMS portal.
          example: https://lms.nust.edu.pk/portal/course/view.php?id=49900
        progress:
          type: integer
          minimum: 0
          maximum: 100
          description: Student's completion progress as a percentage.
          example: 21
        hasprogress:
          type: boolean
          description: Whether completion tracking is enabled for this course.
          example: true
        isfavourite:
          type: boolean
          description: Whether the user has marked this course as a favourite.
          example: false
        hidden:
          type: boolean
          description: Whether the user has hidden this course from their dashboard.
          example: false
        showshortname:
          type: boolean
          description: Whether the short name is displayed alongside the full name.
          example: false
        coursecategory:
          type: string
          description: Name of the category this course belongs to.
          example: 2nd Semester (SP-2024)
    RecentCourseFields:
      type: object
      description: Additional fields specific to recently accessed courses.
      required:
        - timeaccess
      properties:
        timeaccess:
          type: integer
          description: Unix timestamp of the user's most recent access to this course.
          example: 1781632422
    RecentCourse:
      description: A recently accessed course, extending Course with the last-access timestamp.
      allOf:
        - $ref: "#/components/schemas/Course"
        - $ref: "#/components/schemas/RecentCourseFields"
    EnrolledCoursesResponse:
      type: object
      description: Paginated enrolled-courses response.
      required:
        - courses
        - nextoffset
      properties:
        courses:
          type: array
          description: List of enrolled courses for the current page.
          items:
            $ref: "#/components/schemas/Course"
        nextoffset:
          type: integer
          description: Offset to pass on the next page request; -1 when no further pages exist.
          example: 29
    CourseContentFile:
      type: object
      description: A single file (or link) uploaded inside a course module.
      required:
        - type
        - filename
        - fileurl
      properties:
        type:
          type: string
          description: Content type, e.g. 'file' or 'url'.
          example: file
        filename:
          type: string
          description: Name of the file (or title of the link).
          example: Lecture01-Intro.pdf
        filepath:
          type: string
          nullable: true
          description: Folder path within the module; "/" for the module root.
          example: /
        filesize:
          type: integer
          description: File size in bytes (0 for links).
          example: 482133
        fileurl:
          type: string
          description: |
            Moodle pluginfile.php URL for the content. Downloading the bytes requires authentication (a webservice token or the active session); the URL alone is not publicly fetchable.
          example: https://lms.nust.edu.pk/portal/webservice/pluginfile.php/123456/mod_resource/content/1/Lecture01-Intro.pdf
        mimetype:
          type: string
          nullable: true
          description: MIME type of the file when applicable.
          example: application/pdf
        timemodified:
          type: integer
          description: Unix timestamp of the last modification.
          example: 1707745200
    CourseModule:
      type: object
      description: An item on the course page — an activity or resource (file, page, URL, assignment, ...).
      required:
        - id
        - name
        - modname
      properties:
        id:
          type: integer
          description: Course module ID (cmid).
          example: 987654
        name:
          type: string
          description: Display name of the module.
          example: Lecture 01 — Introduction
        modname:
          type: string
          description: |
            Module type, e.g. 'resource' (file), 'folder', 'url', 'page', 'label', 'assign', 'quiz', 'forum'.
          example: resource
        modplural:
          type: string
          description: Human-readable plural label for the module type.
          example: Files
        instance:
          type: integer
          description: Instance ID of the activity within its module type.
          example: 45678
        description:
          type: string
          nullable: true
          description: HTML description/intro for the module, when present.
          example: <p>Course introduction and logistics.</p>
        visible:
          type: integer
          description: Whether the module is visible (1) or hidden (0).
          example: 1
        uservisible:
          type: boolean
          description: Whether the module is visible to the current user.
          example: true
        url:
          type: string
          nullable: true
          description: Link to open the activity/resource, when applicable.
          example: https://lms.nust.edu.pk/portal/mod/resource/view.php?id=987654
        modicon:
          type: string
          nullable: true
          description: URL of the module's type icon.
          example: https://lms.nust.edu.pk/portal/theme/image.php/moove/core/1/f/pdf
        contents:
          type: array
          description: Uploaded files/links for this module (present for resource/folder modules).
          items:
            $ref: "#/components/schemas/CourseContentFile"
    CourseSection:
      type: object
      description: A section (week/topic) of the course, containing its modules.
      required:
        - id
        - name
        - section
        - modules
      properties:
        id:
          type: integer
          description: Section ID.
          example: 33445
        name:
          type: string
          description: Section title (e.g. a week or topic name).
          example: Week 1
        section:
          type: integer
          description: Zero-based section number within the course.
          example: 1
        visible:
          type: integer
          description: Whether the section is visible (1) or hidden (0).
          example: 1
        summary:
          type: string
          nullable: true
          description: HTML summary shown at the top of the section.
          example: <p>Introduction and course overview.</p>
        summaryformat:
          type: integer
          description: Moodle text format of the summary (1 = HTML).
          example: 1
        uservisible:
          type: boolean
          description: Whether the section is visible to the current user.
          example: true
        modules:
          type: array
          description: The activities and resources in this section.
          items:
            $ref: "#/components/schemas/CourseModule"
    EventIcon:
      type: object
      description: Icon metadata for a calendar event.
      required:
        - key
        - component
        - alttext
      properties:
        key:
          type: string
          description: Icon key name used to locate the icon asset.
          example: icon
        component:
          type: string
          description: Moodle component that owns the icon (e.g., 'assign').
          example: assign
        alttext:
          type: string
          description: Accessible alt text for the icon image.
          example: Activity event
    EventSubscription:
      type: object
      description: Subscription display settings for a calendar event.
      required:
        - displayeventsource
      properties:
        displayeventsource:
          type: boolean
          description: Whether to display the event source label on the calendar.
          example: false
    EventAction:
      type: object
      description: Primary action button metadata for a calendar event.
      required:
        - name
        - url
        - itemcount
        - actionable
        - showitemcount
      properties:
        name:
          type: string
          description: Display label for the primary action button.
          example: Add submission
        url:
          type: string
          format: uri
          description: URL the user should navigate to in order to perform the action.
          example: https://lms.nust.edu.pk/portal/mod/assign/view.php?id=999404&action=editsubmission
        itemcount:
          type: integer
          description: Number of items associated with this action.
          example: 1
        actionable:
          type: boolean
          description: Whether the action can currently be taken by the user.
          example: true
        showitemcount:
          type: boolean
          description: Whether to display the item count alongside the action label.
          example: false
    CalendarEvent:
      type: object
      description: |
        A calendar action event. On NUST LMS these represent deadlines — the due date for an assignment, lab, quiz, or other submission tied to a course activity.
      required:
        - id
        - name
        - description
        - descriptionformat
        - location
        - component
        - modulename
        - instance
        - eventtype
        - timestart
        - timeduration
        - timesort
        - visible
        - timemodified
        - icon
        - course
        - subscription
        - canedit
        - candelete
        - deleteurl
        - editurl
        - viewurl
        - formattedtime
        - isactionevent
        - iscourseevent
        - iscategoryevent
        - normalisedeventtype
        - normalisedeventtypetext
        - url
      properties:
        id:
          type: integer
          description: Unique calendar event identifier.
          example: 149885
        name:
          type: string
          description: Display name of the calendar event.
          example: Lab 1 BSCS 13C is due
        description:
          type: string
          description: HTML description body of the event.
          example: <p dir="ltr">Lab 1 BSCS 13C<br /></p>
        descriptionformat:
          type: integer
          description: Text format of the description (1 = HTML).
          example: 1
        location:
          type: string
          description: Physical or virtual location of the event; empty string if not specified.
          example: ""
        categoryid:
          type: integer
          nullable: true
          description: Course category ID; null if not a category event.
          example: null
        groupid:
          type: integer
          nullable: true
          description: Group ID if the event is group-specific; null otherwise.
          example: null
        userid:
          type: integer
          nullable: true
          description: User ID if the event is user-specific; null otherwise.
          example: null
        repeatid:
          type: integer
          nullable: true
          description: ID of the repeat group for recurring events; null if not recurring.
          example: null
        eventcount:
          type: integer
          nullable: true
          description: Total number of events in the repeat group; null if not applicable.
          example: null
        component:
          type: string
          description: Moodle component that created the event (e.g., 'mod_assign').
          example: mod_assign
        modulename:
          type: string
          description: Short name of the Moodle activity module (e.g., 'assign').
          example: assign
        instance:
          type: integer
          description: The course module instance ID.
          example: 999404
        eventtype:
          type: string
          description: Type of the event (e.g., 'due', 'open', 'close').
          example: due
        timestart:
          type: integer
          description: Event start time as Unix timestamp.
          example: 1706900340
        timeduration:
          type: integer
          description: Duration in seconds; 0 for point-in-time events.
          example: 0
        timesort:
          type: integer
          description: Sort timestamp used for ordering events.
          example: 1706900340
        visible:
          $ref: "#/components/schemas/CalendarEventVisibility"
        timemodified:
          type: integer
          description: Last modification time as Unix timestamp.
          example: 1779088440
        icon:
          $ref: "#/components/schemas/EventIcon"
        course:
          $ref: "#/components/schemas/Course"
        subscription:
          $ref: "#/components/schemas/EventSubscription"
        canedit:
          type: boolean
          description: Whether the current user can edit this event.
          example: false
        candelete:
          type: boolean
          description: Whether the current user can delete this event.
          example: false
        deleteurl:
          type: string
          format: uri
          description: URL to delete this calendar event.
          example: https://lms.nust.edu.pk/portal/calendar/delete.php?id=149885&course=49900
        editurl:
          type: string
          format: uri
          description: URL to edit the underlying course module associated with this event.
          example: https://lms.nust.edu.pk/portal/course/mod.php?update=999404&return=1&sesskey=XXXX
        viewurl:
          type: string
          format: uri
          description: URL to view this event on the calendar.
          example: https://lms.nust.edu.pk/portal/calendar/view.php?view=day&course=49900&time=1706900340
        formattedtime:
          type: string
          description: HTML-formatted human-readable event time string.
          example: <span class="dimmed_text">Friday, 2 February, 11:59 PM</span>
        isactionevent:
          type: boolean
          description: Whether this is an action event requiring user interaction.
          example: true
        iscourseevent:
          type: boolean
          description: Whether this event is associated with a specific course.
          example: false
        iscategoryevent:
          type: boolean
          description: Whether this event is associated with a course category.
          example: false
        groupname:
          type: string
          nullable: true
          description: Name of the group for group-specific events; null otherwise.
          example: null
        normalisedeventtype:
          type: string
          description: Normalised event type identifier used for display grouping.
          example: course
        normalisedeventtypetext:
          type: string
          description: Human-readable label for the normalised event type.
          example: Course event
        action:
          $ref: "#/components/schemas/EventAction"
        url:
          type: string
          format: uri
          description: Direct URL to the course activity associated with this event.
          example: https://lms.nust.edu.pk/portal/mod/assign/view.php?id=999404
    CalendarEventsResponse:
      type: object
      description: A list of calendar events with pagination boundary IDs.
      required:
        - events
        - firstid
        - lastid
      properties:
        events:
          type: array
          description: List of calendar action events for the current result set.
          items:
            $ref: "#/components/schemas/CalendarEvent"
        firstid:
          type: integer
          description: Event ID of the first item in the result set.
          example: 149885
        lastid:
          type: integer
          description: Event ID of the last item in the result set.
          example: 151886
    Notification:
      type: object
      description: A popup notification message delivered to a user.
      required:
        - id
        - useridfrom
        - useridto
        - subject
        - shortenedsubject
        - text
        - fullmessage
        - fullmessageformat
        - fullmessagehtml
        - smallmessage
        - contexturl
        - contexturlname
        - timecreated
        - timecreatedpretty
        - read
        - deleted
        - iconurl
        - component
        - eventtype
        - customdata
      properties:
        id:
          type: integer
          description: Unique notification identifier.
          example: 4857819
        useridfrom:
          type: integer
          description: User ID of the sender.
          example: 234567
        useridto:
          type: integer
          description: User ID of the recipient.
          example: 123456
        subject:
          type: string
          description: Subject line of the notification.
          example: "CS-101 Introduction to Computing: Lab 3 Submission Deadline"
        shortenedsubject:
          type: string
          description: Shortened version of the notification subject for compact display.
          example: "CS-101 Introduction to Computing: Lab 3 Submission Deadline"
        text:
          type: string
          description: Short HTML excerpt of the notification.
          example: <p>John Doe posted in CS-101 Introduction to Computing...</p>
        fullmessage:
          type: string
          description: Full plain-text body of the notification.
        fullmessageformat:
          type: integer
          description: Format identifier for fullmessagehtml (2 = Markdown source).
          example: 2
        fullmessagehtml:
          type: string
          description: Full HTML body of the notification email.
        smallmessage:
          type: string
          description: Short plain-text preview of the notification.
          example: John Doe posted in CS-101 Introduction to Computing...
        contexturl:
          type: string
          format: uri
          description: URL to the relevant context for this notification (e.g., a forum post).
          example: https://lms.nust.edu.pk/portal/mod/forum/discuss.php?d=41767#p52342
        contexturlname:
          type: string
          description: Human-readable label for the context URL link.
          example: Lab Sessional Finalization - (DL - Section D & E)
        timecreated:
          type: integer
          description: Unix timestamp when the notification was created.
          example: 1780045085
        timecreatedpretty:
          type: string
          description: Human-readable relative time string (e.g., '19 days ago').
          example: 19 days ago
        timeread:
          type: integer
          nullable: true
          description: Unix timestamp when the notification was read; null if unread.
          example: null
        read:
          type: boolean
          description: Whether the notification has been read by the recipient.
          example: false
        deleted:
          type: boolean
          description: Whether the notification has been deleted by the recipient.
          example: false
        iconurl:
          type: string
          format: uri
          description: URL to the icon image representing the notification source.
          example: https://lms.nust.edu.pk/portal/theme/image.php/moove/mod_forum/1778048051/icon
        component:
          type: string
          description: Moodle component that generated the notification (e.g., 'mod_forum').
          example: mod_forum
        eventtype:
          type: string
          description: Event type within the component that triggered the notification (e.g., 'posts').
          example: posts
        customdata:
          type: string
          description: |
            JSON-encoded string with additional notification metadata (cmid, instance, discussionid, postid, etc.).
          example: '{"cmid":"1272420","instance":"62569","discussionid":"41767"}'
    PopupNotificationsResponse:
      type: object
      description: Response envelope for the popup-notifications endpoint.
      required:
        - notifications
        - unreadcount
      properties:
        notifications:
          type: array
          description: List of popup notifications for the user.
          items:
            $ref: "#/components/schemas/Notification"
        unreadcount:
          type: integer
          description: Total number of unread notifications for the user.
          example: 1
    GetRecentCoursesRequest:
      x-scalar-ignore: true
      type: object
      description: Request parameters for retrieving recently accessed courses.
      required:
        - limit
      properties:
        limit:
          type: integer
          description: Maximum number of courses to return.
          default: 10
          example: 10
    GetEnrolledCoursesByTimelineRequest:
      x-scalar-ignore: true
      type: object
      description: Request parameters for retrieving enrolled courses filtered by timeline classification.
      required:
        - offset
        - limit
        - classification
        - sort
      properties:
        offset:
          type: integer
          description: Zero-based pagination offset.
          default: 0
          example: 0
        limit:
          type: integer
          description: Maximum number of courses to return.
          default: 50
          example: 50
        classification:
          $ref: "#/components/schemas/CourseTimelineClassification"
        sort:
          $ref: "#/components/schemas/CourseTimelineSortField"
    GetCalendarEventsByTimesortRequest:
      x-scalar-ignore: true
      type: object
      description: Request parameters for retrieving calendar action events sorted by time.
      required:
        - limitnum
        - timesortfrom
      properties:
        limitnum:
          type: integer
          description: Maximum number of events to return.
          example: 20
        timesortfrom:
          type: integer
          description: |
            Only return events with timesort >= this Unix timestamp. Pass 0 for no lower bound.
          example: 0
        timesortto:
          type: integer
          description: Only return events with timesort <= this Unix timestamp. Optional.
        aftereventid:
          type: integer
          description: Return events whose ID is greater than this value (cursor pagination). Optional.
    GetCalendarEventsByCourseRequest:
      x-scalar-ignore: true
      type: object
      description: Request parameters for retrieving calendar action events for a specific course.
      required:
        - courseid
      properties:
        courseid:
          type: integer
          description: ID of the course to fetch events for.
          example: 49906
        timesortfrom:
          type: integer
          description: Only return events with timesort >= this Unix timestamp. Optional.
        timesortto:
          type: integer
          description: Only return events with timesort <= this Unix timestamp. Optional.
        aftereventid:
          type: integer
          description: Cursor-based pagination — return events after this event ID. Optional.
        limitnum:
          type: integer
          description: Maximum number of events to return. Optional.
    GetPopupNotificationsRequest:
      x-scalar-ignore: true
      type: object
      description: Request parameters for retrieving popup notifications for a user.
      required:
        - useridto
        - limit
        - offset
      properties:
        useridto:
          type: string
          description: ID of the recipient user, passed as a string.
          example: "123456"
        limit:
          type: integer
          description: Maximum number of notifications to return.
          example: 20
        offset:
          type: integer
          description: Pagination offset.
          default: 0
          example: 0
paths:
  /auth/login:
    post:
      operationId: login
      summary: Log in with NUST LMS credentials
      description: |
        Authenticates against NUST LMS on your behalf and returns a gateway JWT. The LMS session (cookie + sesskey) is created and held server-side; use the returned token as `Authorization: Bearer <token>` for every other operation.
      tags:
        - Authentication
      security: []
      requestBody:
        required: true
        description: NUST LMS credentials.
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/LoginRequest"
      responses:
        "200":
          description: Authentication succeeded; bearer token issued.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TokenResponse"
        "401":
          description: Invalid LMS credentials.
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: string
                    example: Invalid LMS credentials.
      x-codeSamples:
        - lang: typescript
          label: TypeScript
          source: |-
            const body: LoginRequest = {
              username: 'johndoe.bscs23seecs',
              password: 'password0',
            };

            try {
              const response = await authenticationApi.login(body);

              // Extracting fully parsed response body.
              console.log(response.result);

              // Extracting response status code.
              console.log(response.statusCode);
              // Extracting response headers.
              console.log(response.headers);
              // Extracting response body of type `string | Stream`
              console.log(response.body);
            } catch (error) {
              if (error instanceof ApiError) {
                // Extracting response error status code.
                console.log(error.statusCode);
                // Extracting response error headers.
                console.log(error.headers);
                // Extracting response error body of type `string | Stream`.
                console.log(error.body);
                if (error instanceof AuthLogin401Error) {
                  console.log(error.result);
                }
              }
            }
        - lang: python
          label: Python
          source: |-
            body = LoginRequest(
                username='johndoe.bscs23seecs',
                password='password0'
            )

            result = authentication_api.login(body)

            if result.is_success():
                print(result.body)
            elif result.is_error():
                print(result.errors)
        - lang: java
          label: Java
          source: |-
            LoginRequest body = new LoginRequest.Builder(
                "johndoe.bscs23seecs",
                "password0"
            )
            .build();

            authenticationApi.loginAsync(body).thenAccept(result -> {
                // TODO success callback handler
                System.out.println(result);
            }).exceptionally(exception -> {
                Throwable cause = exception.getCause();

                if (cause instanceof AuthLogin401ErrorException) {
                    AuthLogin401ErrorException authLogin401ErrorException = (AuthLogin401ErrorException) cause;
                    authLogin401ErrorException.printStackTrace();
                } else {
                    // fallback for unexpected errors
                    exception.printStackTrace();
                }

                return null;
            });
        - lang: csharp
          label: .NET (C#)
          source: |-
            LoginRequest body = new LoginRequest
            {
                Username = "johndoe.bscs23seecs",
                Password = "password0",
            };

            try
            {
                ApiResponse<TokenResponse> result = await authenticationApi.LoginAsync(body);
            }
            catch (ApiException e)
            {
                Console.WriteLine(e.Message);
                if (e is AuthLogin401ErrorException)
                {
                   // TODO: Handle AuthLogin401ErrorException exception here
                }
            }
        - lang: go
          label: Go
          source: |-
            ctx := context.Background()

            body := models.LoginRequest{
                Username:              "johndoe.bscs23seecs",
                Password:              "password0",
            }

            apiResponse, err := authenticationApi.Login(ctx, body)
            if err != nil {
                switch typedErr := err.(type) {
                    case *errors.AuthLogin401Error:
                        log.Fatalln("AuthLogin401ErrorException: ", typedErr)
                    default:
                        log.Fatalln(err)
                }
            } else {
                // Printing the result and response
                fmt.Println(apiResponse.Data)
                fmt.Println(apiResponse.Response.StatusCode)
            }
        - lang: php
          label: PHP
          source: |-
            $body = LoginRequestBuilder::init(
                'johndoe.bscs23seecs',
                'password0'
            )->build();

            $authenticationApi = $client->getAuthenticationApi();
            $apiResponse = $authenticationApi->login($body);

            // Extracting response status code
            var_dump($apiResponse->getStatusCode());
            // Extracting response headers
            var_dump($apiResponse->getHeaders());

            if ($apiResponse->isSuccess()) {
                echo 'TokenResponse:';
                var_dump($apiResponse->getResult());
            } else {
                $error = $apiResponse->getResult();
                var_dump($error);
            }
        - lang: ruby
          label: Ruby
          source: |-
            body = LoginRequest.new(
              username: 'johndoe.bscs23seecs',
              password: 'password0'
            )

            result = authentication_api.login(body)

            if result.success?
              puts result.data
            elsif result.error?
              warn result.errors
            end
  /service/core_course_get_recent_courses:
    get:
      operationId: getCoreRecentCourses
      summary: Get recently accessed courses
      description: |
        Returns the courses the authenticated user has accessed most recently, ordered by last access time.
        Moodle method: `core_course_get_recent_courses`
      tags:
        - Courses
      parameters:
        - name: limit
          in: query
          required: true
          description: Maximum number of courses to return.
          schema:
            type: integer
            default: 10
      responses:
        "200":
          description: List of recently accessed courses ordered by last access.
          content:
            application/json:
              schema:
                type: array
                description: Recently accessed courses ordered by last access time.
                items:
                  $ref: "#/components/schemas/RecentCourse"
        "400":
          description: Bad request or Moodle exception.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MoodleError"
      x-codeSamples:
        - lang: typescript
          label: TypeScript
          source: |-
            const limit = 10;

            try {
              const response = await coursesApi.getCoreRecentCourses(limit);

              // Extracting fully parsed response body.
              console.log(response.result);

              // Extracting response status code.
              console.log(response.statusCode);
              // Extracting response headers.
              console.log(response.headers);
              // Extracting response body of type `string | Stream`
              console.log(response.body);
            } catch (error) {
              if (error instanceof ApiError) {
                // Extracting response error status code.
                console.log(error.statusCode);
                // Extracting response error headers.
                console.log(error.headers);
                // Extracting response error body of type `string | Stream`.
                console.log(error.body);
                if (error instanceof MoodleError) {
                  console.log(error.result);
                }
              }
            }
        - lang: python
          label: Python
          source: |-
            limit = 10

            result = courses_api.get_core_recent_courses(limit)

            if result.is_success():
                print(result.body)
            elif result.is_error():
                print(result.errors)
        - lang: java
          label: Java
          source: |-
            int limit = 10;

            coursesApi.getCoreRecentCoursesAsync(limit).thenAccept(result -> {
                // TODO success callback handler
                System.out.println(result);
            }).exceptionally(exception -> {
                Throwable cause = exception.getCause();

                if (cause instanceof MoodleErrorException) {
                    MoodleErrorException moodleErrorException = (MoodleErrorException) cause;
                    moodleErrorException.printStackTrace();
                } else {
                    // fallback for unexpected errors
                    exception.printStackTrace();
                }

                return null;
            });
        - lang: csharp
          label: .NET (C#)
          source: |-
            int limit = 10;
            try
            {
                ApiResponse<List<RecentCourse>> result = await coursesApi.GetCoreRecentCoursesAsync(limit);
            }
            catch (ApiException e)
            {
                Console.WriteLine(e.Message);
                if (e is MoodleErrorException)
                {
                   // TODO: Handle MoodleErrorException exception here
                }
            }
        - lang: go
          label: Go
          source: |-
            ctx := context.Background()

            limit := 10

            apiResponse, err := coursesApi.GetCoreRecentCourses(ctx, limit)
            if err != nil {
                switch typedErr := err.(type) {
                    case *errors.MoodleError:
                        log.Fatalln("MoodleErrorException: ", typedErr)
                    default:
                        log.Fatalln(err)
                }
            } else {
                // Printing the result and response
                fmt.Println(apiResponse.Data)
                fmt.Println(apiResponse.Response.StatusCode)
            }
        - lang: php
          label: PHP
          source: |-
            $limit = 10;

            $coursesApi = $client->getCoursesApi();
            $apiResponse = $coursesApi->getCoreRecentCourses($limit);

            // Extracting response status code
            var_dump($apiResponse->getStatusCode());
            // Extracting response headers
            var_dump($apiResponse->getHeaders());

            if ($apiResponse->isSuccess()) {
                echo 'RecentCourse[]:';
                var_dump($apiResponse->getResult());
            } else {
                $error = $apiResponse->getResult();
                var_dump($error);
            }
        - lang: ruby
          label: Ruby
          source: |-
            limit = 10

            result = courses_api.get_core_recent_courses(limit)

            if result.success?
              puts result.data
            elsif result.error?
              warn result.errors
            end
  /service/core_course_get_enrolled_courses_by_timeline_classification:
    get:
      operationId: getEnrolledCoursesByTimeline
      summary: Get enrolled courses by timeline classification
      description: |
        Returns all courses the user is enrolled in, filtered by timeline classification and sorted by a chosen field. Supports pagination via offset.
        Moodle method: `core_course_get_enrolled_courses_by_timeline_classification`
      tags:
        - Courses
      parameters:
        - name: offset
          in: query
          required: true
          description: Zero-based pagination offset.
          schema:
            type: integer
            default: 0
        - name: limit
          in: query
          required: true
          description: Maximum number of courses to return.
          schema:
            type: integer
            default: 50
        - name: classification
          in: query
          required: true
          description: Timeline classification filter for enrolled courses.
          schema:
            $ref: "#/components/schemas/CourseTimelineClassification"
        - name: sort
          in: query
          required: true
          description: Field used to sort enrolled course results.
          schema:
            $ref: "#/components/schemas/CourseTimelineSortField"
      responses:
        "200":
          description: Paginated list of enrolled courses.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnrolledCoursesResponse"
        "400":
          description: Bad request or Moodle exception.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MoodleError"
      x-codeSamples:
        - lang: typescript
          label: TypeScript
          source: |-
            const offset = 0;

            const limit = 50;

            const classification = CourseTimelineClassification.Inprogress;

            const sort = CourseTimelineSortField.Idnumber;

            try {
              const response = await coursesApi.getEnrolledCoursesByTimeline(
                offset,
                limit,
                classification,
                sort
              );

              // Extracting fully parsed response body.
              console.log(response.result);

              // Extracting response status code.
              console.log(response.statusCode);
              // Extracting response headers.
              console.log(response.headers);
              // Extracting response body of type `string | Stream`
              console.log(response.body);
            } catch (error) {
              if (error instanceof ApiError) {
                // Extracting response error status code.
                console.log(error.statusCode);
                // Extracting response error headers.
                console.log(error.headers);
                // Extracting response error body of type `string | Stream`.
                console.log(error.body);
                if (error instanceof MoodleError) {
                  console.log(error.result);
                }
              }
            }
        - lang: python
          label: Python
          source: |-
            offset = 0

            limit = 50

            classification = CourseTimelineClassification.INPROGRESS

            sort = CourseTimelineSortField.IDNUMBER

            result = courses_api.get_enrolled_courses_by_timeline(
                offset,
                limit,
                classification,
                sort
            )

            if result.is_success():
                print(result.body)
            elif result.is_error():
                print(result.errors)
        - lang: java
          label: Java
          source: |-
            int offset = 0;
            int limit = 50;
            CourseTimelineClassification classification = CourseTimelineClassification.INPROGRESS;
            CourseTimelineSortField sort = CourseTimelineSortField.IDNUMBER;

            coursesApi.getEnrolledCoursesByTimelineAsync(offset, limit, classification, sort).thenAccept(result -> {
                // TODO success callback handler
                System.out.println(result);
            }).exceptionally(exception -> {
                Throwable cause = exception.getCause();

                if (cause instanceof MoodleErrorException) {
                    MoodleErrorException moodleErrorException = (MoodleErrorException) cause;
                    moodleErrorException.printStackTrace();
                } else {
                    // fallback for unexpected errors
                    exception.printStackTrace();
                }

                return null;
            });
        - lang: csharp
          label: .NET (C#)
          source: |-
            int offset = 0;
            int limit = 50;
            CourseTimelineClassification classification = CourseTimelineClassification.Inprogress;
            CourseTimelineSortField sort = CourseTimelineSortField.Idnumber;
            try
            {
                ApiResponse<EnrolledCoursesResponse> result = await coursesApi.GetEnrolledCoursesByTimelineAsync(
                    offset,
                    limit,
                    classification,
                    sort
                );
            }
            catch (ApiException e)
            {
                Console.WriteLine(e.Message);
                if (e is MoodleErrorException)
                {
                   // TODO: Handle MoodleErrorException exception here
                }
            }
        - lang: go
          label: Go
          source: |-
            ctx := context.Background()

            offset := 0

            limit := 50

            classification := models.CourseTimelineClassification_Inprogress

            sort := models.CourseTimelineSortField_Idnumber

            apiResponse, err := coursesApi.GetEnrolledCoursesByTimeline(ctx, offset, limit, classification, sort)
            if err != nil {
                switch typedErr := err.(type) {
                    case *errors.MoodleError:
                        log.Fatalln("MoodleErrorException: ", typedErr)
                    default:
                        log.Fatalln(err)
                }
            } else {
                // Printing the result and response
                fmt.Println(apiResponse.Data)
                fmt.Println(apiResponse.Response.StatusCode)
            }
        - lang: php
          label: PHP
          source: |-
            $offset = 0;

            $limit = 50;

            $classification = CourseTimelineClassification::INPROGRESS;

            $sort = CourseTimelineSortField::IDNUMBER;

            $coursesApi = $client->getCoursesApi();
            $apiResponse = $coursesApi->getEnrolledCoursesByTimeline(
                $offset,
                $limit,
                $classification,
                $sort
            );

            // Extracting response status code
            var_dump($apiResponse->getStatusCode());
            // Extracting response headers
            var_dump($apiResponse->getHeaders());

            if ($apiResponse->isSuccess()) {
                echo 'EnrolledCoursesResponse:';
                var_dump($apiResponse->getResult());
            } else {
                $error = $apiResponse->getResult();
                var_dump($error);
            }
        - lang: ruby
          label: Ruby
          source: |-
            offset = 0

            limit = 50

            classification = CourseTimelineClassification::INPROGRESS

            sort = CourseTimelineSortField::IDNUMBER

            result = courses_api.get_enrolled_courses_by_timeline(
              offset,
              limit,
              classification,
              sort
            )

            if result.success?
              puts result.data
            elsif result.error?
              warn result.errors
            end
  /service/core_course_get_contents:
    get:
      operationId: getCourseContents
      summary: Get all content for a course
      description: |
        Returns the full content structure of a course — its sections (weeks/topics) and the modules within them (files, folders, pages, URLs, assignments, and other activities), including metadata for each uploaded file. This is the data the course page itself is built from.
        Note: file URLs point at Moodle's `pluginfile.php` and require authentication (a webservice token or the active session) to download — the URL alone is not publicly fetchable.
        Moodle method: `core_course_get_contents`
      tags:
        - Courses
      parameters:
        - name: courseid
          in: query
          required: true
          description: ID of the course whose contents to retrieve.
          schema:
            type: integer
      responses:
        "200":
          description: Course sections, each with its modules and their uploaded files.
          content:
            application/json:
              schema:
                type: array
                description: The course's sections, in display order.
                items:
                  $ref: "#/components/schemas/CourseSection"
        "400":
          description: Bad request or Moodle exception.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MoodleError"
      x-codeSamples:
        - lang: typescript
          label: TypeScript
          source: |-
            const courseid = 74;

            try {
              const response = await coursesApi.getCourseContents(courseid);

              // Extracting fully parsed response body.
              console.log(response.result);

              // Extracting response status code.
              console.log(response.statusCode);
              // Extracting response headers.
              console.log(response.headers);
              // Extracting response body of type `string | Stream`
              console.log(response.body);
            } catch (error) {
              if (error instanceof ApiError) {
                // Extracting response error status code.
                console.log(error.statusCode);
                // Extracting response error headers.
                console.log(error.headers);
                // Extracting response error body of type `string | Stream`.
                console.log(error.body);
                if (error instanceof MoodleError) {
                  console.log(error.result);
                }
              }
            }
        - lang: python
          label: Python
          source: |-
            courseid = 74

            result = courses_api.get_course_contents(courseid)

            if result.is_success():
                print(result.body)
            elif result.is_error():
                print(result.errors)
        - lang: java
          label: Java
          source: |-
            int courseid = 74;

            coursesApi.getCourseContentsAsync(courseid).thenAccept(result -> {
                // TODO success callback handler
                System.out.println(result);
            }).exceptionally(exception -> {
                Throwable cause = exception.getCause();

                if (cause instanceof MoodleErrorException) {
                    MoodleErrorException moodleErrorException = (MoodleErrorException) cause;
                    moodleErrorException.printStackTrace();
                } else {
                    // fallback for unexpected errors
                    exception.printStackTrace();
                }

                return null;
            });
        - lang: csharp
          label: .NET (C#)
          source: |-
            int courseid = 74;
            try
            {
                ApiResponse<List<CourseSection>> result = await coursesApi.GetCourseContentsAsync(courseid);
            }
            catch (ApiException e)
            {
                Console.WriteLine(e.Message);
                if (e is MoodleErrorException)
                {
                   // TODO: Handle MoodleErrorException exception here
                }
            }
        - lang: go
          label: Go
          source: |-
            ctx := context.Background()

            courseid := 74

            apiResponse, err := coursesApi.GetCourseContents(ctx, courseid)
            if err != nil {
                switch typedErr := err.(type) {
                    case *errors.MoodleError:
                        log.Fatalln("MoodleErrorException: ", typedErr)
                    default:
                        log.Fatalln(err)
                }
            } else {
                // Printing the result and response
                fmt.Println(apiResponse.Data)
                fmt.Println(apiResponse.Response.StatusCode)
            }
        - lang: php
          label: PHP
          source: |-
            $courseid = 74;

            $coursesApi = $client->getCoursesApi();
            $apiResponse = $coursesApi->getCourseContents($courseid);

            // Extracting response status code
            var_dump($apiResponse->getStatusCode());
            // Extracting response headers
            var_dump($apiResponse->getHeaders());

            if ($apiResponse->isSuccess()) {
                echo 'CourseSection[]:';
                var_dump($apiResponse->getResult());
            } else {
                $error = $apiResponse->getResult();
                var_dump($error);
            }
        - lang: ruby
          label: Ruby
          source: |-
            courseid = 74

            result = courses_api.get_course_contents(courseid)

            if result.success?
              puts result.data
            elsif result.error?
              warn result.errors
            end
  /service/core_webservice_get_site_info:
    get:
      operationId: getSiteInfo
      summary: Get your account and site info
      description: |
        Returns your identity (user ID, username, full name, profile picture) and basic site information. Use this to discover your own `userid` — required by other endpoints such as popup notifications (`useridto`).
        Moodle method: `core_webservice_get_site_info`
      tags:
        - Account
      responses:
        "200":
          description: Your account and site information.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SiteInfo"
        "400":
          description: Bad request or Moodle exception.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MoodleError"
      x-codeSamples:
        - lang: typescript
          label: TypeScript
          source: |-
            try {
              const response = await accountApi.getSiteInfo();

              // Extracting fully parsed response body.
              console.log(response.result);

              // Extracting response status code.
              console.log(response.statusCode);
              // Extracting response headers.
              console.log(response.headers);
              // Extracting response body of type `string | Stream`
              console.log(response.body);
            } catch (error) {
              if (error instanceof ApiError) {
                // Extracting response error status code.
                console.log(error.statusCode);
                // Extracting response error headers.
                console.log(error.headers);
                // Extracting response error body of type `string | Stream`.
                console.log(error.body);
                if (error instanceof MoodleError) {
                  console.log(error.result);
                }
              }
            }
        - lang: python
          label: Python
          source: |-
            result = account_api.get_site_info()

            if result.is_success():
                print(result.body)
            elif result.is_error():
                print(result.errors)
        - lang: java
          label: Java
          source: |-
            accountApi.getSiteInfoAsync().thenAccept(result -> {
                // TODO success callback handler
                System.out.println(result);
            }).exceptionally(exception -> {
                Throwable cause = exception.getCause();

                if (cause instanceof MoodleErrorException) {
                    MoodleErrorException moodleErrorException = (MoodleErrorException) cause;
                    moodleErrorException.printStackTrace();
                } else {
                    // fallback for unexpected errors
                    exception.printStackTrace();
                }

                return null;
            });
        - lang: csharp
          label: .NET (C#)
          source: |-
            try
            {
                ApiResponse<SiteInfo> result = await accountApi.GetSiteInfoAsync();
            }
            catch (ApiException e)
            {
                Console.WriteLine(e.Message);
                if (e is MoodleErrorException)
                {
                   // TODO: Handle MoodleErrorException exception here
                }
            }
        - lang: go
          label: Go
          source: |-
            ctx := context.Background()

            apiResponse, err := accountApi.GetSiteInfo(ctx)
            if err != nil {
                switch typedErr := err.(type) {
                    case *errors.MoodleError:
                        log.Fatalln("MoodleErrorException: ", typedErr)
                    default:
                        log.Fatalln(err)
                }
            } else {
                // Printing the result and response
                fmt.Println(apiResponse.Data)
                fmt.Println(apiResponse.Response.StatusCode)
            }
        - lang: php
          label: PHP
          source: |-
            $accountApi = $client->getAccountApi();
            $apiResponse = $accountApi->getSiteInfo();

            // Extracting response status code
            var_dump($apiResponse->getStatusCode());
            // Extracting response headers
            var_dump($apiResponse->getHeaders());

            if ($apiResponse->isSuccess()) {
                echo 'SiteInfo:';
                var_dump($apiResponse->getResult());
            } else {
                $error = $apiResponse->getResult();
                var_dump($error);
            }
        - lang: ruby
          label: Ruby
          source: |-
            result = account_api.get_site_info

            if result.success?
              puts result.data
            elsif result.error?
              warn result.errors
            end
  /service/core_calendar_get_action_events_by_timesort:
    get:
      operationId: getCalendarEventsByTimesort
      summary: Get global calendar action events sorted by time
      description: |
        Returns action events (deadlines) across all enrolled courses, ordered by their sort timestamp. On NUST LMS these are submission due dates for assignments, labs, quizzes, and similar dated activities. Use `timesortfrom` to filter to upcoming deadlines only.
        Moodle method: `core_calendar_get_action_events_by_timesort`
      tags:
        - Calendar
      parameters:
        - name: limitnum
          in: query
          required: true
          description: Maximum number of events to return (e.g. 20 for one page of results).
          schema:
            type: integer
            example: 20
        - name: timesortfrom
          in: query
          required: true
          description: |
            Unix timestamp (seconds since epoch). Only events with a sort time at or after this value are returned. Pass `0` for no lower bound (all upcoming and past events). To see only upcoming deadlines, pass the current epoch time (e.g. the output of `Date.now() / 1000 | 0` in JS or `int(time.time())` in Python).
          schema:
            type: integer
            example: 0
        - name: timesortto
          in: query
          required: false
          description: Only return events with timesort <= this Unix timestamp.
          schema:
            type: integer
        - name: aftereventid
          in: query
          required: false
          description: Return events whose ID is greater than this value (cursor pagination).
          schema:
            type: integer
      responses:
        "200":
          description: Calendar events sorted by timesort.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CalendarEventsResponse"
        "400":
          description: Bad request or Moodle exception.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MoodleError"
      x-codeSamples:
        - lang: typescript
          label: TypeScript
          source: |-
            const limitnum = 20;

            const timesortfrom = 0;

            try {
              const response = await calendarApi.getCalendarEventsByTimesort(
                limitnum,
                timesortfrom
              );

              // Extracting fully parsed response body.
              console.log(response.result);

              // Extracting response status code.
              console.log(response.statusCode);
              // Extracting response headers.
              console.log(response.headers);
              // Extracting response body of type `string | Stream`
              console.log(response.body);
            } catch (error) {
              if (error instanceof ApiError) {
                // Extracting response error status code.
                console.log(error.statusCode);
                // Extracting response error headers.
                console.log(error.headers);
                // Extracting response error body of type `string | Stream`.
                console.log(error.body);
                if (error instanceof MoodleError) {
                  console.log(error.result);
                }
              }
            }
        - lang: python
          label: Python
          source: |-
            limitnum = 20

            timesortfrom = 0

            result = calendar_api.get_calendar_events_by_timesort(
                limitnum,
                timesortfrom
            )

            if result.is_success():
                print(result.body)
            elif result.is_error():
                print(result.errors)
        - lang: java
          label: Java
          source: |-
            int limitnum = 20;
            int timesortfrom = 0;

            calendarApi.getCalendarEventsByTimesortAsync(limitnum, timesortfrom, null, null).thenAccept(result -> {
                // TODO success callback handler
                System.out.println(result);
            }).exceptionally(exception -> {
                Throwable cause = exception.getCause();

                if (cause instanceof MoodleErrorException) {
                    MoodleErrorException moodleErrorException = (MoodleErrorException) cause;
                    moodleErrorException.printStackTrace();
                } else {
                    // fallback for unexpected errors
                    exception.printStackTrace();
                }

                return null;
            });
        - lang: csharp
          label: .NET (C#)
          source: |-
            int limitnum = 20;
            int timesortfrom = 0;
            try
            {
                ApiResponse<CalendarEventsResponse> result = await calendarApi.GetCalendarEventsByTimesortAsync(
                    limitnum,
                    timesortfrom
                );
            }
            catch (ApiException e)
            {
                Console.WriteLine(e.Message);
                if (e is MoodleErrorException)
                {
                   // TODO: Handle MoodleErrorException exception here
                }
            }
        - lang: go
          label: Go
          source: |-
            ctx := context.Background()

            limitnum := 20

            timesortfrom := 0

            apiResponse, err := calendarApi.GetCalendarEventsByTimesort(ctx, limitnum, timesortfrom, nil, nil)
            if err != nil {
                switch typedErr := err.(type) {
                    case *errors.MoodleError:
                        log.Fatalln("MoodleErrorException: ", typedErr)
                    default:
                        log.Fatalln(err)
                }
            } else {
                // Printing the result and response
                fmt.Println(apiResponse.Data)
                fmt.Println(apiResponse.Response.StatusCode)
            }
        - lang: php
          label: PHP
          source: |-
            $limitnum = 20;

            $timesortfrom = 0;

            $calendarApi = $client->getCalendarApi();
            $apiResponse = $calendarApi->getCalendarEventsByTimesort(
                $limitnum,
                $timesortfrom
            );

            // Extracting response status code
            var_dump($apiResponse->getStatusCode());
            // Extracting response headers
            var_dump($apiResponse->getHeaders());

            if ($apiResponse->isSuccess()) {
                echo 'CalendarEventsResponse:';
                var_dump($apiResponse->getResult());
            } else {
                $error = $apiResponse->getResult();
                var_dump($error);
            }
        - lang: ruby
          label: Ruby
          source: |-
            limitnum = 20

            timesortfrom = 0

            result = calendar_api.get_calendar_events_by_timesort(
              limitnum,
              timesortfrom
            )

            if result.success?
              puts result.data
            elsif result.error?
              warn result.errors
            end
  /service/core_calendar_get_action_events_by_course:
    get:
      operationId: getCalendarEventsByCourse
      summary: Get calendar action events for a specific course
      description: |
        Returns all action events (deadlines) for a single course — assignment, lab, and quiz submission due dates, and other dated activities.
        Moodle method: `core_calendar_get_action_events_by_course`
      tags:
        - Calendar
      parameters:
        - name: courseid
          in: query
          required: true
          description: ID of the course to fetch events for.
          schema:
            type: integer
        - name: timesortfrom
          in: query
          required: false
          description: Only return events with timesort >= this Unix timestamp.
          schema:
            type: integer
        - name: timesortto
          in: query
          required: false
          description: Only return events with timesort <= this Unix timestamp.
          schema:
            type: integer
        - name: aftereventid
          in: query
          required: false
          description: Cursor-based pagination — return events after this event ID.
          schema:
            type: integer
        - name: limitnum
          in: query
          required: false
          description: Maximum number of events to return.
          schema:
            type: integer
      responses:
        "200":
          description: Calendar events for the specified course.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CalendarEventsResponse"
        "400":
          description: Bad request or Moodle exception.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MoodleError"
      x-codeSamples:
        - lang: typescript
          label: TypeScript
          source: |-
            const courseid = 74;

            try {
              const response = await calendarApi.getCalendarEventsByCourse(courseid);

              // Extracting fully parsed response body.
              console.log(response.result);

              // Extracting response status code.
              console.log(response.statusCode);
              // Extracting response headers.
              console.log(response.headers);
              // Extracting response body of type `string | Stream`
              console.log(response.body);
            } catch (error) {
              if (error instanceof ApiError) {
                // Extracting response error status code.
                console.log(error.statusCode);
                // Extracting response error headers.
                console.log(error.headers);
                // Extracting response error body of type `string | Stream`.
                console.log(error.body);
                if (error instanceof MoodleError) {
                  console.log(error.result);
                }
              }
            }
        - lang: python
          label: Python
          source: |-
            courseid = 74

            result = calendar_api.get_calendar_events_by_course(courseid)

            if result.is_success():
                print(result.body)
            elif result.is_error():
                print(result.errors)
        - lang: java
          label: Java
          source: |-
            int courseid = 74;

            calendarApi.getCalendarEventsByCourseAsync(courseid, null, null, null, null).thenAccept(result -> {
                // TODO success callback handler
                System.out.println(result);
            }).exceptionally(exception -> {
                Throwable cause = exception.getCause();

                if (cause instanceof MoodleErrorException) {
                    MoodleErrorException moodleErrorException = (MoodleErrorException) cause;
                    moodleErrorException.printStackTrace();
                } else {
                    // fallback for unexpected errors
                    exception.printStackTrace();
                }

                return null;
            });
        - lang: csharp
          label: .NET (C#)
          source: |-
            int courseid = 74;
            try
            {
                ApiResponse<CalendarEventsResponse> result = await calendarApi.GetCalendarEventsByCourseAsync(courseid);
            }
            catch (ApiException e)
            {
                Console.WriteLine(e.Message);
                if (e is MoodleErrorException)
                {
                   // TODO: Handle MoodleErrorException exception here
                }
            }
        - lang: go
          label: Go
          source: |-
            ctx := context.Background()

            courseid := 74

            apiResponse, err := calendarApi.GetCalendarEventsByCourse(ctx, courseid, nil, nil, nil, nil)
            if err != nil {
                switch typedErr := err.(type) {
                    case *errors.MoodleError:
                        log.Fatalln("MoodleErrorException: ", typedErr)
                    default:
                        log.Fatalln(err)
                }
            } else {
                // Printing the result and response
                fmt.Println(apiResponse.Data)
                fmt.Println(apiResponse.Response.StatusCode)
            }
        - lang: php
          label: PHP
          source: |-
            $courseid = 74;

            $calendarApi = $client->getCalendarApi();
            $apiResponse = $calendarApi->getCalendarEventsByCourse($courseid);

            // Extracting response status code
            var_dump($apiResponse->getStatusCode());
            // Extracting response headers
            var_dump($apiResponse->getHeaders());

            if ($apiResponse->isSuccess()) {
                echo 'CalendarEventsResponse:';
                var_dump($apiResponse->getResult());
            } else {
                $error = $apiResponse->getResult();
                var_dump($error);
            }
        - lang: ruby
          label: Ruby
          source: |-
            courseid = 74

            result = calendar_api.get_calendar_events_by_course(courseid)

            if result.success?
              puts result.data
            elsif result.error?
              warn result.errors
            end
  /service/message_popup_get_popup_notifications:
    get:
      operationId: getPopupNotifications
      summary: Get popup notifications for a user
      description: |
        Returns the most recent popup notifications sent to a user, with support for pagination. Also returns the total count of unread notifications.
        Moodle method: `message_popup_get_popup_notifications`
      tags:
        - Notifications
      parameters:
        - name: useridto
          in: query
          required: true
          description: |
            ID of the recipient user (yourself), passed as a string. Get your numeric user ID from `GET /service/core_webservice_get_site_info`.
          schema:
            type: string
        - name: limit
          in: query
          required: true
          description: Maximum number of notifications to return.
          schema:
            type: integer
        - name: offset
          in: query
          required: true
          description: Pagination offset.
          schema:
            type: integer
            default: 0
      responses:
        "200":
          description: Popup notifications and total unread count.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PopupNotificationsResponse"
        "400":
          description: Bad request or Moodle exception.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MoodleError"
      x-codeSamples:
        - lang: typescript
          label: TypeScript
          source: |-
            const useridto = 'useridto2';

            const limit = 172;

            const offset = 0;

            try {
              const response = await notificationsApi.getPopupNotifications(
                useridto,
                limit,
                offset
              );

              // Extracting fully parsed response body.
              console.log(response.result);

              // Extracting response status code.
              console.log(response.statusCode);
              // Extracting response headers.
              console.log(response.headers);
              // Extracting response body of type `string | Stream`
              console.log(response.body);
            } catch (error) {
              if (error instanceof ApiError) {
                // Extracting response error status code.
                console.log(error.statusCode);
                // Extracting response error headers.
                console.log(error.headers);
                // Extracting response error body of type `string | Stream`.
                console.log(error.body);
                if (error instanceof MoodleError) {
                  console.log(error.result);
                }
              }
            }
        - lang: python
          label: Python
          source: |-
            useridto = 'useridto2'

            limit = 172

            offset = 0

            result = notifications_api.get_popup_notifications(
                useridto,
                limit,
                offset
            )

            if result.is_success():
                print(result.body)
            elif result.is_error():
                print(result.errors)
        - lang: java
          label: Java
          source: |-
            String useridto = "useridto2";
            int limit = 172;
            int offset = 0;

            notificationsApi.getPopupNotificationsAsync(useridto, limit, offset).thenAccept(result -> {
                // TODO success callback handler
                System.out.println(result);
            }).exceptionally(exception -> {
                Throwable cause = exception.getCause();

                if (cause instanceof MoodleErrorException) {
                    MoodleErrorException moodleErrorException = (MoodleErrorException) cause;
                    moodleErrorException.printStackTrace();
                } else {
                    // fallback for unexpected errors
                    exception.printStackTrace();
                }

                return null;
            });
        - lang: csharp
          label: .NET (C#)
          source: |-
            string useridto = "useridto2";
            int limit = 172;
            int offset = 0;
            try
            {
                ApiResponse<PopupNotificationsResponse> result = await notificationsApi.GetPopupNotificationsAsync(
                    useridto,
                    limit,
                    offset
                );
            }
            catch (ApiException e)
            {
                Console.WriteLine(e.Message);
                if (e is MoodleErrorException)
                {
                   // TODO: Handle MoodleErrorException exception here
                }
            }
        - lang: go
          label: Go
          source: |-
            ctx := context.Background()

            useridto := "useridto2"

            limit := 172

            offset := 0

            apiResponse, err := notificationsApi.GetPopupNotifications(ctx, useridto, limit, offset)
            if err != nil {
                switch typedErr := err.(type) {
                    case *errors.MoodleError:
                        log.Fatalln("MoodleErrorException: ", typedErr)
                    default:
                        log.Fatalln(err)
                }
            } else {
                // Printing the result and response
                fmt.Println(apiResponse.Data)
                fmt.Println(apiResponse.Response.StatusCode)
            }
        - lang: php
          label: PHP
          source: |-
            $useridto = 'useridto2';

            $limit = 172;

            $offset = 0;

            $notificationsApi = $client->getNotificationsApi();
            $apiResponse = $notificationsApi->getPopupNotifications(
                $useridto,
                $limit,
                $offset
            );

            // Extracting response status code
            var_dump($apiResponse->getStatusCode());
            // Extracting response headers
            var_dump($apiResponse->getHeaders());

            if ($apiResponse->isSuccess()) {
                echo 'PopupNotificationsResponse:';
                var_dump($apiResponse->getResult());
            } else {
                $error = $apiResponse->getResult();
                var_dump($error);
            }
        - lang: ruby
          label: Ruby
          source: |-
            useridto = 'useridto2'

            limit = 172

            offset = 0

            result = notifications_api.get_popup_notifications(
              useridto,
              limit,
              offset
            )

            if result.success?
              puts result.data
            elsif result.error?
              warn result.errors
            end
  /sdk/initialize-client:
    get:
      operationId: initializeSdkClient
      summary: Initialize the SDK client
      tags:
        - SDK Setup
      security: []
      description: Setup reference (not a live endpoint). After installing an SDK and getting a token from `POST /auth/login`, initialize a client with that token — every other code sample assumes this `client`.
      x-codeSamples:
        - lang: typescript
          label: TypeScript
          source: |-
            import { Client } from 'nust-lms-apilib';

            const client = new Client({
              bearerAuthCredentials: {
                accessToken: 'YOUR_BEARER_TOKEN'
              },
            });
        - lang: python
          label: Python
          source: |-
            from nustlmsapi.http.auth.oauth_2 import BearerAuthCredentials
            from nustlmsapi.nustlmsapi_client import NustlmsapiClient

            client = NustlmsapiClient(
                bearer_auth_credentials=BearerAuthCredentials(
                    access_token='YOUR_BEARER_TOKEN'
                )
            )
        - lang: java
          label: Java
          source: |-
            import m18000.m0.m0.m127.NustLmsApiClient;
            import m18000.m0.m0.m127.authentication.BearerAuthModel;

            public class Program {
                public static void main(String[] args) {
                    NustLmsApiClient client = new NustLmsApiClient.Builder()
                        .bearerAuthCredentials(new BearerAuthModel.Builder(
                                "YOUR_BEARER_TOKEN"
                            )
                            .build())
                        .build();
                }
            }
        - lang: csharp
          label: .NET (C#)
          source: |-
            using NustLmsApi.Standard;
            using NustLmsApi.Standard.Authentication;

            namespace ConsoleApp;

            NustLmsApiClient client = new NustLmsApiClient.Builder()
                .BearerAuthCredentials(
                    new BearerAuthModel.Builder(
                        "YOUR_BEARER_TOKEN"
                    )
                    .Build())
                .Build();
        - lang: go
          label: Go
          source: |-
            package main

            import (
                "nustLmsApi"
            )

            func main() {
                client := nustLmsApi.NewClient(
                nustLmsApi.CreateConfiguration(
                        nustLmsApi.WithBearerAuthCredentials(
                            nustLmsApi.NewBearerAuthCredentials("YOUR_BEARER_TOKEN"),
                        ),
                    ),
                )
            }
        - lang: php
          label: PHP
          source: |-
            use NustLmsApiLib\Authentication\BearerAuthCredentialsBuilder;
            use NustLmsApiLib\NustLmsApiClientBuilder;

            $client = NustLmsApiClientBuilder::init()
                ->bearerAuthCredentials(
                    BearerAuthCredentialsBuilder::init(
                        'YOUR_BEARER_TOKEN'
                    )
                )
                ->build();
        - lang: ruby
          label: Ruby
          source: |-
            require 'nust_lms_api'
            include NustLmsApi

            client = Client.new(
              bearer_auth_credentials: BearerAuthCredentials.new(
                access_token: 'YOUR_BEARER_TOKEN'
              )
            )
      responses: {}
