{
  "components": {
    "schemas": {
      "APIKey": {
        "properties": {
          "createdAt": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "type": "string"
          },
          "keyPrefix": {
            "type": "string"
          },
          "lastUsedAt": {
            "format": "date-time",
            "nullable": true,
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "revokedAt": {
            "format": "date-time",
            "nullable": true,
            "type": "string"
          },
          "scopes": {
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "type": "object"
      },
      "CreateAPIKeyRequest": {
        "properties": {
          "name": {
            "type": "string"
          },
          "scopes": {
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "type": "object"
      },
      "CreateAPIKeyResponse": {
        "properties": {
          "apiKey": {
            "type": "string"
          },
          "apiKeyRecord": {
            "$ref": "#/components/schemas/APIKey"
          }
        },
        "required": [
          "apiKey",
          "apiKeyRecord"
        ],
        "type": "object"
      },
      "Error": {
        "properties": {
          "error": {
            "type": "string"
          }
        },
        "required": [
          "error"
        ],
        "type": "object"
      },
      "QRExchangeRequest": {
        "properties": {
          "qr": {
            "type": "string"
          }
        },
        "required": [
          "qr"
        ],
        "type": "object"
      },
      "QRExchangeResponse": {
        "properties": {
          "apiKey": {
            "type": "string"
          },
          "apiKeyRecord": {
            "$ref": "#/components/schemas/APIKey"
          },
          "user": {
            "$ref": "#/components/schemas/User"
          }
        },
        "required": [
          "user",
          "apiKey",
          "apiKeyRecord"
        ],
        "type": "object"
      },
      "User": {
        "properties": {
          "displayName": {
            "type": "string"
          },
          "id": {
            "type": "string"
          },
          "moodleSiteUrl": {
            "type": "string"
          },
          "moodleUserId": {
            "type": "integer"
          }
        },
        "required": [
          "id",
          "moodleSiteUrl",
          "moodleUserId",
          "displayName"
        ],
        "type": "object"
      }
    },
    "securitySchemes": {
      "apiKey": {
        "in": "header",
        "name": "X-Moodle-App-Key",
        "type": "apiKey"
      },
      "bearerAuth": {
        "scheme": "bearer",
        "type": "http"
      }
    }
  },
  "info": {
    "description": "Private Moodle Services API for QR login, API keys, Moodle courses, materials, PDFs, calendar data, and ChatGPT MCP support.",
    "title": "Moodle Services API",
    "version": "0.1.0"
  },
  "openapi": "3.1.0",
  "paths": {
    "/api/auth/qr/exchange": {
      "post": {
        "operationId": "exchangeQRCode",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QRExchangeRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QRExchangeResponse"
                }
              }
            },
            "description": "OK"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          }
        },
        "summary": "Exchange Moodle Mobile QR code"
      }
    },
    "/api/courses": {
      "get": {
        "operationId": "listCourses",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "description": "OK"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKey": []
          }
        ],
        "summary": "List Moodle courses"
      }
    },
    "/api/courses/{courseId}/materials": {
      "get": {
        "operationId": "listCourseMaterials",
        "parameters": [
          {
            "in": "path",
            "name": "courseId",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "description": "OK"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKey": []
          }
        ],
        "summary": "List course materials"
      }
    },
    "/api/courses/{courseId}/materials/{resourceId}/pdf": {
      "get": {
        "operationId": "readMaterialPDF",
        "parameters": [
          {
            "in": "path",
            "name": "courseId",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "resourceId",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "description": "OK"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKey": []
          }
        ],
        "summary": "Read material PDF"
      }
    },
    "/api/courses/{courseId}/materials/{resourceId}/text": {
      "get": {
        "operationId": "readMaterialText",
        "parameters": [
          {
            "in": "path",
            "name": "courseId",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "resourceId",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "description": "OK"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKey": []
          }
        ],
        "summary": "Read material text"
      }
    },
    "/api/keys": {
      "get": {
        "operationId": "listAPIKeys",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/APIKey"
                  },
                  "type": "array"
                }
              }
            },
            "description": "OK"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKey": []
          }
        ],
        "summary": "List API keys"
      },
      "post": {
        "operationId": "createAPIKey",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAPIKeyRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateAPIKeyResponse"
                }
              }
            },
            "description": "OK"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKey": []
          }
        ],
        "summary": "Create API key"
      }
    },
    "/api/me": {
      "get": {
        "operationId": "getMe",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            },
            "description": "OK"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKey": []
          }
        ],
        "summary": "Get current API user"
      }
    },
    "/api/openapi.json": {
      "get": {
        "operationId": "getOpenAPISpec",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "description": "OK"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          }
        },
        "summary": "Get OpenAPI spec"
      }
    },
    "/api/search": {
      "get": {
        "operationId": "searchMoodle",
        "parameters": [
          {
            "in": "query",
            "name": "q",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "description": "OK"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Error"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "apiKey": []
          }
        ],
        "summary": "Search Moodle"
      }
    }
  },
  "servers": [
    {
      "url": "https://moodle-services.os-home.net"
    }
  ]
}