openapi: 3.0.3
info:
  title: MyTimetable API
  version: '0.8'
  contact:
    name: Eveoh
    url: 'https://developer.eveoh.nl'
    email: support@eveoh.nl
  description: |-
    # Introduction
    The MyTimeTable API allows you to retrieve timetables and alter user's profiles. Most of the data in MyTimetable can be accessed using the API, and the possibilities are expanded continuously. The API is based on REST principles. Requests can be done using the various available HTTP verbs (`GET`, `POST`, `PUT` and `DELETE`).

    The server URL depends on the domain name of the MyTimetable application instance.

    Not all MyTimetable instances have enabled API access. Some customers choose to enable API access only for certain trusted applications. Please contact us if you have questions about the API or if you would like to receive an access token for a certain API.
    ## API versions
    The API uses a version numbering scheme. The version number is included in the API base URL. It guarantees that in that version, no breaking changes will be introduced (this only applies to *documented* endpoints and attributes). MyTimetable may support multiple API versions at the same time. Eveoh will try to support older API versions when technically and economically feasible, but users are encouraged to always use the latest API version.
    # Authentication
    Depending on the wishes of the institution, the MyTimetable API can require several forms of authentication and authorisation.

    First of all, it can be necessary for the client application to provide some form of authentication. This makes sure only authorised applications can access the API data. This authorisation is usually done using an API token. Next to the client authentication, sometimes the client application wants to access the personal data of a user. The user can either provide authorise the application to access this data, using OAuth, or the client can use a special API token with elevation privileges. Some MyTimetable environment only allow API access for requests that can be linked to a real user. In these cases an OAuth token is always necessary.

    In the requests below we have not included the authorisation information (like the `access_token` query parameter or the `apiToken` header).

    <security-definitions />

    # Localisation
    Data can be available in multiple languages. Use the `Accept-Language` HTTP header to specify the locale, for example `nl-NL`. When the specified locale is not available, the default locale will be used.

    # Date formats
    Dates and times are returned as [Unix timestamp](https://en.wikipedia.org/wiki/Unix_time) (in milliseconds, instead of the default seconds). 

    When specifying date/time parameters, the following formats are supported:
    - [ISO 8601 format](https://en.wikipedia.org/wiki/ISO_8601) (`yyyy-MM-ddTHH:mm:ss±HH:mm`): elements on the right side (time, time zone offset) are optional;
    - [Unix timestamp format](https://en.wikipedia.org/wiki/Unix_time) (in milliseconds sinds 1970, so don't forget to multiply/divide by 1000);
    - 'today' or 'tomorrow' for the current or next day at 0:00;
    - Legacy format (`yyyy/MM/dd HH:mm`): the time is optional.
    # Recommendations
    Please keep some things in mind when using the API:
    - The API-token is a secret, and should only be used in back-end services.
      Do not include it in your end-user application.

    - Enable GZIP compression in your API library. Support for non-compressed responses may be dropped in the future.
    - Make sure your client supports TLS v1.2, older versions may not be available.
    - Do not cache data for long periods of time (or at all), but do make sure end-users cannot trigger useless API requests (e.g., cache while the user is in the same view, and do not let the user refresh 100's of times by simply spamming a button).
    - The schema may change as fields may be added. Be sure to ignore unknown fields in your data mapper.
    - Do not 'scrape' the API and store data locally.
      It causes a high load and stale data.

    - Do not perform unnecessarily large requests or a large number of requests.
      E.g., if you want to show the upcoming 5 activities of a location, just request the upcoming 5 activities and not the timetable for the whole year.
      Also, do not refresh that view every minute, as the timetable will not change every minute.

    # Changes since v0.7
    - The endpoints `/weeklabelmaps` and `/weeklabelmaps/{key}` have been removed and a new `/weeklabels` endpoint has been created.
      MyTimetable no longer supports multiple week label maps. The `/weeklabels` endpoint offers a single list of all
      defined week labels.
    - The attribute `physical` of `Event` has been renamed to `onLocation`.
servers:
  - url: '{protocol}://{hostname}:{port}/api/v0.8'
    variables:
      protocol:
        enum:
          - http
          - https
        default: http
      hostname:
        default: localhost
      port:
        default: '8080'
tags:
  - name: Timetable sources
    description: |
      Multiple timetable sources with timetabling data may be available (e.g. one for every year).
      By specifying a query parameter, it is possible to select a certain timetable source for the request in certain requests.
      The list of possible timetable sources can be retrieved using the [GET /databasedetails](#operation/get-timetable-sources) endpoint.
      If no timetable source is specified when retrieving timetables, the default source will be used, which is usually the most current and sensible option.
  - name: Timetables
  - name: Terms
  - name: Week labels
  - name: User
  - name: Messages
paths:
  /databasedetails:
    get:
      operationId: get-timetable-sources
      summary: List timetable sources
      description: |
        Query the available timetable sources.
        The ID (to be used in the query string of other calls) and the label are returned.

        See [Timetable sources](#section/Timetable-sources) for more information.
      security:
        - Token: []
        - OAuth:
            - profile_read
        - OAuth:
            - alltimetables
      tags:
        - Timetable sources
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  databases:
                    type: array
                    items:
                      $ref: '#/components/schemas/TimetableSource'
                description: Available timetable sources
  /timetabletypesdetails:
    get:
      operationId: get-timetable-types
      summary: List timetable types
      description: |
        Query all possible timetable types and return them including some details regards naming, whether or not they can include child timetables and their ordering in a user interface.
      security:
        - Token: []
        - OAuth:
            - profile_read
        - OAuth:
            - alltimetables
      tags:
        - Timetables
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  timetableTypes:
                    type: array
                    items:
                      $ref: '#/components/schemas/TimetableType'
                    description: Available timetable types
  /timetablefilters:
    get:
      operationId: get-timetable-filters
      summary: List timetable filters for a timetable type
      description: |
        Query all timetable filters types and their available options available for a specific timetable type.
        Using the results it is possible to filter the output of [this endpoint itself](#operation/get-timetable-filters) and of the [GET /timetables](#operation/get-timetables) endpoint.
      security:
        - Token: []
        - OAuth:
            - profile_read
        - OAuth:
            - alltimetables
      tags:
        - Timetables
      parameters:
        - name: type
          in: query
          schema:
            type: string
          required: true
          description: Name (ID) of the timetable type to retrieve the filter types and filter options for.
          example: module
        - name: exampleFilter
          in: query
          schema:
            type: string
          description: |
            Filters the filter values using the timetable filter type with the name 'example'.
            The value should be a timetable filter option ID that is can be acquired from an earlier call to [this same endpoint](#operation/get-timetable-filters).

            Adjust the parameter name to the timetable filter name to use.
            If the filter type name is `department`, the parameter name is `departmentFilter`.
            You can also combine multiple parameters for multiple timetable filter types.
          example: 3772C4D1BFA1033EDD5E0539C89DD333
        - name: d
          in: query
          schema:
            type: string
          description: |
            Data source to search in.
            By default, the data source with the highest priority is used, which is usually the most current database.
          example: TimetableDB
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  filterattribute:
                    type: array
                    items:
                      $ref: '#/components/schemas/TimetableFilterType'
  /timetables:
    get:
      operationId: get-timetables
      summary: List timetables
      description: |
        Query the available timetables of a specified type.
        The filters that can be specified can be retrieved using the [GET /timetablefilters](#operation/get-timetable-filters) endpoint.
        The identifiers can be used in subsequent calls to the [/timetables/{key}](#operation/get-timetable-events) and [/subscriptions/{key}](](#operation/get-subscription) endpoints.
      security:
        - Token: []
        - OAuth:
            - alltimetables
      tags:
        - Timetables
      parameters:
        - name: type
          in: query
          schema:
            type: string
          required: true
          description: Type of the timetables
          example: module
        - name: limit
          in: query
          schema:
            type: integer
          description: Maximum number of timetables returned
          example: 100
        - name: offset
          in: query
          schema:
            type: integer
          description: Starting offset of the timetables returned (e.g. `5` skips the first 5 records)
          example: 5
        - name: exampleFilter
          in: query
          schema:
            type: string
          description: |
            Filters the timetables using the timetable filter type with the name 'example'.
            The value should be a timetable filter option ID that is can be acquired from the list of available timetable filter options.

            Adjust the parameter name to the timetable filter name to use.
            If the filter type name as returned by the [GET /timetablefilters](#operation/get-timetable-filters) endpoint is `department`, the parameter name is `departmentFilter`.
            You can also combine multiple parameters for multiple timetable filter types.
          example: 3772C4D1BFA1033EDD5E0539C89DD333
        - name: q
          in: query
          schema:
            type: string
          description: Search string to filter results
          example: Informatics
        - name: d
          in: query
          schema:
            type: string
          description: |
            Data source to search in.
            By default, the data source with the highest priority is used, which is usually the most current database.
          example: TimetableDB
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Timetable'
  '/timetables/{key}':
    get:
      operationId: get-timetable-events
      summary: List events of a timetable
      description: |
        Get all events of the specified timetable.
      security:
        - Token: []
        - OAuth:
            - alltimetables
      tags:
        - Timetables
      parameters:
        - name: key
          in: path
          schema:
            type: string
          required: true
          description: Timetable ID of the timetable.
          example: 2011!pos!49E8C5057B344E02604A712CBD432F01
        - name: fetchBy
          in: query
          schema:
            type: string
            enum:
              - id
              - hostKey
            default: id
          description: |
            Use `hostKey` to retrieve the events by its timetable's host key instead of its timetable's ID.
          example: hostKey
        - name: type
          in: query
          schema:
            type: string
          description: |
            The type of the timetable, only used in combination with `fetchBy=hostKey`. See [GET /timetabletypesdetails](#operation/get-timetable-types).
          example: module
        - name: startDate
          in: query
          schema:
            type: string
          description: |
            The start date to retrieve events from, or `today` for the current date at 0:00, or `tomorrow` for tomorrow at 0:00, or none for the beginning of times.
            See [Date formats](#section/Date-formats).
          example: '2000-01-01T00:00:00Z'
        - name: endDate
          in: query
          schema:
            type: string
          description: |
            The end date to retrieve events until, or `today` for the current date at 0:00, or `tomorrow` for tomorrow at 0:00, or none for the end of times.
            See [Date formats](#section/Date-formats).
          example: '2001-01-01T00:00:00Z'
        - name: limit
          in: query
          schema:
            type: integer
          description: 'The maximum amount of events returned, 0 for no limit.'
          example: 100
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Event'
        '404':
          description: Timetable does not exist
  '/timetables/{key}/options':
    get:
      operationId: get-timetable-options
      summary: List timetable options of a timetable
      description: |
        Get all timetable options of the specified timetable.

        These options can be selected on a timetable subscription for this timetable using the [PUT /subscriptions/{key}/options](#operation/set-timetable-subscription-options) endpoint.
      security:
        - Token: []
        - OAuth:
            - alltimetables
      tags:
        - Timetables
      parameters:
        - name: key
          in: path
          schema:
            type: string
          required: true
          description: |
            Timetable ID of the timetable.

            Available timetables can be retrieved using the [GET /timetables](#operation/get-timetables) endpoint.
          example: 2011!pos!49E8C5057B344E02604A712CBD432F01
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  allEquivalent:
                    type: boolean
                    description: |
                      Any choice of options results in the same timetable.
                      So timetable option selection is irrelevant in this situation.
                  options:
                    type: array
                    description: Timetable options of the timetable.
                    items:
                      $ref: '#/components/schemas/TimetableOption'
        '404':
          description: Timetable does not exist
  '/timetables/{parent}/{key}/options':
    get:
      operationId: get-child-timetable-options
      summary: List timetable options of a child timetable
      description: |
        Get all timetable options of the specified timetable.

        These options can be selected on a child timetable subscription for this timetable using the [PUT /subscriptions/{key}/{parent}/options](#operation/set-child-timetable-subscription-options) endpoint.
      security:
        - Token: []
        - OAuth:
            - alltimetables
      tags:
        - Timetables
      parameters:
        - name: parent
          in: path
          schema:
            type: string
          required: true
          description: |
            Timetable ID of the timetable.
          example: 2011!pos!49E8C5057B344E02604A712CBD432F01
        - name: key
          in: path
          schema:
            type: string
          required: true
          description: |
            Child timetable ID of the child timetable.
          example: Child!49CBD432F01E8C5057B344E02604A711
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  allEquivalent:
                    type: boolean
                    description: |
                      Any choice of options results in the same timetable.
                      So timetable option selection is irrelevant in this situation.
                  options:
                    type: array
                    description: Timetable options of the child timetable.
                    items:
                      $ref: '#/components/schemas/TimetableOption'
        '404':
          description: Timetable or child timetable does not exist
  /terms:
    get:
      operationId: get-terms
      summary: List terms
      description: |
        Query the available terms.
        A term represents academic periods (e.g. '2015, Semester 1') and consists of one or multiple date ranges internally.
      security:
        - Token: []
        - OAuth:
            - profile_read
        - OAuth:
            - alltimetables
      tags:
        - Terms
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  terms:
                    type: array
                    items:
                      $ref: '#/components/schemas/Term'
                    description: Available terms
  /weeklabels:
    get:
      operationId: get-week-labels
      summary: Get week labels
      description: |
        Query all available week labels.

        Returns a list containing week labels. If there are no week labels defined, an empty list will be returned.
      security:
        - Token: []
        - OAuth:
            - profile_read
        - OAuth:
            - alltimetables
      tags:
        - Week labels
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WeekLabels'
              example:
                - year: 2022
                  week: 4
                  description: S1 Week 2
                - year: 2022
                  week: 5
                  description: S1 Week 3
  /user:
    get:
      operationId: get-user
      summary: Get user
      description: |
        Query details of a user.
      security:
        - Token: []
          RequestedAuth: []
        - OAuth:
            - username
        - OAuth:
            - user_read
      tags:
        - User
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
  /timetable:
    get:
      operationId: get-schedule
      summary: List events in schedule
      description: |
        Get the events in the schedule of the current user (as identified by the OAuth token or `requestedAuth` header).
      security:
        - Token: []
          RequestedAuth: []
        - OAuth:
            - profile_read
      tags:
        - User
      parameters:
        - name: startDate
          in: query
          schema:
            type: string
          description: |
            The start date to retrieve events from, or `today` for the current date at 0:00, or `tomorrow` for tomorrow at 0:00, or none for the beginning of times.
            See [Date formats](#section/Date-formats).
          example: '2000-01-01T00:00:00Z'
        - name: endDate
          in: query
          schema:
            type: string
          description: |
            The end date to retrieve events until, or `today` for the current date at 0:00, or `tomorrow` for tomorrow at 0:00, or none for the end of times.
            See [Date formats](#section/Date-formats).
          example: '2001-01-01T00:00:00Z'
        - name: limit
          in: query
          schema:
            type: integer
            default: 0
          description: 'Maximum amount of events returned, 0 for no limit.'
          example: 100
        - name: type
          in: query
          schema:
            type: array
            items:
              type: string
          description: |
            Specifies the timetable type of the subscriptions to include events from in the schedule.
            This parameter can be specified multiple times.
            If not specified, events from all subscriptions will be included.
          example:
            - module
        - name: excludeResourceTimetables
          in: query
          schema:
            type: boolean
            default: false
          description: |
            Set this to `true` to exclude any resource (location, zone, equipment) timetables.
            Generally, you'll want this when displaying the personal schedule of a user, for example in portal integrations.
          example: false
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Event'
  /subscriptions:
    get:
      operationId: get-subscriptions
      summary: Get timetable subscriptions
      description: |
        Retrieve all timetable subscriptions of the current user (as identified by the OAuth token or `requestedAuth` header).
      security:
        - Token: []
          RequestedAuth: []
        - OAuth:
            - profile_read
      tags:
        - User
      parameters:
        - name: type
          in: query
          schema:
            type: array
            items:
              type: string
          description: |
            Specifies the timetable type of the subscriptions to include.
            This parameter can be specified multiple times.
            If not specified all subscriptions will be included in the result.
          example:
            - module
        - name: excludeResourceTimetables
          in: query
          schema:
            type: boolean
            default: false
          description: |
            Exclude subscriptions to resource timetables (e.g. rooms, buildings, equipment).
            Generally, you will want this when you're interested in the personal timetable, for example when when creating a DLE portal integration.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/TimetableSubscription'
  '/subscriptions/{key}':
    post:
      operationId: create-timetable-subscription
      summary: Create timetable subscription
      description: |
        Create a new timetable subscription for the current user (as identified by the OAuth token or `requestedAuth` header).
      security:
        - Token: []
          RequestedAuth: []
        - OAuth:
            - profile_write
      tags:
        - User
      parameters:
        - name: key
          in: path
          schema:
            type: string
          required: true
          description: ID of the timetable to subscribe to.
          example: 2011!module!49CBD432F01E8C5057B344E02604A711
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              properties:
                option:
                  type: array
                  items:
                    type: string
                  default: []
                  description: |
                    The ID of a timetable option to select.

                    Can be specified multiple times to select multiple options, or be omitted to select all.

                    The [GET /timetables/{key}/options](#operation/get-timetable-options) endpoint can be used to get the available options.
      responses:
        '204':
          description: OK
        '400':
          description: Timetable subscription already exists
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/SubscriptionAlreadyExistsError'
                discriminator:
                  propertyName: errorType
                  mapping:
                    subscription_already_exists: '#/components/schemas/SubscriptionAlreadyExistsError'
    put:
      operationId: update-timetable-subscription
      summary: Update timetable subscription
      description: |
        Update a timetable subscription of the current user (as identified by the OAuth token or `requestedAuth` header).
      security:
        - Token: []
          RequestedAuth: []
        - OAuth:
            - profile_read
      tags:
        - User
      parameters:
        - name: key
          in: path
          schema:
            type: string
          required: true
          description: Timetable ID of the timetable subscription that should be updated.
          example: 2011!module!49CBD432F01E8C5057B344E02604A711
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              properties:
                state:
                  type: boolean
                  description: |
                    The visibility state of the timetable's events in the user interface.
                    Depending on the scenario, the user can toggle this visibility in the UI.
              required:
                - state
      responses:
        '204':
          description: OK
        '400':
          description: Refused
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/SubscriptionChangeNotAllowedError'
                  - $ref: '#/components/schemas/TooManySubscriptionsEnabledError'
                discriminator:
                  propertyName: errorType
                  mapping:
                    subscription_change_not_allowed: '#/components/schemas/SubscriptionChangeNotAllowedError'
                    too_many_subscriptions_enabled: '#/components/schemas/TooManySubscriptionsEnabledError'
    delete:
      operationId: delete-timetable-subscription
      summary: Delete timetable subscription
      description: |
        Delete a timetable subscription of the current user (as identified by the OAuth token or `requestedAuth` header).
      security:
        - Token: []
          RequestedAuth: []
        - OAuth:
            - profile_read
      tags:
        - User
      parameters:
        - name: key
          in: path
          schema:
            type: string
          required: true
          description: Timetable ID of the timetable subscription that should be deleted.
          example: 2011!module!49CBD432F01E8C5057B344E02604A711
      responses:
        '204':
          description: OK
  '/subscriptions/{key}/options':
    put:
      operationId: set-timetable-subscription-options
      summary: Set selected options of timetable subscription
      description: |
        Set the selected options of a timetable subscription of the current user (as identified by the OAuth token or `requestedAuth` header).
      security:
        - Token: []
          RequestedAuth: []
        - OAuth:
            - profile_read
      tags:
        - User
      parameters:
        - name: key
          in: path
          schema:
            type: string
          required: true
          description: Timetable ID of the timetable subscription that should be updated.
          example: 2011!module!49CBD432F01E8C5057B344E02604A711
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              properties:
                option:
                  type: array
                  items:
                    type: string
                  minItems: 1
                  description: |
                    The ID of a timetable option to select.

                    Can be specified multiple times to select multiple options.
                    Please note that specifying all possible options will cause the selection to be cleared.

                    The [GET /timetables/{key}/options](#operation/get-timetable-options) endpoint can be used to get the available options.
              required:
                - option
      responses:
        '204':
          description: OK
    delete:
      operationId: clear-timetable-subscription-options
      summary: Clear selected options of timetable subscription
      description: |
        Clear the selected options of a timetable subscription of the current user (as identified by the OAuth token or `requestedAuth` header).
        This will cause all activities of the timetable to be shown to the user.
      security:
        - Token: []
          RequestedAuth: []
        - OAuth:
            - profile_read
      tags:
        - User
      parameters:
        - name: key
          in: path
          schema:
            type: string
          required: true
          description: Timetable ID of the timetable subscription that should be updated.
          example: 2011!module!49CBD432F01E8C5057B344E02604A711
      responses:
        '204':
          description: OK
  '/subscriptions/{parent}/{key}':
    put:
      operationId: update-child-timetable-subscription
      summary: Update child timetable subscription
      description: |
        Update a child timetable subscription of the current user (as identified by the OAuth token or `requestedAuth` header).
      security:
        - Token: []
          RequestedAuth: []
        - OAuth:
            - profile_read
      tags:
        - User
      parameters:
        - name: parent
          in: path
          schema:
            type: string
          required: true
          description: Timetable ID of the timetable subscription that should be updated.
          example: 2011!pos!49E8C5057B344E02604A712CBD432F01
        - name: key
          in: path
          schema:
            type: string
          required: true
          description: Child timetable ID of the child timetable subscription that should be updated.
          example: Child!49CBD432F01E8C5057B344E02604A711
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              properties:
                state:
                  type: boolean
                  description: |
                    The visibility state of the child timetable's events in the user interface.
                    Depending on the scenario, the user can toggle this visibility in the UI.
              required:
                - state
      responses:
        '204':
          description: OK
  '/subscriptions/{parent}/{key}/options':
    put:
      operationId: set-child-timetable-subscription-options
      summary: Set selected options of child timetable subscription
      description: |
        Set the selected options of a child timetable subscription of the current user (as identified by the OAuth token or `requestedAuth` header).
      security:
        - Token: []
          RequestedAuth: []
        - OAuth:
            - profile_read
      tags:
        - User
      parameters:
        - name: parent
          in: path
          schema:
            type: string
          required: true
          description: Timetable ID of the timetable subscription that should be updated.
          example: 2011!pos!49E8C5057B344E02604A712CBD432F01
        - name: key
          in: path
          schema:
            type: string
          required: true
          description: Child timetable ID of the child timetable subscription that should be updated.
          example: Child!49CBD432F01E8C5057B344E02604A711
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              properties:
                option:
                  type: array
                  items:
                    type: string
                  minItems: 1
                  description: |
                    The ID of a timetable option to select.

                    Can be specified multiple times to select multiple options.
                    Please note that specifying all possible options will cause the selection to be cleared.

                    The [GET /timetables/{key}/{parent}/options](#operation/get-child-timetable-options) endpoint can be used to get the available timetable options.
              required:
                - option
      responses:
        '204':
          description: OK
    delete:
      operationId: clear-child-timetable-subscription-options
      summary: Clear selected options of child timetable subscription
      description: |
        Clear the selected options of a child timetable subscription of the current user (as identified by the OAuth token or `requestedAuth` header).
        This will cause all activities of the child timetable to be shown to the user.
      security:
        - Token: []
          RequestedAuth: []
        - OAuth:
            - profile_read
      tags:
        - User
      parameters:
        - name: parent
          in: path
          schema:
            type: string
          required: true
          description: Timetable ID of the timetable subscription that should be updated.
          example: 2011!pos!49E8C5057B344E02604A712CBD432F01
        - name: key
          in: path
          schema:
            type: string
          required: true
          description: Child timetable ID of the child timetable subscription that should be updated.
          example: Child!49CBD432F01E8C5057B344E02604A711
      responses:
        '204':
          description: OK
  /eventtypegroups:
    get:
      operationId: get-event-type-groups
      summary: Get event type group filter
      description: |
        Query the event type groups and event type groups filtering settings of the current user.
      security:
        - Token: []
        - OAuth:
            - alltimetables
      tags:
        - User
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  filteringEnabled:
                    type: boolean
                    description: Event type group filtering is available.
                  eventtypegroups:
                    type: array
                    items:
                      type: object
                      description: Event type group
                      properties:
                        id:
                          type: string
                          description: ID
                          example: LECTURE
                        description:
                          type: string
                          description: Human-readable name
                          example: Lecture
                        isFilteredByDefault:
                          type: boolean
                          nullable: true
                          description: |
                            The event type group is configured to be filtered by default.

                            This property will only be present when authenticated using an elevated API token or with OAuth scope `profile_read`.
                        isFiltered:
                          type: boolean
                          nullable: true
                          description: |
                            The event type group is filtered by the current user when displaying the schedule in the user interface.

                            This property will only be present when authenticated using an elevated API token or with OAuth scope `profile_read`.
                        isFilteredForSync:
                          type: boolean
                          nullable: true
                          description: |
                            The event type group is filtered by the current user when sychronizing timetables with external calendars.
                            The user also doesn't receive notifications for this event type group.

                            This property will only be present when authenticated using an elevated API token or with OAuth scope `profile_read`.
                    description: Available event type groups and their filtering settings.
    patch:
      operationId: set-event-type-group-filter
      summary: Set event type group filter
      description: |
        Set the event type groups that are filtered from the schedule of the current user.
      security:
        - Token: []
        - OAuth:
            - profile_write
      tags:
        - User
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              properties:
                eventTypeGroups:
                  type: object
                  description: Map with filter settings keyed by event type group ID.
                  additionalProperties:
                    type: object
                    description: Event type group
                    properties:
                      isFiltered:
                        type: boolean
                      isFilteredForSync:
                        type: boolean
            example: |
              eventTypeGroups[LECTURE][isFiltered]=true
              eventTypeGroups[LECTURE][isFilteredForSync]=false
              eventTypeGroups[EXAM][isFiltered]=false
      responses:
        '204':
          description: OK
        '403':
          description: 'Event type group filtering is not available, because it has been disabled.'
  /user/messages:
    get:
      operationId: get-user-messages
      summary: List active messages
      description: |
        Query the active messages targeted at the current user (as identified by the OAuth token or `requestedAuth` header).
      security:
        - Token: []
          RequestedAuth: []
        - OAuth:
            - messages_read
      tags:
        - User
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  messsages:
                    type: array
                    description: Active messages
                    items:
                      $ref: '#/components/schemas/Message'
            application/vnd.mytimetable.html+json:
              schema:
                type: object
                properties:
                  messsages:
                    type: array
                    description: Active messages
                    items:
                      $ref: '#/components/schemas/HtmlMessage'
  /messages:
    get:
      operationId: get-messages
      summary: List messages
      description: |
        Query all messages, both active and inactive.
      security:
        - Token:
            - ROLE_API_MESSAGES
      tags:
        - Messages
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  messsages:
                    type: array
                    description: Messages
                    items:
                      $ref: '#/components/schemas/Message'
            application/vnd.mytimetable.html+json:
              schema:
                type: object
                properties:
                  messsages:
                    type: array
                    description: Messages
                    items:
                      $ref: '#/components/schemas/HtmlMessage'
    post:
      operationId: create-message
      summary: Create message
      description: |
        Create a new message.
      security:
        - Token:
            - ROLE_API_MESSAGES
      tags:
        - Messages
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              allOf:
                - $ref: '#/components/schemas/MessageSubmission'
              required:
                - title
                - body
            example:
              title: This is the title of a message
              body: |-
                Lorem ipsum dolor sit amet, consectetur adipiscing elit.
                Sed faucibus, lectus nec lobortis posuere, leo eros convallis purus, eu cursus nunc velit lacinia nisi.

                # This is a header formatted with Markdown
                Ut eu dignissim leo, et lacinia elit.\nNullam vulputate egestas suscipit.
                Nullam leo metus, mollis non ornare at, elementum vel lorem.
              important: true
              publicationDate: '2019-12-12T00:00:00Z'
              expirationDate: '2020-02-01T00:00:00Z'
              targetRoles:
                - ROLE_STAFF
                - ROLE_STUDENT
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Message'
            application/vnd.mytimetable.html+json:
              schema:
                $ref: '#/components/schemas/HtmlMessage'
        '400':
          description: Validation failed
  '/messages/{id}':
    get:
      operationId: get-message
      summary: Get message
      description: |
        Retrieve the message with the specified ID.
      security:
        - Token:
            - ROLE_API_MESSAGES
      tags:
        - Messages
      parameters:
        - name: id
          in: path
          schema:
            type: integer
          required: true
          description: ID of the message that should be retrieved
          example: 16
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Message'
            application/vnd.mytimetable.html+json:
              schema:
                $ref: '#/components/schemas/HtmlMessage'
        '404':
          description: Message does not exist
    patch:
      operationId: update-message
      summary: Update message
      description: |
        Update the message with the specified ID.
      security:
        - Token:
            - ROLE_API_MESSAGES
      tags:
        - Messages
      parameters:
        - name: id
          in: path
          schema:
            type: integer
          required: true
          description: ID of the message that should be updated
          example: 16
      requestBody:
        required: true
        description: |
          Attributes to update.
          Only attributes set in the body of the request will be updated.
        content:
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/MessageSubmission'
            example:
              title: This is the title of a message
              body: |-
                Lorem ipsum dolor sit amet, consectetur adipiscing elit.
                Sed faucibus, lectus nec lobortis posuere, leo eros convallis purus, eu cursus nunc velit lacinia nisi.

                # This is a header formatted with Markdown
                Ut eu dignissim leo, et lacinia elit.\nNullam vulputate egestas suscipit.
                Nullam leo metus, mollis non ornare at, elementum vel lorem.
              important: true
              publicationDate: '2019-12-12'
              expirationDate: ''
              targetRoles:
                - ROLE_STAFF
                - ROLE_STUDENT
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Message'
            application/vnd.mytimetable.html+json:
              schema:
                $ref: '#/components/schemas/HtmlMessage'
        '400':
          description: Validation failed
        '404':
          description: Message does not exist
    delete:
      operationId: delete-message
      summary: Delete message
      description: |
        Delete the message with the specified ID.
      security:
        - Token:
            - ROLE_API_MESSAGES
      tags:
        - Messages
      parameters:
        - name: id
          in: path
          schema:
            type: integer
          required: true
          description: ID of the message that should be deleted
          example: 16
      responses:
        '204':
          description: OK
        '404':
          description: Message does not exist
components:
  schemas:
    Error:
      title: Error
      description: An error with details.
      type: object
      properties:
        status:
          type: string
          description: |
            High level error category
          example: error
        errorType:
          type: string
          description: Error type (machine-readable)
        errorMessage:
          type: string
          description: Human-readable error message
          example: The requested timetable does not exist.
    SubscriptionAlreadyExistsError:
      allOf:
        - $ref: '#/components/schemas/Error'
        - example:
            errorType: subscription_already_exists
            errorMessage: The subscription already exists.
    SubscriptionChangeNotAllowedError:
      allOf:
        - $ref: '#/components/schemas/Error'
        - example:
            errorType: subscription_change_not_allowed
            errorMessage: It's not allowed to change this non-removable subscription.
    TooManySubscriptionsEnabledError:
      allOf:
        - $ref: '#/components/schemas/Error'
        - example:
            errorType: too_many_subscriptions_enabled
            errorMessage: Too many subscriptions enabled. You can concurrently enable 25 subscriptions at most.
    Department:
      title: Department
      description: A department.
      type: object
      properties:
        id:
          type: string
          description: ID
          example: 2015!79066B3B1FB50D457F35D1264DC8D385-2020-W35-1
        key:
          type: string
          description: Host key
          nullable: true
        name:
          type: string
          description: Human-readable name
    Event:
      title: Event
      description: An event in a timetable.
      type: object
      properties:
        id:
          type: string
          description: Event ID
          example: 2015!79066B3B1FB50D457F35D1264DC8D385-2020-W35-1
        startDate:
          type: integer
          format: int64
          description: |
            Start date and time of the event (inclusive) as Unix timestamp in milliseconds.
            See [Date formats](#section/Date-formats).
          example: 1598252400000
        endDate:
          type: integer
          format: int64
          description: |
            End date and time of the event (exclusive) as Unix timestamp in milliseconds.
            See [Date formats](#section/Date-formats).
          example: 1598256000000
        allDay:
          type: boolean
          example: false
          description: |
            `true` if this event spans entire days, e.g. Christmas Day.
        activityDescription:
          type: string
          description: Human-readable name of the event
          example: Introduction to Artificial Intelligence
        conferenceUrl:
          type: string
          nullable: true
          format: uri
          description: |
            URL that can be used to join the online meeting of the event.
            Note that this attribute may still be null even if `online == true`.
        department:
          description: Department associated with the event.
          allOf:
            - nullable: true
            - $ref: '#/components/schemas/Department'
        draft:
          type: boolean
          description: The event is a draft (not yet final).
        enrolled:
          type: boolean
          nullable: true
          description: The user is enrolled for this event.
        eventType:
          description: Type of the event
          allOf:
            - nullable: true
            - $ref: '#/components/schemas/EventType'
        filtered:
          type: boolean
          description: |
            A filtered event must not be displayed in a user interface.
        highlighted:
          type: boolean
          description: Highlight in the user interface this event to draw attention to it.
        links:
          type: array
          items:
            type: object
            properties:
              key:
                type: string
                description: Machine-readable name of the link
                example: study_guide
              name:
                type: string
                description: Human-readable name
                example: Study guide
              url:
                type: string
                format: uri
                description: URL of the destination web page.
                example: 'https://studyguide.example.org/IN1000'
          description: Links to web pages that are relevant to the event.
        locations:
          type: array
          items:
            $ref: '#/components/schemas/Location'
          description: Locations at which the event takes place.
        moduleCode:
          type: string
          nullable: true
          description: Human-readable code or short name of the module
          example: IN1000
        notes1:
          type: string
          nullable: true
          description: Additional note 1 (free-form text)
        notes2:
          type: string
          nullable: true
          description: Additional note 2 (free-form text)
        notes3:
          type: string
          nullable: true
          description: Additional note 3 (free-form text)
        online:
          type: boolean
          description: The event takes place online.
        onLocation:
          type: boolean
          description: The event takes place on location.
        recorded:
          type: boolean
          description: The event was or will be recorded.
        recordingUrl:
          type: string
          nullable: true
          format: uri
          description: |
            URL to the recording of the event.
            Note that this attribute may still be null even if `recorded == true`.
        staffMembers:
          type: array
          items:
            $ref: '#/components/schemas/StaffMember'
          description: Staff members associated with the event.
        students:
          type: array
          items:
            $ref: '#/components/schemas/Student'
          description: Students associated with the event.
        studentSets:
          type: array
          items:
            $ref: '#/components/schemas/StudentSet'
          description: Student sets associated with the event.
        tags:
          type: array
          items:
            $ref: '#/components/schemas/Tag'
          description: Tags associated with the event.
        timetableKeys:
          type: array
          items:
            type: string
            example: 2015!syllabusng_pos!9A051B9B950DEE713FD55FCEFA2A7F70
          description: IDs of requested (top-level) timetables that include this event.
        customAttributes:
          type: object
          description: |
            Custom event properties in addition to the set offered by MyTimetable.
          additionalProperties:
            type: string
    EventType:
      title: Event type
      type: object
      properties:
        id:
          type: string
          description: ID
          example: LECTURE
        description:
          type: string
          description: Human-readable name
          example: Lecture
        color:
          type: string
          nullable: true
          description: Color of the event type for display in a user-interface.
          example: '#ff0000'
        eventTypeGroup:
          description: Event type group to which the event type belongs.
          allOf:
            - $ref: '#/components/schemas/EventTypeGroup'
    EventTypeGroup:
      title: Event type group
      description: A group of event types.
      type: object
      properties:
        id:
          type: string
          description: ID
          example: LECTURE
        description:
          type: string
          description: Human-readable name
          example: Lecture
    Location:
      title: Location
      description: A location or room.
      type: object
      properties:
        id:
          type: string
          description: ID
          example: 2015!5AE68DF33D7F7E8A1733AE6046FB8A1C
        key:
          type: string
          nullable: true
          description: Host key
          example: A-1.10
        name:
          type: string
          description: Human-readable name
          example: Room A-1.10
        capacity:
          type: integer
          nullable: true
          description: 'The capacity of the location, usually the number seats for students.'
          example: 50
        examCapacity:
          type: integer
          nullable: true
          description: 'The capacity of the location when used for exams, usually the number seats for students.'
          example: 25
        url:
          type: string
          format: uri
          nullable: true
          description: URL of a web page with information about this location.
          example: 'https://rooms.example.org/A-1.10'
        bookUrl:
          type: string
          format: uri
          nullable: true
          description: URL of an web page where this location can be booked.
          example: 'https://rooms.example.org/A-1.10/book'
        sipAddress:
          type: string
          description: |
            URI that addresses this location's telephone extension on a voice over IP system.
          nullable: true
        avoidConcurrencyLocationIds:
          type: array
          description: ID's of locations that cannot be used concurrently with this location.
          items:
            type: string
            example: 2015!5AE68DF33D7F7E8A1733AE6046FB8A1D
        customAttributes:
          type: object
          description: |
            Custom location properties in addition to the set offered by MyTimetable.
          additionalProperties:
            type: string
    MessageSubmission:
      title: Message
      description: A message.
      type: object
      properties:
        title:
          type: string
          description: Human-readable name
          example: This is the title of a message
        body:
          type: string
          description: 'Body text, formatted using [CommonMark Markdown](https://spec.commonmark.org/).'
          example: |-
            Lorem ipsum dolor sit amet, consectetur adipiscing elit.
            Sed faucibus, lectus nec lobortis posuere, leo eros convallis purus, eu cursus nunc velit lacinia nisi.

            # This is a header formatted with Markdown
            Ut eu dignissim leo, et lacinia elit.
            Nullam vulputate egestas suscipit.
            Nullam leo metus, mollis non ornare at, elementum vel lorem.
        important:
          type: boolean
          description: This message is marked as important.
        publicationDate:
          type: string
          nullable: true
          description: |
            The publication date of the message as Unix timestamp in milliseconds.
            See [Date formats](#section/Date-formats).

            The message will be published automatically on this date and time.
            If this field is null, this means the message is still a draft which is not published.
          example: '2019-03-01T00:00:00Z'
        expirationDate:
          type: string
          nullable: true
          description: |
            The expiration date of the message as Unix timestamp in milliseconds.
            See [Date formats](#section/Date-formats).

            The message will be unpublished automatically on this date and time.
            If this field is null, this means the message will not expire automatically.
          example: '2019-04-01T00:00:00Z'
        targetRoles:
          type: array
          description: |
            The roles at which this message is targeted.
            No roles means all users.
          items:
            type: string
            example: ROLE_STUDENT
    Message:
      title: Message
      description: A message.
      type: object
      properties:
        id:
          type: integer
          description: ID
          example: 16
          readOnly: true
        title:
          type: string
          description: Human-readable name
          example: This is the title of a message
        body:
          type: string
          description: 'Body text, formatted using [CommonMark Markdown](https://spec.commonmark.org/).'
          example: |-
            Lorem ipsum dolor sit amet, consectetur adipiscing elit.
            Sed faucibus, lectus nec lobortis posuere, leo eros convallis purus, eu cursus nunc velit lacinia nisi.

            # This is a header formatted with Markdown
            Ut eu dignissim leo, et lacinia elit.
            Nullam vulputate egestas suscipit.
            Nullam leo metus, mollis non ornare at, elementum vel lorem.
        important:
          type: boolean
          description: This message is marked as important.
        publicationDate:
          type: integer
          format: int64
          nullable: true
          description: |
            The publication date of the message as Unix timestamp in milliseconds.
            See [Date formats](#section/Date-formats).

            The message will be published automatically on this date and time.
            If this field is null, this means the message is still a draft which is not published.
          example: 1550155320000
        expirationDate:
          type: integer
          format: int64
          nullable: true
          description: |
            The expiration date of the message as Unix timestamp in milliseconds.
            See [Date formats](#section/Date-formats).

            The message will be unpublished automatically on this date and time.
            If this field is null, this means the message will not expire automatically.
          example: 1553252400000
        targetRoles:
          type: array
          description: |
            The roles at which this message is targeted.
            No roles means all users.
          items:
            type: string
            example: ROLE_STUDENT
    HtmlMessage:
      allOf:
        - description: A message with body rendered as HTML.
        - $ref: '#/components/schemas/Message'
        - properties:
            bodyHtml:
              type: string
              description: 'Body text, rendered as HTML.'
              example: |-
                <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed faucibus, lectus nec lobortis posuere, leo eros convallis purus, eu cursus nunc velit lacinia nisi.</p>
                <h1>This is a header formatted with Markdown</h1>
                <p>Ut eu dignissim leo, et lacinia elit. Nullam vulputate egestas suscipit. Nullam leo metus, mollis non ornare at, elementum vel lorem.</p>
    StaffMember:
      title: Staff member
      description: A staff member.
      type: object
      properties:
        id:
          type: string
          description: ID
          example: 2015!5AE68DF33D7F7E8A1733AE6046FB8A1C
        key:
          type: string
          nullable: true
          description: Host key
          example: WHI
        name:
          type: string
          description: Human-readable name
          example: Prof. White
        customAttributes:
          type: object
          description: |
            Custom staff properties in addition to the set offered by MyTimetable.
          additionalProperties:
            type: string
    Student:
      title: Student
      description: A student.
      type: object
      properties:
        id:
          type: string
          description: ID
          example: 2015!5AE68DF33D7F7E8A1733AE6046FB8E4D
        key:
          type: string
          nullable: true
          description: Host key
          example: '01354351'
        name:
          type: string
          description: Human-readable name
          example: Mr. Green
    StudentSet:
      title: Student set
      description: A group of students.
      properties:
        id:
          type: string
          description: ID
          example: 2015!5AE68DF33D7F7E8A1733AE6046FB87EF
        key:
          type: string
          nullable: true
          description: Host key
          example: IN1000-A
        name:
          type: string
          description: Human-readable name
          example: Group A
        customAttributes:
          type: object
          description: |
            Custom student set properties in addition to the set offered by MyTimetable.
          additionalProperties:
            type: string
    Tag:
      title: Tag
      description: A tag.
      type: object
      properties:
        key:
          type: string
          description: Host key
          nullable: true
          example: DRAFT
        name:
          type: string
          description: Human-readable name
          example: Draft
    Term:
      title: Term
      description: A term.
      type: object
      properties:
        id:
          type: string
          description: ID
        key:
          type: string
          nullable: true
          description: Host key
        name:
          type: string
          description: Human-readable name
        dateRanges:
          type: array
          items:
            type: object
            description: Date range
            properties:
              startDate:
                type: integer
                format: int64
                description: Start of the date range (inclusive)
              endDate:
                type: integer
                format: int64
                description: End of the date range (exclusive)
          description: Date ranges belonging to the term
    Timetable:
      title: Timetable
      description: A timetable.
      type: object
      properties:
        value:
          type: string
          description: ID
          example: 2011!module!49CBD432F01E8C5057B344E02604A710
        description:
          type: string
          description: Human-readable name
          example: VMT for Informatics
    TimetableFilterType:
      title: Timetable filter type
      type: object
      properties:
        type:
          type: string
          description: 'Timetable filter type name (ID, machine-readable)'
          example: department
        option:
          type: array
          items:
            $ref: '#/components/schemas/TimetableFilterOption'
          description: Available timetable filter options
    TimetableFilterOption:
      title: Timetable filter option
      type: object
      properties:
        value:
          type: string
          description: Timetable filter option ID
          example: 646ADCA666D4A88402CA46C26A73803C
        name:
          type: string
          description: Human readable name
          example: Faculty of Informatics
    TimetableOption:
      title: Timetable option
      type: object
      description: |
        A timetable option can be used to narrow down the selection of events from a timetable.
        It respresents a part of the timetable, for example, a specific student group.
        This group may only need to attend certain events in the timetable.

        Note that the timetables of timetable options may overlap, in other words, an event may be associated to multiple timetable options.
        On the other hand, if an event is not associated with any timetable option, it means it is not optional and will be selected in any case.
      properties:
        id:
          type: string
          description: ID
          example: 3772C4D1BFA1033EDD5E0539C89DD335
        name:
          type: string
          description: Human-readable name
          example: Group A
    TimetableSource:
      title: Timetable source
      type: object
      properties:
        key:
          type: string
          description: 'Key (ID, machine-readable)'
          example: '2015'
        label:
          type: string
          description: Human-readable name
          example: 2015/2016
    TimetableSubscription:
      title: Timetable subscription
      type: object
      properties:
        key:
          type: string
          description: Timetable ID (unique within the timetable subscriptions of a single user)
          example: 2015!module!49CBD432F01E8C5057B344E02604A711
        database:
          type: string
          description: The ID of the timetable source from which the timetable originates.
          example: '2015'
        type:
          type: string
          description: The timetable type name of the timetable.
          example: pos
        description:
          type: string
          description: Human-readable name of the timetable
          example: 'Computer Science, year 1'
        enabled:
          type: boolean
          description: |
            The visibility state of the timetable's events in the user interface.
            Depending on the scenario, the user can toggle this visibility in the UI.
        removable:
          type: boolean
          description: |
            This timetable can be removed by the user.
            When a timetable is removable, it basically means that the timetable was not subscribed to automatically based on (enrolment) information about the user.
        enabledOptions:
          type: array
          description: The selected timetable options
          items:
            $ref: '#/components/schemas/TimetableOption'
        childSubscriptions:
          type: array
          description: The child timetables of the timetable
          items:
            type: object
            properties:
              key:
                type: string
                description: Child timetable ID (unique within the parent timetable subscription)
                example: Child!49CBD432F01E8C5057B344E02604A712
              description:
                type: string
                description: Human-readable name of the child timetable
                example: Introduction to Artificial Intelligence
              enabled:
                type: boolean
                description: |
                  The visibility state of the child timetable's events in the user interface.
                  Depending on the scenario, the user can toggle this visibility in the UI.
              enabledOptions:
                type: array
                description: The selected timetable options
                items:
                  $ref: '#/components/schemas/TimetableOption'
    TimetableType:
      title: Timetable type
      type: object
      properties:
        name:
          type: string
          description: 'Timetable type name (ID, machine-readable)'
          example: pos
        description:
          type: string
          description: Human-readable name
          example: Programme of Study
        parent:
          type: boolean
          description: Supports child timetables
        optionMode:
          $ref: '#/components/schemas/OptionMode'
        childOptionMode:
          $ref: '#/components/schemas/ChildOptionMode'
        weight:
          type: integer
          description: Ordering weight (lower weight means higher priority)
          example: 1
    User:
      title: User
      description: A user.
      type: object
      properties:
        username:
          type: string
          description: 'Username (unique ID, machine-readable)'
          example: testuser
        roles:
          type: array
          nullable: true
          items:
            type: string
          description: |
            Roles of the user (machine-readable).

            This property will only be present when authenticated using an API token or with the OAuth scope `user_read`.
          example:
            - ROLE_STUDENT
            - ROLE_TUTOR
        feedUrl:
          type: string
          format: uri
          nullable: true
          description: |
            URL of the user's iCalendar feed containing its schedule.

            This property will only be present when authenticated using an API token or with the OAuth scope `profile_read`.
          example: 'https://mytimetable.example.org/ical?634b11c7&eu=ANQpzy==&h=ewmsyGgyVY8px7HR-czV_7SBz-RhbVjIQLox7gK6nfA='
    WeekLabel:
      title: Week label
      description: A custom label of a calendar week.
      type: object
      properties:
        year:
          type: integer
          description: ISO week year number
          example: 2014
        week:
          type: integer
          description: ISO week number
          example: 4
        description:
          type: string
          description: Human-readable name
          example: S1 Week 2
    WeekLabels:
      description: A list containing week labels.
      type: array
      items:
        $ref: '#/components/schemas/WeekLabel'
    OptionMode:
      type: string
      description: |
        Determines whether option selection is enabled when adding subscriptions.
        See [GET /timetables/{key}/options](#operation/get-timetable-options) for the available options.
      enum:
        - DISABLED
        - FIXED
        - EDITABLE_WHEN_REMOVABLE
        - EDITABLE
    ChildOptionMode:
      type: string
      description: |
        Determines whether child option selection is enabled when adding subscriptions.
        See [GET /timetables/{parent}/{key}/options](#operation/get-child-timetable-options) for the available child options.
      enum:
        - DISABLED
        - EDITABLE_WHEN_REMOVABLE
        - EDITABLE
  securitySchemes:
    Token:
      type: apiKey
      name: apiToken
      in: header
      description: |
        Usage of the MyTimetable API requires authentication using a token (pre-shared secret) when making API calls.
        This token can then be used to monitor an application's API usage and limit the amount of requests by a specific application (and thus the load placed on the servers).

        The token should be included in every request in the HTTP request header `apiToken`.

        ⚠ Please keep your API token a secret.
        This means you should only use it server-side, and any client-side requests (for instance from a mobile or Javascript application) should be proxied through your own web server.
    RequestedAuth:
      type: apiKey
      name: requestedAuth
      in: header
      description: |
        When necessary, an API token can be assigned *elevated permissions*, granting an impersonation privilege.
        Using such an API token it is possible to retrieve the personal data of any user, without prior consent from the user (and thus without an OAuth token).
        In these cases the application have to send an extra header, `requestedAuth`, specifying the username of the user to impersonate.
    OAuth:
      type: oauth2
      flows:
        authorizationCode:
          authorizationUrl: 'https://mytimetable.example.org/oauth/authorize'
          tokenUrl: 'https://mytimetable.example.org/oauth/token'
          scopes:
            username: 'Read basic user information, including username.'
            user_read: 'Read user information, including username and roles.'
            profile_read: 'Read user schedule, timetable subscriptions and preferences.'
            profile_write: Edit user timetable subscriptions and preferences.
            alltimetables: Read any timetables the user has access to.
            messages_read: Read any messages the user has access to.
      description: |
        Personal information in MyTimetable, like a user's timetable subscriptions or personal timetable, is available after receiving an OAuth token for the specified user (or by using an [API token](#section/Authentication/Token) with *elevated* permissions).

        MyTimetable uses OAuth 2.0.
        More information on the OAuth specification can be found on the [OAuth site](https://oauth.net/2/), in the [OAuth 2.0 RFC](https://tools.ietf.org/html/rfc6749) and in the [OAuth 2.0 Bearer Token RFC](https://tools.ietf.org/html/rfc6750).
        Currently, MyTimetable only supports the *Authorization Code* grant type.
        This is because this is the only grant type that provides absolute client identification using a client secret.
        On request by the educational institution other grant types can be tested and enabled (but these types will provide less security).

        For access to non-user specific resources (like the timetable of a room or module), a OAuth token will generally not be necessary.


        ### Example OAuth flow

        The following steps provide you with a token for our demo site:

        1. Redirect the end-user to the following URL: `https://demo.eveoh.nl/oauth/authorize?response_type=code&client_id=test&redirect_uri=http://localhost`.
           The user is then asked to authenticated and grant the application permission to retrieve the user's personal information.
           Afterwards the user will be redirected to the `redirect_uri` (so point this URL at your own web server).

        2. After granting permission, the user will be redirect to `redirect_uri/?code=XXXXXX`.
           Using this authorization code and the client secret, your application will be able to request an OAuth token.

        3. In the background and from your own secure server, your application should make an HTTP POST request to `https://demo.eveoh.nl/oauth/token` with form-encoded parameters: `grant_type=authorization_code&client_id=test&client_secret=test&code=XXXXXX&redirect_uri=http://localhost`.
           In a production environment, the `client_id` and `client_secret` should be replaced with your own client id and secret.
           The redirect_uri should match the value from the first step.

        4. This request will respond with an access token in JSON format.
           This token can then be used to make API calls by prepending the URL with `?access_token=token`, or by providing an `Authorization` request header (e.g. `Authorization: Bearer XX-XX-XX-XX`).

        ⚠ For optimal security, all communication should take place over an HTTPS encrypted channel.
        Also, the parameters in step 3 should be sent using an HTTP POST instead of GET.
        For more security recommendations check the RFCs.


        ### Scopes

        If an authorization request is made without providing any scopes, all scopes allowed for your application will be requested.
        Scopes can be limited by using the scope query parameter on the authorization request.
        In the authorization request dialog, the user will see a descriptions of the scopes your application wants to access.
security:
  - Token: []
  - OAuth: []
