{
  "openapi": "3.1.0",
  "info": {
    "title": "Aceversity API",
    "version": "1.0.0",
    "summary": "Courses, deadlines, study plans, grades, practice stats and flashcards for Aceversity members.",
    "description": "The Aceversity API gives a member — and the apps they connect, such as Claude, ChatGPT or n8n — access to their own study data: courses read from syllabi, exam and assignment dates, study-plan milestones, weighted grades, practice accuracy and flashcard decks.\n\n**Authentication.** Send `Authorization: Bearer <token>` with a personal API key (`ace_sk_…`, create one at https://api.aceversity.com/keys) or an OAuth 2.1 access token (`ace_at_…`). Scopes: `read`, `write`.\n\n**MCP.** The same operations are available as tools at `https://api.aceversity.com/mcp` (Streamable HTTP) for Claude and other MCP clients.\n\nGuides: https://docs.aceversity.com",
    "termsOfService": "https://aceversity.com/terms",
    "contact": {
      "name": "Aceversity developer support",
      "email": "support@aceversity.com",
      "url": "https://docs.aceversity.com"
    },
    "x-privacy-policy": "https://aceversity.com/privacy"
  },
  "servers": [
    {
      "url": "https://api.aceversity.com",
      "description": "Production"
    }
  ],
  "externalDocs": {
    "description": "Guides, connector setup and testing",
    "url": "https://docs.aceversity.com"
  },
  "tags": [
    {
      "name": "Account",
      "description": "Who the credential belongs to and whether their membership is active."
    },
    {
      "name": "Deadlines",
      "description": "Exams, quizzes, assignments, labs, papers and projects — the dated items read from syllabi."
    },
    {
      "name": "Courses",
      "description": "The member's courses and syllabus text."
    },
    {
      "name": "Study plan",
      "description": "Milestones: the steps leading up to each deadline."
    },
    {
      "name": "Grades",
      "description": "Weighted grade categories, scores and the current grade."
    },
    {
      "name": "Practice",
      "description": "Practice accuracy, streaks and weak topics."
    },
    {
      "name": "Vocabulary",
      "description": "Flashcard decks studied with spaced repetition."
    }
  ],
  "security": [
    {
      "ApiKey": []
    },
    {
      "OAuth2": [
        "read",
        "write"
      ]
    }
  ],
  "paths": {
    "/v1/me": {
      "get": {
        "operationId": "get_me",
        "summary": "Get the signed-in member",
        "description": "Returns the member the credential belongs to: name, email, time zone, today's date in that time zone, practice streak, membership status and the credential's scopes. Works without an active membership — call it first to check access.",
        "tags": [
          "Account"
        ],
        "security": [
          {
            "ApiKey": []
          },
          {
            "OAuth2": [
              "read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Me"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "x-openai-isConsequential": false,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X GET \"https://api.aceversity.com/v1/me\" \\\n  -H \"Authorization: Bearer $ACEVERSITY_API_KEY\""
          }
        ]
      }
    },
    "/v1/agenda": {
      "get": {
        "operationId": "get_agenda",
        "summary": "What's coming up",
        "description": "Everything due in the next `days` days (default 14) in the member's time zone: course items, plus unfinished study-plan milestones (overdue ones included and flagged). The best single call for \"what do I have to do this week?\".",
        "tags": [
          "Deadlines"
        ],
        "security": [
          {
            "ApiKey": []
          },
          {
            "OAuth2": [
              "read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "required": false,
            "description": "How many days ahead, 1–120.",
            "schema": {
              "default": 14,
              "type": "integer",
              "minimum": 1,
              "maximum": 120
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "today": {
                      "type": "string",
                      "format": "date",
                      "description": "Calendar date, YYYY-MM-DD."
                    },
                    "until": {
                      "type": "string",
                      "format": "date",
                      "description": "Calendar date, YYYY-MM-DD."
                    },
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Item"
                      }
                    },
                    "milestones": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "Resource id (UUID)."
                          },
                          "item_id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "Resource id (UUID)."
                          },
                          "title": {
                            "type": "string"
                          },
                          "due_on": {
                            "anyOf": [
                              {
                                "type": "string",
                                "format": "date",
                                "description": "Calendar date, YYYY-MM-DD."
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "done": {
                            "type": "boolean"
                          },
                          "position": {
                            "type": "integer"
                          },
                          "item_title": {
                            "type": "string"
                          },
                          "course_name": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "overdue": {
                            "type": "boolean"
                          }
                        },
                        "required": [
                          "id",
                          "item_id",
                          "title",
                          "due_on",
                          "done",
                          "position",
                          "item_title",
                          "course_name",
                          "overdue"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "today",
                    "until",
                    "items",
                    "milestones"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "x-openai-isConsequential": false,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X GET \"https://api.aceversity.com/v1/agenda\" \\\n  -H \"Authorization: Bearer $ACEVERSITY_API_KEY\""
          }
        ]
      }
    },
    "/v1/courses": {
      "get": {
        "operationId": "list_courses",
        "summary": "List my courses",
        "description": "Lists the member's courses, oldest first. Use a course `id` with the deadline, grade and vocabulary endpoints.",
        "tags": [
          "Courses"
        ],
        "security": [
          {
            "ApiKey": []
          },
          {
            "OAuth2": [
              "read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Course"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "description": "Pass as `cursor` to get the next page.",
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "has_more",
                    "next_cursor"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "x-openai-isConsequential": false,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X GET \"https://api.aceversity.com/v1/courses\" \\\n  -H \"Authorization: Bearer $ACEVERSITY_API_KEY\""
          }
        ]
      },
      "post": {
        "operationId": "create_course",
        "summary": "Create a course",
        "description": "Adds a course without a syllabus (like the app's \"no syllabus\" form). Add its deadlines with `create_item`.",
        "tags": [
          "Courses"
        ],
        "security": [
          {
            "ApiKey": []
          },
          {
            "OAuth2": [
              "write"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 120,
                    "description": "Course name, e.g. \"Introduction to Biology\"."
                  },
                  "code": {
                    "description": "Course number, e.g. \"BIO 101\".",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 20
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "term": {
                    "description": "Term, e.g. \"Fall 2026\". Defaults to \"Fall semester\".",
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 60
                  },
                  "meets": {
                    "description": "When the class meets.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 120
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "institution": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 120
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "subject": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 80
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "name"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Course"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "x-openai-isConsequential": true,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X POST \"https://api.aceversity.com/v1/courses\" \\\n  -H \"Authorization: Bearer $ACEVERSITY_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"name\":\"Midterm 1\"}'"
          }
        ]
      }
    },
    "/v1/courses/{course_id}": {
      "get": {
        "operationId": "get_course",
        "summary": "Get a course",
        "description": "Returns one course with its next five dated items. Set `include_syllabus` to also get the full syllabus text — useful context for answering questions about policies, topics and readings.",
        "tags": [
          "Courses"
        ],
        "security": [
          {
            "ApiKey": []
          },
          {
            "OAuth2": [
              "read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "course_id",
            "in": "path",
            "required": true,
            "description": "Resource id (UUID).",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "include_syllabus",
            "in": "query",
            "required": false,
            "description": "Include `syllabus_text` (can be long).",
            "schema": {
              "default": false,
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CourseDetail"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "x-openai-isConsequential": false,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X GET \"https://api.aceversity.com/v1/courses/<course_id>\" \\\n  -H \"Authorization: Bearer $ACEVERSITY_API_KEY\""
          }
        ]
      },
      "patch": {
        "operationId": "update_course",
        "summary": "Update a course",
        "description": "Changes only the fields you send. Send `null` to clear an optional field.",
        "tags": [
          "Courses"
        ],
        "security": [
          {
            "ApiKey": []
          },
          {
            "OAuth2": [
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "course_id",
            "in": "path",
            "required": true,
            "description": "Resource id (UUID).",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 120,
                    "description": "Course name, e.g. \"Introduction to Biology\"."
                  },
                  "code": {
                    "description": "Course number, e.g. \"BIO 101\".",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 20
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "term": {
                    "description": "Term, e.g. \"Fall 2026\". Defaults to \"Fall semester\".",
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 60
                  },
                  "meets": {
                    "description": "When the class meets.",
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 120
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "institution": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 120
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "subject": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 80
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Course"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "x-openai-isConsequential": true,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X PATCH \"https://api.aceversity.com/v1/courses/<course_id>\" \\\n  -H \"Authorization: Bearer $ACEVERSITY_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}'"
          }
        ]
      },
      "delete": {
        "operationId": "delete_course",
        "summary": "Delete a course",
        "description": "Permanently deletes the course with all of its deadlines, milestones, grades and uploaded files. This cannot be undone — confirm with the member first.",
        "tags": [
          "Courses"
        ],
        "security": [
          {
            "ApiKey": []
          },
          {
            "OAuth2": [
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "course_id",
            "in": "path",
            "required": true,
            "description": "Resource id (UUID).",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Deleted"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "x-openai-isConsequential": true,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X DELETE \"https://api.aceversity.com/v1/courses/<course_id>\" \\\n  -H \"Authorization: Bearer $ACEVERSITY_API_KEY\""
          }
        ]
      }
    },
    "/v1/items": {
      "get": {
        "operationId": "list_items",
        "summary": "List exams, quizzes and assignments",
        "description": "Lists dated course items (exams, quizzes, assignments, labs, papers, projects) across all courses, soonest first; undated items come last. Filter by course, kind and date range. For automations that poll for new items, pass `created_after` with the time of the previous run.",
        "tags": [
          "Deadlines"
        ],
        "security": [
          {
            "ApiKey": []
          },
          {
            "OAuth2": [
              "read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "course_id",
            "in": "query",
            "required": false,
            "description": "Only this course.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/ItemKind"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Due on or after this date.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Due on or before this date.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "created_after",
            "in": "query",
            "required": false,
            "description": "Only items added after this time (ISO 8601) — for polling triggers.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size, 1–100.",
            "schema": {
              "default": 25,
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "`next_cursor` from the previous page.",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Item"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "description": "Pass as `cursor` to get the next page.",
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "has_more",
                    "next_cursor"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "x-openai-isConsequential": false,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X GET \"https://api.aceversity.com/v1/items\" \\\n  -H \"Authorization: Bearer $ACEVERSITY_API_KEY\""
          }
        ]
      }
    },
    "/v1/items/{item_id}": {
      "get": {
        "operationId": "get_item",
        "summary": "Get an item",
        "description": "Returns one course item.",
        "tags": [
          "Deadlines"
        ],
        "security": [
          {
            "ApiKey": []
          },
          {
            "OAuth2": [
              "read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "item_id",
            "in": "path",
            "required": true,
            "description": "Resource id (UUID).",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Item"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "x-openai-isConsequential": false,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X GET \"https://api.aceversity.com/v1/items/<item_id>\" \\\n  -H \"Authorization: Bearer $ACEVERSITY_API_KEY\""
          }
        ]
      },
      "patch": {
        "operationId": "update_item",
        "summary": "Update an item",
        "description": "Changes only the fields you send — e.g. move an exam with `{ \"due_on\": \"2026-11-04\" }`. Send `due_on: null` to clear the date.",
        "tags": [
          "Deadlines"
        ],
        "security": [
          {
            "ApiKey": []
          },
          {
            "OAuth2": [
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "item_id",
            "in": "path",
            "required": true,
            "description": "Resource id (UUID).",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 160,
                    "description": "e.g. \"Midterm 1\" or \"Lab report 3\"."
                  },
                  "kind": {
                    "$ref": "#/components/schemas/ItemKind"
                  },
                  "due_on": {
                    "description": "Due date (YYYY-MM-DD).",
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "date",
                        "description": "Calendar date, YYYY-MM-DD."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Item"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "x-openai-isConsequential": true,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X PATCH \"https://api.aceversity.com/v1/items/<item_id>\" \\\n  -H \"Authorization: Bearer $ACEVERSITY_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}'"
          }
        ]
      },
      "delete": {
        "operationId": "delete_item",
        "summary": "Delete an item",
        "description": "Permanently deletes the item and its milestones. Confirm with the member first.",
        "tags": [
          "Deadlines"
        ],
        "security": [
          {
            "ApiKey": []
          },
          {
            "OAuth2": [
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "item_id",
            "in": "path",
            "required": true,
            "description": "Resource id (UUID).",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Deleted"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "x-openai-isConsequential": true,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X DELETE \"https://api.aceversity.com/v1/items/<item_id>\" \\\n  -H \"Authorization: Bearer $ACEVERSITY_API_KEY\""
          }
        ]
      }
    },
    "/v1/courses/{course_id}/items": {
      "post": {
        "operationId": "create_item",
        "summary": "Add an exam, quiz or assignment",
        "description": "Adds a dated item to a course. It appears on the member's calendar and drives their study plan and reminders.",
        "tags": [
          "Deadlines"
        ],
        "security": [
          {
            "ApiKey": []
          },
          {
            "OAuth2": [
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "course_id",
            "in": "path",
            "required": true,
            "description": "Resource id (UUID).",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 160,
                    "description": "e.g. \"Midterm 1\" or \"Lab report 3\"."
                  },
                  "kind": {
                    "default": "other",
                    "$ref": "#/components/schemas/ItemKind"
                  },
                  "due_on": {
                    "description": "Due date (YYYY-MM-DD).",
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "date",
                        "description": "Calendar date, YYYY-MM-DD."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "title"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Item"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "x-openai-isConsequential": true,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X POST \"https://api.aceversity.com/v1/courses/<course_id>/items\" \\\n  -H \"Authorization: Bearer $ACEVERSITY_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"title\":\"Midterm 1\"}'"
          }
        ]
      }
    },
    "/v1/items/{item_id}/milestones": {
      "get": {
        "operationId": "list_milestones",
        "summary": "List an item's milestones",
        "description": "The study-plan steps leading up to an item, in order.",
        "tags": [
          "Study plan"
        ],
        "security": [
          {
            "ApiKey": []
          },
          {
            "OAuth2": [
              "read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "item_id",
            "in": "path",
            "required": true,
            "description": "Resource id (UUID).",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Milestone"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "description": "Pass as `cursor` to get the next page.",
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "has_more",
                    "next_cursor"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "x-openai-isConsequential": false,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X GET \"https://api.aceversity.com/v1/items/<item_id>/milestones\" \\\n  -H \"Authorization: Bearer $ACEVERSITY_API_KEY\""
          }
        ]
      },
      "post": {
        "operationId": "create_milestone",
        "summary": "Add a milestone",
        "description": "Adds a study-plan step to an item (appended at the end).",
        "tags": [
          "Study plan"
        ],
        "security": [
          {
            "ApiKey": []
          },
          {
            "OAuth2": [
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "item_id",
            "in": "path",
            "required": true,
            "description": "Resource id (UUID).",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 160
                  },
                  "due_on": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "date",
                        "description": "Calendar date, YYYY-MM-DD."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "title"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Milestone"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "x-openai-isConsequential": true,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X POST \"https://api.aceversity.com/v1/items/<item_id>/milestones\" \\\n  -H \"Authorization: Bearer $ACEVERSITY_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"title\":\"Midterm 1\"}'"
          }
        ]
      }
    },
    "/v1/milestones/{milestone_id}": {
      "patch": {
        "operationId": "update_milestone",
        "summary": "Update or complete a milestone",
        "description": "Changes only the fields you send. `{ \"done\": true }` checks it off.",
        "tags": [
          "Study plan"
        ],
        "security": [
          {
            "ApiKey": []
          },
          {
            "OAuth2": [
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "milestone_id",
            "in": "path",
            "required": true,
            "description": "Resource id (UUID).",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 160
                  },
                  "due_on": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "date",
                        "description": "Calendar date, YYYY-MM-DD."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "done": {
                    "type": "boolean"
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Milestone"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "x-openai-isConsequential": true,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X PATCH \"https://api.aceversity.com/v1/milestones/<milestone_id>\" \\\n  -H \"Authorization: Bearer $ACEVERSITY_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}'"
          }
        ]
      },
      "delete": {
        "operationId": "delete_milestone",
        "summary": "Delete a milestone",
        "description": "Permanently deletes one study-plan step.",
        "tags": [
          "Study plan"
        ],
        "security": [
          {
            "ApiKey": []
          },
          {
            "OAuth2": [
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "milestone_id",
            "in": "path",
            "required": true,
            "description": "Resource id (UUID).",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Deleted"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "x-openai-isConsequential": true,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X DELETE \"https://api.aceversity.com/v1/milestones/<milestone_id>\" \\\n  -H \"Authorization: Bearer $ACEVERSITY_API_KEY\""
          }
        ]
      }
    },
    "/v1/courses/{course_id}/grades": {
      "get": {
        "operationId": "get_grades",
        "summary": "Get a course's grade breakdown",
        "description": "Grade categories with their weights and scores, each category's average, and the current weighted grade (renormalized over categories that have scores) with its letter grade.",
        "tags": [
          "Grades"
        ],
        "security": [
          {
            "ApiKey": []
          },
          {
            "OAuth2": [
              "read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "course_id",
            "in": "path",
            "required": true,
            "description": "Resource id (UUID).",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Grades"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "x-openai-isConsequential": false,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X GET \"https://api.aceversity.com/v1/courses/<course_id>/grades\" \\\n  -H \"Authorization: Bearer $ACEVERSITY_API_KEY\""
          }
        ]
      }
    },
    "/v1/courses/{course_id}/grade-categories": {
      "put": {
        "operationId": "set_grade_categories",
        "summary": "Replace a course's grade categories",
        "description": "Sets the full list of grade categories and weights (e.g. Exams 50, Homework 30, Labs 20). Send existing categories with their `id` to keep their scores; categories left out are deleted together with their scores.",
        "tags": [
          "Grades"
        ],
        "security": [
          {
            "ApiKey": []
          },
          {
            "OAuth2": [
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "course_id",
            "in": "path",
            "required": true,
            "description": "Resource id (UUID).",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "categories": {
                    "maxItems": 12,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid",
                          "description": "Resource id (UUID)."
                        },
                        "name": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 60
                        },
                        "weight": {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 100
                        }
                      },
                      "required": [
                        "name",
                        "weight"
                      ]
                    },
                    "description": "The complete list, in display order."
                  }
                },
                "required": [
                  "categories"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Grades"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "x-openai-isConsequential": true,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X PUT \"https://api.aceversity.com/v1/courses/<course_id>/grade-categories\" \\\n  -H \"Authorization: Bearer $ACEVERSITY_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"categories\":[]}'"
          }
        ]
      }
    },
    "/v1/courses/{course_id}/grade-scores": {
      "post": {
        "operationId": "add_grade_score",
        "summary": "Record a score",
        "description": "Records a score (percent) in one of the course's grade categories, e.g. `{ \"category_id\": \"…\", \"label\": \"Quiz 2\", \"score\": 88 }`. Get category ids from `get_grades`.",
        "tags": [
          "Grades"
        ],
        "security": [
          {
            "ApiKey": []
          },
          {
            "OAuth2": [
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "course_id",
            "in": "path",
            "required": true,
            "description": "Resource id (UUID).",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "category_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Resource id (UUID)."
                  },
                  "label": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 80
                  },
                  "score": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 150,
                    "description": "Percentage (0–150, extra credit allowed)."
                  }
                },
                "required": [
                  "category_id",
                  "label",
                  "score"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GradeScore"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "x-openai-isConsequential": true,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X POST \"https://api.aceversity.com/v1/courses/<course_id>/grade-scores\" \\\n  -H \"Authorization: Bearer $ACEVERSITY_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"category_id\":\"3f1c…\",\"label\":\"Midterm 1\",\"score\":90}'"
          }
        ]
      }
    },
    "/v1/grade-scores/{score_id}": {
      "delete": {
        "operationId": "delete_grade_score",
        "summary": "Delete a score",
        "description": "Permanently deletes one recorded score.",
        "tags": [
          "Grades"
        ],
        "security": [
          {
            "ApiKey": []
          },
          {
            "OAuth2": [
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "score_id",
            "in": "path",
            "required": true,
            "description": "Resource id (UUID).",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Deleted"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "x-openai-isConsequential": true,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X DELETE \"https://api.aceversity.com/v1/grade-scores/<score_id>\" \\\n  -H \"Authorization: Bearer $ACEVERSITY_API_KEY\""
          }
        ]
      }
    },
    "/v1/practice/stats": {
      "get": {
        "operationId": "get_practice_stats",
        "summary": "Practice accuracy and weak topics",
        "description": "Summarizes the member's practice answers over the last `days` days: overall accuracy, accuracy per topic (weakest first) and weak topics (≥ 3 attempts under 70%) — the topics to review next.",
        "tags": [
          "Practice"
        ],
        "security": [
          {
            "ApiKey": []
          },
          {
            "OAuth2": [
              "read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "required": false,
            "description": "Look-back window in days.",
            "schema": {
              "default": 30,
              "type": "integer",
              "minimum": 1,
              "maximum": 365
            }
          },
          {
            "name": "course_code",
            "in": "query",
            "required": false,
            "description": "Only this course code, e.g. \"BIO 101\".",
            "schema": {
              "type": "string",
              "maxLength": 40
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PracticeStats"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "x-openai-isConsequential": false,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X GET \"https://api.aceversity.com/v1/practice/stats\" \\\n  -H \"Authorization: Bearer $ACEVERSITY_API_KEY\""
          }
        ]
      }
    },
    "/v1/vocab/decks": {
      "get": {
        "operationId": "list_vocab_decks",
        "summary": "List flashcard decks",
        "description": "Lists the member's vocabulary decks, newest first.",
        "tags": [
          "Vocabulary"
        ],
        "security": [
          {
            "ApiKey": []
          },
          {
            "OAuth2": [
              "read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "course_id",
            "in": "query",
            "required": false,
            "description": "Only decks for this course.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/VocabDeck"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "description": "Pass as `cursor` to get the next page.",
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "has_more",
                    "next_cursor"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "x-openai-isConsequential": false,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X GET \"https://api.aceversity.com/v1/vocab/decks\" \\\n  -H \"Authorization: Bearer $ACEVERSITY_API_KEY\""
          }
        ]
      },
      "post": {
        "operationId": "create_vocab_deck",
        "summary": "Create a flashcard deck",
        "description": "Creates a deck of terms for a course; it shows up in the member's Practice → Vocabulary with spaced repetition. Write clear, self-contained definitions (one or two sentences).",
        "tags": [
          "Vocabulary"
        ],
        "security": [
          {
            "ApiKey": []
          },
          {
            "OAuth2": [
              "write"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "course_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Resource id (UUID)."
                  },
                  "title": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 140
                  },
                  "study_mode": {
                    "default": "term",
                    "description": "term: see the term, recall the definition; definition: the reverse; spell: type the term.",
                    "type": "string",
                    "enum": [
                      "term",
                      "definition",
                      "spell"
                    ]
                  },
                  "terms": {
                    "minItems": 1,
                    "maxItems": 100,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "term": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 120
                        },
                        "definition": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 600
                        },
                        "example": {
                          "anyOf": [
                            {
                              "type": "string",
                              "maxLength": 300
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "topic": {
                          "anyOf": [
                            {
                              "type": "string",
                              "maxLength": 120
                            },
                            {
                              "type": "null"
                            }
                          ]
                        }
                      },
                      "required": [
                        "term",
                        "definition"
                      ]
                    }
                  }
                },
                "required": [
                  "course_id",
                  "title",
                  "terms"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Resource id (UUID)."
                    },
                    "course_id": {
                      "anyOf": [
                        {
                          "type": "string",
                          "format": "uuid",
                          "description": "Resource id (UUID)."
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "title": {
                      "type": "string"
                    },
                    "word_count": {
                      "type": "integer"
                    },
                    "study_mode": {
                      "type": "string",
                      "enum": [
                        "term",
                        "definition",
                        "spell"
                      ]
                    },
                    "sessions": {
                      "type": "integer"
                    },
                    "last_studied_at": {
                      "anyOf": [
                        {
                          "type": "string",
                          "description": "ISO 8601 timestamp (UTC)."
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "created_at": {
                      "type": "string",
                      "description": "ISO 8601 timestamp (UTC)."
                    },
                    "terms": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/VocabTerm"
                      }
                    }
                  },
                  "required": [
                    "id",
                    "course_id",
                    "title",
                    "word_count",
                    "study_mode",
                    "sessions",
                    "last_studied_at",
                    "created_at",
                    "terms"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "x-openai-isConsequential": true,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X POST \"https://api.aceversity.com/v1/vocab/decks\" \\\n  -H \"Authorization: Bearer $ACEVERSITY_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"course_id\":\"3f1c…\",\"title\":\"Midterm 1\",\"terms\":[]}'"
          }
        ]
      }
    },
    "/v1/vocab/decks/{deck_id}/terms": {
      "get": {
        "operationId": "list_vocab_terms",
        "summary": "List a deck's terms",
        "description": "The terms and definitions in one deck.",
        "tags": [
          "Vocabulary"
        ],
        "security": [
          {
            "ApiKey": []
          },
          {
            "OAuth2": [
              "read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "deck_id",
            "in": "path",
            "required": true,
            "description": "Resource id (UUID).",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/VocabTerm"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "description": "Pass as `cursor` to get the next page.",
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "has_more",
                    "next_cursor"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "x-openai-isConsequential": false,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X GET \"https://api.aceversity.com/v1/vocab/decks/<deck_id>/terms\" \\\n  -H \"Authorization: Bearer $ACEVERSITY_API_KEY\""
          }
        ]
      }
    },
    "/v1/vocab/decks/{deck_id}": {
      "delete": {
        "operationId": "delete_vocab_deck",
        "summary": "Delete a deck",
        "description": "Permanently deletes the deck, its terms and their review history.",
        "tags": [
          "Vocabulary"
        ],
        "security": [
          {
            "ApiKey": []
          },
          {
            "OAuth2": [
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "deck_id",
            "in": "path",
            "required": true,
            "description": "Resource id (UUID).",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Deleted"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "x-openai-isConsequential": true,
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl -X DELETE \"https://api.aceversity.com/v1/vocab/decks/<deck_id>\" \\\n  -H \"Authorization: Bearer $ACEVERSITY_API_KEY\""
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "ace_sk_…",
        "description": "Personal API key from https://api.aceversity.com/keys, sent as `Authorization: Bearer ace_sk_…`."
      },
      "OAuth2": {
        "type": "oauth2",
        "description": "Authorization code with PKCE (S256). Clients may register dynamically (RFC 7591).",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://api.aceversity.com/oauth/authorize",
            "tokenUrl": "https://api.aceversity.com/oauth/token",
            "refreshUrl": "https://api.aceversity.com/oauth/token",
            "scopes": {
              "read": "Read your courses, deadlines, study plan, grades, practice stats and vocabulary",
              "write": "Add, change and delete courses, deadlines, milestones, grades and vocabulary"
            }
          }
        }
      }
    },
    "headers": {
      "RequestId": {
        "description": "Unique id of this request.",
        "schema": {
          "type": "string"
        }
      },
      "RateLimitRemaining": {
        "description": "Requests left in the current one-minute window.",
        "schema": {
          "type": "integer"
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Malformed request (e.g. invalid JSON or cursor).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "type": "invalid_request",
                "message": "The request body is not a valid JSON object.",
                "request_id": "req_8f2a1c9b0d3e4f5a6b7c"
              }
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing, invalid, expired or revoked credentials.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "type": "unauthorized",
                "message": "This API key is invalid, expired or revoked.",
                "request_id": "req_8f2a1c9b0d3e4f5a6b7c"
              }
            }
          }
        }
      },
      "Forbidden": {
        "description": "Missing scope, or the account has no active membership.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "type": "insufficient_scope",
                "message": "This credential lacks the `write` scope.",
                "request_id": "req_8f2a1c9b0d3e4f5a6b7c"
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "The resource doesn't exist or isn't yours.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "type": "not_found",
                "message": "Course not found.",
                "request_id": "req_8f2a1c9b0d3e4f5a6b7c"
              }
            }
          }
        }
      },
      "ValidationFailed": {
        "description": "The input failed validation; `details` lists each field.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "type": "validation_failed",
                "message": "`due_on`: Invalid ISO date",
                "request_id": "req_8f2a1c9b0d3e4f5a6b7c"
              }
            }
          }
        }
      },
      "RateLimited": {
        "description": "Too many requests. Wait `Retry-After` seconds.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "type": "rate_limited",
                "message": "Rate limit of 120 requests per 60s exceeded. Retry after 12s.",
                "request_id": "req_8f2a1c9b0d3e4f5a6b7c"
              }
            }
          }
        }
      },
      "ServerError": {
        "description": "Unexpected error. Retry; contact support with the `request_id` if it persists.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "type": "internal_error",
                "message": "Something went wrong on our side.",
                "request_id": "req_8f2a1c9b0d3e4f5a6b7c"
              }
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "type",
              "message",
              "request_id"
            ],
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "invalid_request",
                  "validation_failed",
                  "unauthorized",
                  "forbidden",
                  "insufficient_scope",
                  "membership_required",
                  "not_found",
                  "method_not_allowed",
                  "conflict",
                  "rate_limited",
                  "internal_error"
                ]
              },
              "message": {
                "type": "string",
                "description": "Human-readable explanation."
              },
              "request_id": {
                "type": "string",
                "description": "Quote this when contacting support."
              },
              "details": {
                "description": "Extra context, e.g. per-field validation errors."
              }
            }
          }
        }
      },
      "Me": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Resource id (UUID)."
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "email": {
            "type": [
              "string",
              "null"
            ]
          },
          "role": {
            "type": "string",
            "enum": [
              "student",
              "instructor"
            ]
          },
          "timezone": {
            "type": "string"
          },
          "locale": {
            "type": [
              "string",
              "null"
            ]
          },
          "today": {
            "type": "string",
            "format": "date",
            "description": "The member's current date in their time zone."
          },
          "streak": {
            "type": "integer"
          },
          "membership": {
            "type": "object",
            "properties": {
              "active": {
                "type": "boolean"
              },
              "status": {
                "description": "Stripe status: trialing, active, past_due, canceled…",
                "type": [
                  "string",
                  "null"
                ]
              },
              "plan": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "current_period_end": {
                "anyOf": [
                  {
                    "type": "string",
                    "description": "ISO 8601 timestamp (UTC)."
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "active",
              "status",
              "plan",
              "current_period_end"
            ],
            "additionalProperties": false
          },
          "credential": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "api_key",
                  "oauth"
                ]
              },
              "scopes": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "read",
                    "write"
                  ]
                }
              },
              "client_id": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "type",
              "scopes",
              "client_id"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "id",
          "name",
          "email",
          "role",
          "timezone",
          "locale",
          "today",
          "streak",
          "membership",
          "credential"
        ],
        "additionalProperties": false
      },
      "Item": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Resource id (UUID)."
          },
          "course_id": {
            "type": "string",
            "format": "uuid",
            "description": "Resource id (UUID)."
          },
          "course_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "title": {
            "type": "string"
          },
          "kind": {
            "$ref": "#/components/schemas/ItemKind"
          },
          "due_on": {
            "anyOf": [
              {
                "type": "string",
                "format": "date",
                "description": "Calendar date, YYYY-MM-DD."
              },
              {
                "type": "null"
              }
            ],
            "description": "Due date; null when the syllabus gave none."
          },
          "days_until": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Days from the member's today (negative = past)."
          },
          "created_at": {
            "type": "string",
            "description": "ISO 8601 timestamp (UTC)."
          }
        },
        "required": [
          "id",
          "course_id",
          "course_name",
          "title",
          "kind",
          "due_on",
          "days_until",
          "created_at"
        ],
        "additionalProperties": false,
        "description": "A dated course item: exam, quiz, assignment, lab, paper, project or other."
      },
      "ItemKind": {
        "type": "string",
        "enum": [
          "exam",
          "quiz",
          "assignment",
          "lab",
          "paper",
          "project",
          "other"
        ],
        "description": "What kind of deadline this is."
      },
      "Course": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Resource id (UUID)."
          },
          "name": {
            "type": "string"
          },
          "code": {
            "description": "Course number, e.g. \"BIO 101\".",
            "type": [
              "string",
              "null"
            ]
          },
          "term": {
            "type": "string"
          },
          "meets": {
            "description": "When the class meets, e.g. \"Mon/Wed 10:00\".",
            "type": [
              "string",
              "null"
            ]
          },
          "institution": {
            "type": [
              "string",
              "null"
            ]
          },
          "subject": {
            "type": [
              "string",
              "null"
            ]
          },
          "color": {
            "type": "string",
            "description": "Hex colour used for the course in the app."
          },
          "has_syllabus": {
            "type": "boolean",
            "description": "Whether a syllabus has been read for this course."
          },
          "created_at": {
            "type": "string",
            "description": "ISO 8601 timestamp (UTC)."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO 8601 timestamp (UTC)."
          }
        },
        "required": [
          "id",
          "name",
          "code",
          "term",
          "meets",
          "institution",
          "subject",
          "color",
          "has_syllabus",
          "created_at",
          "updated_at"
        ],
        "additionalProperties": false,
        "description": "A course the member is taking."
      },
      "CourseDetail": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Resource id (UUID)."
          },
          "name": {
            "type": "string"
          },
          "code": {
            "description": "Course number, e.g. \"BIO 101\".",
            "type": [
              "string",
              "null"
            ]
          },
          "term": {
            "type": "string"
          },
          "meets": {
            "description": "When the class meets, e.g. \"Mon/Wed 10:00\".",
            "type": [
              "string",
              "null"
            ]
          },
          "institution": {
            "type": [
              "string",
              "null"
            ]
          },
          "subject": {
            "type": [
              "string",
              "null"
            ]
          },
          "color": {
            "type": "string",
            "description": "Hex colour used for the course in the app."
          },
          "has_syllabus": {
            "type": "boolean",
            "description": "Whether a syllabus has been read for this course."
          },
          "created_at": {
            "type": "string",
            "description": "ISO 8601 timestamp (UTC)."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO 8601 timestamp (UTC)."
          },
          "syllabus_text": {
            "description": "Full syllabus text. Only present when `include_syllabus` is true.",
            "type": [
              "string",
              "null"
            ]
          },
          "item_count": {
            "type": "integer"
          },
          "upcoming": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Item"
            },
            "description": "The next 5 dated items from today."
          }
        },
        "required": [
          "id",
          "name",
          "code",
          "term",
          "meets",
          "institution",
          "subject",
          "color",
          "has_syllabus",
          "created_at",
          "updated_at",
          "item_count",
          "upcoming"
        ],
        "additionalProperties": false
      },
      "Deleted": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Resource id (UUID)."
          },
          "deleted": {
            "type": "boolean",
            "const": true
          }
        },
        "required": [
          "id",
          "deleted"
        ],
        "additionalProperties": false
      },
      "Milestone": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Resource id (UUID)."
          },
          "item_id": {
            "type": "string",
            "format": "uuid",
            "description": "Resource id (UUID)."
          },
          "title": {
            "type": "string"
          },
          "due_on": {
            "anyOf": [
              {
                "type": "string",
                "format": "date",
                "description": "Calendar date, YYYY-MM-DD."
              },
              {
                "type": "null"
              }
            ]
          },
          "done": {
            "type": "boolean"
          },
          "position": {
            "type": "integer"
          }
        },
        "required": [
          "id",
          "item_id",
          "title",
          "due_on",
          "done",
          "position"
        ],
        "additionalProperties": false,
        "description": "A study-plan step leading up to an item (e.g. \"Draft outline\")."
      },
      "Grades": {
        "type": "object",
        "properties": {
          "course_id": {
            "type": "string",
            "format": "uuid",
            "description": "Resource id (UUID)."
          },
          "current_percent": {
            "description": "Weighted grade over the categories that have scores, renormalized to their weights.",
            "type": [
              "number",
              "null"
            ]
          },
          "letter": {
            "description": "US letter grade for current_percent.",
            "type": [
              "string",
              "null"
            ]
          },
          "graded_weight": {
            "type": "number",
            "description": "Total weight (percent) of categories that have scores."
          },
          "categories": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GradeCategory"
            }
          }
        },
        "required": [
          "course_id",
          "current_percent",
          "letter",
          "graded_weight",
          "categories"
        ],
        "additionalProperties": false
      },
      "GradeCategory": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Resource id (UUID)."
          },
          "name": {
            "type": "string"
          },
          "weight": {
            "type": "number",
            "description": "Share of the final grade, in percent."
          },
          "position": {
            "type": "integer"
          },
          "average": {
            "description": "Mean of this category's scores; null when none yet.",
            "type": [
              "number",
              "null"
            ]
          },
          "scores": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GradeScore"
            }
          }
        },
        "required": [
          "id",
          "name",
          "weight",
          "position",
          "average",
          "scores"
        ],
        "additionalProperties": false
      },
      "GradeScore": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Resource id (UUID)."
          },
          "category_id": {
            "type": "string",
            "format": "uuid",
            "description": "Resource id (UUID)."
          },
          "label": {
            "type": "string"
          },
          "score": {
            "type": "number",
            "description": "Percentage, 0–150."
          },
          "created_at": {
            "type": "string",
            "description": "ISO 8601 timestamp (UTC)."
          }
        },
        "required": [
          "id",
          "category_id",
          "label",
          "score",
          "created_at"
        ],
        "additionalProperties": false
      },
      "PracticeStats": {
        "type": "object",
        "properties": {
          "since": {
            "type": "string",
            "format": "date",
            "description": "Calendar date, YYYY-MM-DD."
          },
          "streak": {
            "type": "integer",
            "description": "Consecutive practice days."
          },
          "last_practice_on": {
            "anyOf": [
              {
                "type": "string",
                "format": "date",
                "description": "Calendar date, YYYY-MM-DD."
              },
              {
                "type": "null"
              }
            ]
          },
          "total_attempts": {
            "type": "integer"
          },
          "total_correct": {
            "type": "integer"
          },
          "accuracy_percent": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "topics": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TopicStat"
            },
            "description": "Accuracy per topic, weakest first."
          },
          "weak_topics": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TopicStat"
            },
            "description": "Topics with ≥ 3 attempts under 70% — what to study next."
          }
        },
        "required": [
          "since",
          "streak",
          "last_practice_on",
          "total_attempts",
          "total_correct",
          "accuracy_percent",
          "topics",
          "weak_topics"
        ],
        "additionalProperties": false
      },
      "TopicStat": {
        "type": "object",
        "properties": {
          "course_code": {
            "type": [
              "string",
              "null"
            ]
          },
          "topic": {
            "type": "string"
          },
          "attempts": {
            "type": "integer"
          },
          "correct": {
            "type": "integer"
          },
          "percent": {
            "type": "integer"
          }
        },
        "required": [
          "course_code",
          "topic",
          "attempts",
          "correct",
          "percent"
        ],
        "additionalProperties": false
      },
      "VocabDeck": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Resource id (UUID)."
          },
          "course_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid",
                "description": "Resource id (UUID)."
              },
              {
                "type": "null"
              }
            ]
          },
          "title": {
            "type": "string"
          },
          "word_count": {
            "type": "integer"
          },
          "study_mode": {
            "type": "string",
            "enum": [
              "term",
              "definition",
              "spell"
            ]
          },
          "sessions": {
            "type": "integer"
          },
          "last_studied_at": {
            "anyOf": [
              {
                "type": "string",
                "description": "ISO 8601 timestamp (UTC)."
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "type": "string",
            "description": "ISO 8601 timestamp (UTC)."
          }
        },
        "required": [
          "id",
          "course_id",
          "title",
          "word_count",
          "study_mode",
          "sessions",
          "last_studied_at",
          "created_at"
        ],
        "additionalProperties": false,
        "description": "A flashcard deck."
      },
      "VocabTerm": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Resource id (UUID)."
          },
          "deck_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid",
                "description": "Resource id (UUID)."
              },
              {
                "type": "null"
              }
            ]
          },
          "term": {
            "type": "string"
          },
          "definition": {
            "type": "string"
          },
          "example": {
            "type": [
              "string",
              "null"
            ]
          },
          "topic": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "deck_id",
          "term",
          "definition",
          "example",
          "topic"
        ],
        "additionalProperties": false
      }
    }
  }
}