{
  "openapi": "3.0.1",
  "info": {
    "title": "SoftLanding.ApiService | customer",
    "version": "1.0.0"
  },
  "paths": {
    "/customer/homework-documents/{id}": {
      "get": {
        "tags": [
          "HomeworkDocument (Customer)"
        ],
        "summary": "Download a file of one of the customer's students' homework.",
        "description": "Streams the stored file with its original name and content type. A customer reads the files of homework on a course one of THEIR students is enrolled in — the portal renders the homework off the student's lessons, so the file has to follow it there. Anything else is `404`.",
        "operationId": "DownloadHomeworkDocumentCustomer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/dashboard": {
      "get": {
        "tags": [
          "Dashboard (Customer)"
        ],
        "summary": "Get the customer dashboard aggregate.",
        "description": "Returns a single read-only snapshot object for the signed-in customer's home screen, assembled in\none call instead of from the individual customer endpoints.\n\nIt is scoped to the signed-in customer and aggregates across all of that customer's own students:\n- counters (remaining prepaid credit in CHF, outstanding unpaid invoices, upcoming lessons, unread\n  notifications),\n- upcoming lessons across the customer's students,\n- course invites awaiting the customer's response,\n- recently issued invoices and recent notifications.\n\nThe figures are point-in-time and computed on each request. No other customer's data is included.",
        "operationId": "GetCustomerDashboard",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerDashboardGet"
                }
              }
            }
          }
        }
      }
    },
    "/customer/invoice-documents/{id}": {
      "get": {
        "tags": [
          "Customer Invoices"
        ],
        "summary": "Download the invoice PDF that was sent to you.",
        "description": "Streams the invoice document. The id comes from `fileUrl` on the invoice — it is the id of the\nstored PDF, not of the invoice, because what a customer may download is the document that was\nactually sent to them and not a fresh rendering of the current data.\n\nAn invoice that has never been sent has no document and therefore no `fileUrl`.\n\n`404` for a document that does not exist OR belongs to another customer — never `403`, which\nwould confirm that somebody else's invoice exists.",
        "operationId": "GetCustomerInvoiceDocument",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/material-change-requests": {
      "get": {
        "tags": [
          "MaterialChangeRequest (Customer)"
        ],
        "summary": "List the material questions put to this customer's students.",
        "description": "Returns the requests addressed to any of the signed-in customer's own students — anything else is\nnot in scope and cannot be reached by id either.\n\nEach carries the course, which student it is about, the articles with their status, and\n`defaultDeliveryAddress`: the address on file, offered when the answer says \"by mail\".\n\nFilter with `isAnswered`, `courseId`, `studentId` and `searchTerm`.\nSupports pagination and sorting: send an optional `Range` request header (`0-49` = first 50, `-50` = last\n50, `50` = from index 50; 0-based, end inclusive) plus the `orderBy` (a property name of the returned\nobject, case-insensitive) and `desc` query parameters. The body is a plain JSON array; the total count is\nreturned in the `Content-Range` response header (`items {start}-{end}/{total}`). Status is `206` when a\n`Range` is sent, `416` if the range is invalid.",
        "operationId": "GetMaterialChangeRequestsCustomer",
        "parameters": [
          {
            "name": "SearchTerm",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ShowRemoved",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "IsAnswered",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "CourseId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "StudentId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Range",
            "in": "header",
            "description": "Pagination window (zero-based, end inclusive): `{start}-{end}` e.g. `0-49`; `-{n}` = last n; `{n}` = first n. When set, the response is 206 with a `Content-Range` header.",
            "schema": {
              "type": "string",
              "example": "0-49"
            }
          },
          {
            "name": "orderBy",
            "in": "query",
            "description": "Sort by this result property name (case-insensitive). Unknown property → 400.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "desc",
            "in": "query",
            "description": "Sort descending when true (default false). Applied before pagination.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/MaterialChangeRequestGet"
                  }
                }
              }
            }
          },
          "206": {
            "description": "Partial Content — returned when a `Range` header is present. Body is the requested window.",
            "headers": {
              "Content-Range": {
                "description": "`items {start}-{end}/{total}` (empty page → `items */{total}`).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/MaterialChangeRequestGet"
                  }
                }
              }
            }
          },
          "416": {
            "description": "Range Not Satisfiable — the `Range` header is malformed or starts beyond the last item."
          }
        }
      }
    },
    "/customer/material-change-requests/{id}": {
      "get": {
        "tags": [
          "MaterialChangeRequest (Customer)"
        ],
        "summary": "Get one of the customer's material change requests.",
        "description": "`404` for a request that belongs to somebody else — the answer must not confirm that it exists.",
        "operationId": "GetMaterialChangeRequestCustomerById",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MaterialChangeRequestGet"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "MaterialChangeRequest (Customer)"
        ],
        "summary": "Answer a material change request.",
        "description": "Answers the request, or corrects an answer already given.\n\nSend one entry per article in `answers`; articles left out keep what they had, so a round may legitimately\nbe answered in two sittings. `alreadyInPossession` is REQUIRED on every entry — omitting it would arrive\nas `false`, which reads as \"please order it\", and a book must never be bought by saying nothing.\n\nThe delivery method may be stated per article or once for the whole round (`deliveryMethodId`); the\nper-article value wins. An article that is NOT already owned needs an effective method, and anything going\nby mail needs a `deliveryAddress` — both are `400` with the article named, because neither can be decided\nfrom one article alone.\n\nAnswering the LAST open article closes the round and produces the material order, in the same transaction:\nan answered round can never exist without its order. It is billed on the next monthly invoice, not on a\nmaterial invoice of its own — this is Fall 2 by definition.\nA customer answers for ALL of their students, adults included — the specification's own rule, and\nthe difference from the student's own route, where a minor is refused.",
        "operationId": "UpdateMaterialChangeRequestCustomer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MaterialChangeRequestPatch"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MaterialChangeRequestGet"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/customers": {
      "get": {
        "tags": [
          "Customer (Customer)"
        ],
        "summary": "List customers (customer portal).",
        "description": "Returns the customer account(s) the signed-in user can see in the self-service portal — normally\nonly their own record — each as a `CustomerGet` with the customer type (Company or Private Person),\ncompany name, correspondence language, contact person, billing address and the list of the\ncustomer's students. Office-internal fields (VAT number, notes, activity flag) are not exposed.\nRecords belonging to other customers are never returned. Soft-deleted records are excluded by\ndefault. Filter with `searchTerm` (matches company name, contact first/last name, email and phone),\n`customerTypeId`, `city` and `postalCode`.\n\nSupports pagination and sorting: send an optional `Range` request header (`0-49` = first 50,\n`-50` = last 50, `50` = from index 50; 0-based, end inclusive) plus the `orderBy` (a property\nname of the returned object, case-insensitive) and `desc` query parameters. The body is a plain\nJSON array; the total count is returned in the `Content-Range` response header\n(`items {start}-{end}/{total}`). Status is `206` when a `Range` is sent, `416` if the range is invalid.",
        "operationId": "GetCustomersCustomer",
        "parameters": [
          {
            "name": "SearchTerm",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ShowRemoved",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "CustomerTypeId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "City",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "PostalCode",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Range",
            "in": "header",
            "description": "Pagination window (zero-based, end inclusive): `{start}-{end}` e.g. `0-49`; `-{n}` = last n; `{n}` = first n. When set, the response is 206 with a `Content-Range` header.",
            "schema": {
              "type": "string",
              "example": "0-49"
            }
          },
          {
            "name": "orderBy",
            "in": "query",
            "description": "Sort by this result property name (case-insensitive). Unknown property → 400.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "desc",
            "in": "query",
            "description": "Sort descending when true (default false). Applied before pagination.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CustomerGet"
                  }
                }
              }
            }
          },
          "206": {
            "description": "Partial Content — returned when a `Range` header is present. Body is the requested window.",
            "headers": {
              "Content-Range": {
                "description": "`items {start}-{end}/{total}` (empty page → `items */{total}`).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CustomerGet"
                  }
                }
              }
            }
          },
          "416": {
            "description": "Range Not Satisfiable — the `Range` header is malformed or starts beyond the last item."
          }
        }
      },
      "post": {
        "tags": [
          "Customer (Customer)"
        ],
        "summary": "Register a customer (private person self-registration).",
        "description": "Self-registers a new private-person customer account from the `CustomerPost` body and returns the\ncreated `CustomerGet` (with its generated id). The new account starts with `ProfileConfirmed`\nset to false so the portal can prompt for a first-login profile review. Returns `400` with\nvalidation details if the body is invalid.",
        "operationId": "CreateCustomerCustomer",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerPost"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerGet"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/customers/{id}": {
      "get": {
        "tags": [
          "Customer (Customer)"
        ],
        "summary": "Get a single customer by id.",
        "description": "Returns a single customer account by its id as a `CustomerGet` (self-view; office-internal fields\nexcluded). Returns `404` if no such customer exists or if it does not belong to the signed-in user.",
        "operationId": "GetCustomerCustomerById",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerGet"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Customer (Customer)"
        ],
        "summary": "Partially update a customer.",
        "description": "Partially updates an existing customer account: only the fields present in the `CustomerPatch`\nbody are changed, the rest stay as they are. Returns the updated `CustomerGet`. Returns `404` if\nno such customer exists or it does not belong to the signed-in user; `400` on validation errors.",
        "operationId": "UpdateCustomerCustomer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerPatch"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerGet"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Customer (Customer)"
        ],
        "summary": "Delete a customer (soft by default; ?hard=true to hard-delete).",
        "description": "Deletes a customer account. By default this is a soft delete — the account is hidden from normal\nlistings but can be restored; pass `?hard=true` to remove it permanently. Returns `204`, or `404`\nif no such customer exists or it does not belong to the signed-in user.",
        "operationId": "DeleteCustomerCustomer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "hard",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/customers/{id}/restore": {
      "post": {
        "tags": [
          "Customer (Customer)"
        ],
        "summary": "Restore a soft-deleted customer.",
        "description": "Restores a previously soft-deleted customer account so it appears in normal listings again.\nReturns `204`, or `404` if no such customer exists or it does not belong to the signed-in user.",
        "operationId": "RestoreCustomerCustomer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/students": {
      "get": {
        "tags": [
          "Student (Customer)"
        ],
        "summary": "List the current customer's students.",
        "description": "Returns the students that belong to the signed-in customer â€” each a `StudentGet` with identity\n(name, birthdate, native language), contact details, subjects (language/level pairs), lifecycle\nstatus and the student's related courses and lessons. Office-internal fields (teacher notes,\ninternal exam records) are excluded. Students of other customers are never returned. Soft-deleted\nstudents are excluded by default. Filter with `searchTerm` (matches first name, last name and\nemail), `nativeLanguageId`, `subjectLanguageId` (resolvable via `/lookups/â€¦`), `isChild` and\n`status`.\n\nSupports pagination and sorting: send an optional `Range` request header (`0-49` = first 50,\n`-50` = last 50, `50` = from index 50; 0-based, end inclusive) plus the `orderBy` (a property\nname of the returned object, case-insensitive) and `desc` query parameters. The body is a plain\nJSON array; the total count is returned in the `Content-Range` response header\n(`items {start}-{end}/{total}`). Status is `206` when a `Range` is sent, `416` if the range is invalid.",
        "operationId": "GetStudentsCustomer",
        "parameters": [
          {
            "name": "SearchTerm",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ShowRemoved",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "NativeLanguageId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "IsChild",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "SubjectLanguageId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Status",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/NullableOfEStudentStatus"
            }
          },
          {
            "name": "AccountStatus",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/NullableOfEAccountStatus"
            }
          },
          {
            "name": "Range",
            "in": "header",
            "description": "Pagination window (zero-based, end inclusive): `{start}-{end}` e.g. `0-49`; `-{n}` = last n; `{n}` = first n. When set, the response is 206 with a `Content-Range` header.",
            "schema": {
              "type": "string",
              "example": "0-49"
            }
          },
          {
            "name": "orderBy",
            "in": "query",
            "description": "Sort by this result property name (case-insensitive). Unknown property → 400.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "desc",
            "in": "query",
            "description": "Sort descending when true (default false). Applied before pagination.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/StudentGet"
                  }
                }
              }
            }
          },
          "206": {
            "description": "Partial Content — returned when a `Range` header is present. Body is the requested window.",
            "headers": {
              "Content-Range": {
                "description": "`items {start}-{end}/{total}` (empty page → `items */{total}`).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/StudentGet"
                  }
                }
              }
            }
          },
          "416": {
            "description": "Range Not Satisfiable — the `Range` header is malformed or starts beyond the last item."
          }
        }
      },
      "post": {
        "tags": [
          "Student (Customer)"
        ],
        "summary": "Add a student to the current customer's account.",
        "description": "Adds a new student to the signed-in customer's account from the `StudentPost` body and returns\nthe created `StudentGet` (with its generated id). The new student is automatically linked to the\nsigned-in customer. Returns `400` with validation details if the body is invalid.",
        "operationId": "CreateStudentCustomer",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StudentPost"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StudentGet"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/students/{id}": {
      "get": {
        "tags": [
          "Student (Customer)"
        ],
        "summary": "Get a single student by id (customer).",
        "description": "Returns a single student by its id as a `StudentGet` (office-internal fields excluded): identity,\ncontact details, subjects, lifecycle status, the student's related `courses` and their `lessons`.\nEach lesson carries its course (incl. teaching level, course type and the course's teacher), the\nlesson's own teacher and its homeworks. A student's lessons are the lessons of the courses the\nstudent is ENROLLED in; courses still in `Draft` and their lessons are never shown. This is also\nthe only student-scoped lesson list: the `/customer/lessons` list filters by course, not by\nstudent. Returns `404` if no such student exists or if it does not belong to the signed-in\ncustomer.",
        "operationId": "GetStudentCustomerById",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StudentGet"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Student (Customer)"
        ],
        "summary": "Partially update one of the customer's students.",
        "description": "Partially updates one of the customer's students: only the fields present in the `StudentPatch`\nbody are changed, the rest stay as they are. This INCLUDES the student's email address — for a\nminor it is the only way it can change at all, and it is carried through to their login account\n(whose login NUMBER never changes). A duplicate address is refused with `409`. Returns the updated `StudentGet`. Returns `404` if\nno such student exists or it does not belong to the signed-in customer; `400` on validation errors.\n\nIt also carries `inactive`, which PAUSES the student (`true`) or resumes them (`false`). The\nstudent's `status` is composed from it: `inactive` → `Inactive`, otherwise `Invited` while their\nlogin has not been used yet, otherwise `Active` — so the status itself cannot be set, only this\nflag. Pausing WITHDRAWS the student's unanswered course invitations and refuses (`409`) any new\nenquiry, enrolment request, course assignment or invitation for them; it also silences their\nnotifications and mails. What already exists is untouched: enrolled courses keep running, past\nlessons stay billed and the login keeps working.",
        "operationId": "UpdateStudentCustomer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StudentPatch"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StudentGet"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Student (Customer)"
        ],
        "summary": "Delete one of the customer's students (soft by default; ?hard=true to hard-delete).",
        "description": "Archives one of the customer's students: a SOFT delete — the student disappears from the normal\nlistings and can be restored. Returns `204`, or `404` if no such student exists or it does not\nbelong to the signed-in customer.\n\n**`?hard=true` is not available to a customer.** A permanent delete needs the `hard-delete` realm\nrole, which only office staff hold, so this route answers `403` with that reason — the customer\nportal must offer archiving, not permanent deletion.",
        "operationId": "DeleteStudentCustomer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "hard",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/students/{id}/resend-invitation": {
      "post": {
        "tags": [
          "Student (Customer)"
        ],
        "summary": "Re-send one of my students' password-setup mail.",
        "description": "Triggers the onboarding (\"magic link\") mail again for one of the signed-in customer's own students â€”\nthe one added through \"Add new student\" who has not followed the first mail. It also repairs a\nprovisioning run that did not finish, which is how a student whose `accountStatus` reads `Failed` is\nfixed. The mail is rendered in the student's correspondence language.\n\nOnly the customer's OWN students are reachable: another customer's student is `404`, never `403`.\nReturns `204` on success, `400` if the student has no email address, `409` if the account already\ncompleted onboarding (a forgotten password is reset by the student through the sign-in page, not\nfrom here), and `503` when no identity provider is configured for this environment.",
        "operationId": "ResendStudentInvitationCustomer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/students/{id}/set-password": {
      "post": {
        "tags": [
          "Student (Customer)"
        ],
        "summary": "Set a one-time password for one of my students' logins.",
        "description": "Sets a one-time password on one of the signed-in customer's own students and forces the student to\nchoose their own at the next sign-in. This is how a student **without an email address** gets in\nat all — no magic link can reach them, so they sign in with their `loginNumber` plus this\npassword — and it is also the password reset, because the identity provider's self-service reset\nneeds a mailbox the student does not have.\n\nType the password and tell the student directly; nothing is mailed. Works for every one of your\nstudents, not only those without an address.\n\nOnly the customer's OWN students are reachable: another customer's student is `404`, never `403`.\nReturns `204` on success, `400` if the password is missing or shorter than 8 characters, `409` if\nthe student has no login account yet, and `502` if the identity provider could not be reached.",
        "operationId": "SetStudentPasswordCustomer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetPasswordPost"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/students/{id}/restore": {
      "post": {
        "tags": [
          "Student (Customer)"
        ],
        "summary": "Restore a soft-deleted student (customer).",
        "description": "Restores a previously soft-deleted student so it appears in normal listings again. Returns `204`,\nor `404` if no such student exists or it does not belong to the signed-in customer.",
        "operationId": "RestoreStudentCustomer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/courses": {
      "get": {
        "tags": [
          "Course (Customer)"
        ],
        "summary": "List every course relevant to the customer (catalog + enrolled + requested).",
        "description": "Returns the SUPERSET of courses relevant to the signed-in customer: the union of the open\ncatalog (group courses available for enrollment), courses the customer's own students are\nenrolled in, and courses the customer has an enrollment request for. Each `CourseGet` carries\nthree server-computed membership flags so the FE can tell the categories apart (they overlap):\n`IsAvailable` (in the open catalog), `IsEnrolled` (has one of your students) and `IsRequested`\n(you have a request for it). The customer-contextual data (`EnrolledStudents`,\n`EnrollmentRequests`, `EnrollmentStatus`, `Capacity`) is scoped to the signed-in customer; no\ninternal pricing or teacher-internal data is included. Each course also carries its `Lessons`\n(schedule: date/time, teacher, room, status, homework) — the enrolled students are NOT repeated\nper lesson, read them once from the course's `EnrolledStudents`. Use `/customer/courses/available` and\n`/customer/courses/my` for the pre-filtered subsets. Filter here with `searchTerm` (name and\ndescription), `courseTypeId`, `subjectId`, `levelId`, `statusId` (resolvable via `/lookups/…`)\nand the flag filters `isAvailable` / `isEnrolled` / `isRequested`.\n\nSupports pagination and sorting: send an optional `Range` request header (`0-49` = first 50,\n`-50` = last 50, `50` = from index 50; 0-based, end inclusive) plus the `orderBy` (a property\nname of the returned object, case-insensitive) and `desc` query parameters. The body is a plain\nJSON array; the total count is returned in the `Content-Range` response header\n(`items {start}-{end}/{total}`). Status is `206` when a `Range` is sent, `416` if the range is invalid.",
        "operationId": "GetCoursesCustomer",
        "parameters": [
          {
            "name": "SearchTerm",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ShowRemoved",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "CourseTypeId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "SubjectId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "LevelId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "StatusId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "IsAvailable",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "IsEnrolled",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "IsRequested",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "Range",
            "in": "header",
            "description": "Pagination window (zero-based, end inclusive): `{start}-{end}` e.g. `0-49`; `-{n}` = last n; `{n}` = first n. When set, the response is 206 with a `Content-Range` header.",
            "schema": {
              "type": "string",
              "example": "0-49"
            }
          },
          {
            "name": "orderBy",
            "in": "query",
            "description": "Sort by this result property name (case-insensitive). Unknown property → 400.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "desc",
            "in": "query",
            "description": "Sort descending when true (default false). Applied before pagination.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CourseGet"
                  }
                }
              }
            }
          },
          "206": {
            "description": "Partial Content — returned when a `Range` header is present. Body is the requested window.",
            "headers": {
              "Content-Range": {
                "description": "`items {start}-{end}/{total}` (empty page → `items */{total}`).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CourseGet"
                  }
                }
              }
            }
          },
          "416": {
            "description": "Range Not Satisfiable — the `Range` header is malformed or starts beyond the last item."
          }
        }
      }
    },
    "/customer/courses/available": {
      "get": {
        "tags": [
          "Course (Customer)"
        ],
        "summary": "List the public catalog of open group courses available for enrollment.",
        "description": "The catalog subset of `/customer/courses`: publicly-open group courses (status Created or\nStarted), shown regardless of whether the customer already has students enrolled or\nrequests pending. Full courses are not filtered out — read each `CourseGet`'s `Capacity`. Narrow\nwith `searchTerm`, `courseTypeId`, `subjectId`, `levelId`, `statusId` (resolvable via `/lookups/…`).\nPaginated/sortable via `Range` + `orderBy`/`desc` (see `/customer/courses`).",
        "operationId": "GetAvailableCoursesCustomer",
        "parameters": [
          {
            "name": "SearchTerm",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ShowRemoved",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "CourseTypeId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "SubjectId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "LevelId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "StatusId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Range",
            "in": "header",
            "description": "Pagination window (zero-based, end inclusive): `{start}-{end}` e.g. `0-49`; `-{n}` = last n; `{n}` = first n. When set, the response is 206 with a `Content-Range` header.",
            "schema": {
              "type": "string",
              "example": "0-49"
            }
          },
          {
            "name": "orderBy",
            "in": "query",
            "description": "Sort by this result property name (case-insensitive). Unknown property → 400.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "desc",
            "in": "query",
            "description": "Sort descending when true (default false). Applied before pagination.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CourseGet"
                  }
                }
              }
            }
          },
          "206": {
            "description": "Partial Content — returned when a `Range` header is present. Body is the requested window.",
            "headers": {
              "Content-Range": {
                "description": "`items {start}-{end}/{total}` (empty page → `items */{total}`).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CourseGet"
                  }
                }
              }
            }
          },
          "416": {
            "description": "Range Not Satisfiable — the `Range` header is malformed or starts beyond the last item."
          }
        }
      }
    },
    "/customer/courses/my": {
      "get": {
        "tags": [
          "Course (Customer)"
        ],
        "summary": "List courses the customer's own students are enrolled in (\"my courses\").",
        "description": "The enrolment subset of `/customer/courses`: courses in which the signed-in customer has\nenrolled students. Can include non-catalog courses the customer's students are in (e.g.\nprivate/duo). Only the customer's own students/requests are shown within each course. Filter with\n`searchTerm`, `courseTypeId`, `subjectId`, `statusId` and `studentId` to narrow to a specific one\nof your own students. Paginated/sortable via `Range` + `orderBy`/`desc` (see `/customer/courses`).",
        "operationId": "GetMyCoursesCustomer",
        "parameters": [
          {
            "name": "SearchTerm",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ShowRemoved",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "CourseTypeId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "SubjectId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "StatusId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "StudentId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Range",
            "in": "header",
            "description": "Pagination window (zero-based, end inclusive): `{start}-{end}` e.g. `0-49`; `-{n}` = last n; `{n}` = first n. When set, the response is 206 with a `Content-Range` header.",
            "schema": {
              "type": "string",
              "example": "0-49"
            }
          },
          {
            "name": "orderBy",
            "in": "query",
            "description": "Sort by this result property name (case-insensitive). Unknown property → 400.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "desc",
            "in": "query",
            "description": "Sort descending when true (default false). Applied before pagination.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CourseGet"
                  }
                }
              }
            }
          },
          "206": {
            "description": "Partial Content — returned when a `Range` header is present. Body is the requested window.",
            "headers": {
              "Content-Range": {
                "description": "`items {start}-{end}/{total}` (empty page → `items */{total}`).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CourseGet"
                  }
                }
              }
            }
          },
          "416": {
            "description": "Range Not Satisfiable — the `Range` header is malformed or starts beyond the last item."
          }
        }
      }
    },
    "/customer/courses/{id}": {
      "get": {
        "tags": [
          "Course (Customer)"
        ],
        "summary": "Get a single course by id (any course in the customer's superset).",
        "description": "Returns a single course by its id as a `CourseGet`, resolvable for any course in the customer's\nsuperset — the open catalog, one their students are enrolled in, OR one they have a request for —\nso every list (`/`, `/available`, `/my`) can open a detail view with the same id. Only the\ncustomer's own enrolled students and enrollment requests are shown within the course; the course's\n`Lessons` (schedule) are included without repeating the students per lesson; no internal pricing\nor teacher-internal data is included. Returns `404` if no such course exists or if it is not in\nthe signed-in customer's superset.",
        "operationId": "GetCourseCustomerById",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CourseGet"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/interests": {
      "get": {
        "tags": [
          "Interest (Customer)"
        ],
        "summary": "List interests (customer portal).",
        "description": "Returns the interests (tuition requests) the signed-in customer has raised for their own\nstudents — each an `InterestGet` with the language, level, interest type (Private, Group,\nCitizenship Preparation, Exam Preparation, Fide Test, Fide Information), status (Open, Done, Declined), desired schedule, requested\nstudents and an estimated price. Teacher applications against these interests are not visible to\nthe customer; the office matches teachers internally. Interests raised by other customers are\nnever returned. Soft-deleted interests are excluded by default. Filter with `searchTerm` (matches\nstudent, language and level), `studentId`, `languageId`, `levelId`, `interestTypeId`, `statusId`\n(resolvable via `/lookups/…`) and a `dateFrom` / `dateTo` overlap range.\n\nSupports pagination and sorting: send an optional `Range` request header (`0-49` = first 50,\n`-50` = last 50, `50` = from index 50; 0-based, end inclusive) plus the `orderBy` (a property\nname of the returned object, case-insensitive) and `desc` query parameters. The body is a plain\nJSON array; the total count is returned in the `Content-Range` response header\n(`items {start}-{end}/{total}`). Status is `206` when a `Range` is sent, `416` if the range is invalid.",
        "operationId": "GetInterestsCustomer",
        "parameters": [
          {
            "name": "SearchTerm",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ShowRemoved",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "StudentId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "LanguageId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "LevelId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "InterestTypeId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "StatusId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "DateFrom",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "DateTo",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "Range",
            "in": "header",
            "description": "Pagination window (zero-based, end inclusive): `{start}-{end}` e.g. `0-49`; `-{n}` = last n; `{n}` = first n. When set, the response is 206 with a `Content-Range` header.",
            "schema": {
              "type": "string",
              "example": "0-49"
            }
          },
          {
            "name": "orderBy",
            "in": "query",
            "description": "Sort by this result property name (case-insensitive). Unknown property → 400.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "desc",
            "in": "query",
            "description": "Sort descending when true (default false). Applied before pagination.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/InterestGet"
                  }
                }
              }
            }
          },
          "206": {
            "description": "Partial Content — returned when a `Range` header is present. Body is the requested window.",
            "headers": {
              "Content-Range": {
                "description": "`items {start}-{end}/{total}` (empty page → `items */{total}`).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/InterestGet"
                  }
                }
              }
            }
          },
          "416": {
            "description": "Range Not Satisfiable — the `Range` header is malformed or starts beyond the last item."
          }
        }
      },
      "post": {
        "tags": [
          "Interest (Customer)"
        ],
        "summary": "Raise a new interest for one of the customer's students.",
        "description": "Raises a new interest (tuition request) for one or more of the customer's own students from the\n`InterestPost` body and returns the created `InterestGet` (with its generated id and an Open\nstatus). The office then reviews it and matches a teacher. Returns `400` with validation details\nif the body is invalid or if a referenced student does not belong to the signed-in customer, and\n`409` when one of the students is currently INACTIVE (paused) — the response names them.",
        "operationId": "CreateInterestCustomer",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InterestPost"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InterestGet"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/interests/{id}": {
      "get": {
        "tags": [
          "Interest (Customer)"
        ],
        "summary": "Get a single interest by id.",
        "description": "Returns a single interest by its id as an `InterestGet`. Returns `404` if no such interest exists\nor if it was not raised by the signed-in customer.",
        "operationId": "GetInterestCustomerById",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InterestGet"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Interest (Customer)"
        ],
        "summary": "Partially update an open interest (or withdraw it).",
        "description": "Partially updates an existing interest (e.g. adjusting the desired schedule or notes, or\nwithdrawing it): only the fields present in the `InterestPatch` body are changed, the rest stay\nas they are. Returns the updated `InterestGet`. Returns `404` if no such interest exists or it\nwas not raised by the signed-in customer; `400` on validation errors.",
        "operationId": "UpdateInterestCustomer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InterestPatch"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InterestGet"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Interest (Customer)"
        ],
        "summary": "Delete an interest (soft by default; ?hard=true to hard-delete).",
        "description": "Deletes an interest. By default this is a soft delete — the interest is hidden from normal\nlistings but can be restored; pass `?hard=true` to remove it permanently. Returns `204`, or `404`\nif no such interest exists or it was not raised by the signed-in customer.",
        "operationId": "DeleteInterestCustomer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "hard",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/interests/{id}/restore": {
      "post": {
        "tags": [
          "Interest (Customer)"
        ],
        "summary": "Restore a soft-deleted interest.",
        "description": "Restores a previously soft-deleted interest so it appears in normal listings again. Returns `204`,\nor `404` if no such interest exists or it was not raised by the signed-in customer.",
        "operationId": "RestoreInterestCustomer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/lessons": {
      "get": {
        "tags": [
          "Lesson (Customer)"
        ],
        "summary": "List lessons (customer).",
        "description": "Returns the lessons attached to courses the signed-in customer's students are enrolled in — each\na `LessonGet` with date and time, course reference, teacher (name only) and room, computed status,\nhomework assignments, attendance records and `enrolledStudents` (the customer's OWN students in\nthe lesson's course, mirroring the `enrolledStudents` on the course view). Only the customer's own\ndata is shown: attendance records and enrolled students are limited to the customer's own students,\nand no salary, invoicing or teacher-internal fields are included. Lessons unrelated to the\ncustomer's students are never returned. Soft-deleted lessons are excluded by default. Filter with\n`searchTerm` (matches homework text and course name), `courseId`, a `dateFrom` / `dateTo` range\nand `isCancelled`.\n\nSupports pagination and sorting: send an optional `Range` request header (`0-49` = first 50,\n`-50` = last 50, `50` = from index 50; 0-based, end inclusive) plus the `orderBy` (a property\nname of the returned object, case-insensitive) and `desc` query parameters. The body is a plain\nJSON array; the total count is returned in the `Content-Range` response header\n(`items {start}-{end}/{total}`). Status is `206` when a `Range` is sent, `416` if the range is invalid.",
        "operationId": "GetLessonsCustomer",
        "parameters": [
          {
            "name": "SearchTerm",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ShowRemoved",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "CourseId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "DateFrom",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "DateTo",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "IsCancelled",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "Range",
            "in": "header",
            "description": "Pagination window (zero-based, end inclusive): `{start}-{end}` e.g. `0-49`; `-{n}` = last n; `{n}` = first n. When set, the response is 206 with a `Content-Range` header.",
            "schema": {
              "type": "string",
              "example": "0-49"
            }
          },
          {
            "name": "orderBy",
            "in": "query",
            "description": "Sort by this result property name (case-insensitive). Unknown property → 400.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "desc",
            "in": "query",
            "description": "Sort descending when true (default false). Applied before pagination.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/LessonGet"
                  }
                }
              }
            }
          },
          "206": {
            "description": "Partial Content — returned when a `Range` header is present. Body is the requested window.",
            "headers": {
              "Content-Range": {
                "description": "`items {start}-{end}/{total}` (empty page → `items */{total}`).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/LessonGet"
                  }
                }
              }
            }
          },
          "416": {
            "description": "Range Not Satisfiable — the `Range` header is malformed or starts beyond the last item."
          }
        }
      }
    },
    "/customer/lessons/{id}": {
      "get": {
        "tags": [
          "Lesson (Customer)"
        ],
        "summary": "Get a single lesson by id.",
        "description": "Returns a single lesson by its id as a `LessonGet`, with attendance and `enrolledStudents` limited\nto the customer's own students and no salary / teacher-internal fields. Returns `404` if no such\nlesson exists or if it does not belong to a course the signed-in customer's students are enrolled in.",
        "operationId": "GetLessonCustomerById",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LessonGet"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/invoices": {
      "get": {
        "tags": [
          "Invoice (Customer)"
        ],
        "summary": "List invoices (customer).",
        "description": "Returns the invoices addressed to the signed-in customer — each an `InvoiceGet` with title,\ninvoice number, issue and due date, payment status, total amount, line items and, when available,\na download link (`FileUrl`) for the invoice PDF. Two optional texts belong on the invoice and are\ntherefore included: `purchaseOrderNumber` (the customer's OWN order reference, so their accounts\ndepartment can match it) and `notes` (a remark the office printed on this invoice — why it was\ncorrected, what was agreed on the phone). This is a read-only view; invoices belonging to\nother customers are never returned. Soft-deleted invoices are excluded by default. Filter with\n`searchTerm` (matches title and invoice number), `statusId` (resolvable via `/lookups/…`),\nthe billing period via `periodYear` and/or `periodMonth` (each independent),\n`invoiceDateFrom` / `invoiceDateTo`, `dueDateFrom` / `dueDateTo` and a `minTotalAmount` /\n`maxTotalAmount` range.\n\nSupports pagination and sorting: send an optional `Range` request header (`0-49` = first 50,\n`-50` = last 50, `50` = from index 50; 0-based, end inclusive) plus the `orderBy` (a property\nname of the returned object, case-insensitive) and `desc` query parameters. The body is a plain\nJSON array; the total count is returned in the `Content-Range` response header\n(`items {start}-{end}/{total}`). Status is `206` when a `Range` is sent, `416` if the range is invalid.",
        "operationId": "GetInvoicesCustomer",
        "parameters": [
          {
            "name": "SearchTerm",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ShowRemoved",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "StatusId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "InvoiceDateFrom",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "InvoiceDateTo",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "DueDateFrom",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "DueDateTo",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "PeriodYear",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "PeriodMonth",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "MinTotalAmount",
            "in": "query",
            "schema": {
              "type": "number",
              "format": "double"
            }
          },
          {
            "name": "MaxTotalAmount",
            "in": "query",
            "schema": {
              "type": "number",
              "format": "double"
            }
          },
          {
            "name": "Range",
            "in": "header",
            "description": "Pagination window (zero-based, end inclusive): `{start}-{end}` e.g. `0-49`; `-{n}` = last n; `{n}` = first n. When set, the response is 206 with a `Content-Range` header.",
            "schema": {
              "type": "string",
              "example": "0-49"
            }
          },
          {
            "name": "orderBy",
            "in": "query",
            "description": "Sort by this result property name (case-insensitive). Unknown property → 400.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "desc",
            "in": "query",
            "description": "Sort descending when true (default false). Applied before pagination.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/InvoiceGet"
                  }
                }
              }
            }
          },
          "206": {
            "description": "Partial Content — returned when a `Range` header is present. Body is the requested window.",
            "headers": {
              "Content-Range": {
                "description": "`items {start}-{end}/{total}` (empty page → `items */{total}`).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/InvoiceGet"
                  }
                }
              }
            }
          },
          "416": {
            "description": "Range Not Satisfiable — the `Range` header is malformed or starts beyond the last item."
          }
        }
      }
    },
    "/customer/invoices/{id}": {
      "get": {
        "tags": [
          "Invoice (Customer)"
        ],
        "summary": "Get a single invoice by id.",
        "description": "Returns a single invoice by its id as an `InvoiceGet`, including its line items and download link.\nReturns `404` if no such invoice exists or if it is not addressed to the signed-in customer.",
        "operationId": "GetInvoiceCustomerById",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceGet"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/invoices/annual-overview": {
      "get": {
        "tags": [
          "Invoice (Customer)"
        ],
        "summary": "Annual invoice overview (customer).",
        "description": "Returns an aggregated yearly roll-up over the signed-in customer's own invoices for a single\nbilling-period year, as an `AnnualOverviewGet`: the year, the overall total amount and invoice\ncount, a per-month breakdown (`Months`), a per-status breakdown (`ByStatus`), and the underlying\ninvoices (`Invoices`). Like every customer invoice view it is read-only and identity-scoped —\nanother customer's invoices are never included.\n\nThe optional `year` query parameter selects the billing-period year; when omitted it defaults to\nthe current (UTC) year. A `year` outside the supported range (2000–2100) returns `400`.",
        "operationId": "GetInvoiceCustomerAnnualOverview",
        "parameters": [
          {
            "name": "year",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnnualOverviewGet"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/invoices/annual-overview.pdf": {
      "get": {
        "tags": [
          "Invoice (Customer)"
        ],
        "summary": "Annual invoice overview as PDF (customer).",
        "description": "Downloads the customer's annual invoice overview for a billing-period year as a PDF\n(`application/pdf`, filename `annual-overview-{year}.pdf`). The optional `year` query parameter\nselects the year and defaults to the current (UTC) year; a `year` outside 2000–2100 returns `400`.\n\nNOTE: PDF generation is not implemented yet — this currently returns an EMPTY placeholder file.\nThe real document (rendered from the same data as `GET /customer/invoices/annual-overview`) is a\nfollow-up. See the `annual-overview-pdf-todo` note.",
        "operationId": "GetInvoiceCustomerAnnualOverviewPdf",
        "parameters": [
          {
            "name": "year",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/budgets": {
      "get": {
        "tags": [
          "Budget (Customer)"
        ],
        "summary": "List budgets (customer).",
        "description": "Returns the budgets that involve the signed-in customer — i.e. budgets the customer funds\n(as sponsor) or receives and spends (as beneficiary) — each as a `BudgetGet` with its status\n(Active, Exhausted, Expired, Closed), total / consumed / remaining amount, item count and the\nsponsor and beneficiary references. Budgets belonging only to other parties are never returned.\nSoft-deleted budgets are excluded by default. Filter with `searchTerm` (matches the description\nand the sponsor / beneficiary display name), `sponsorCustomerId`, `beneficiaryCustomerId` and a\n`minTotalAmount` / `maxTotalAmount` range.\n\nA budget may carry an **average lesson price** (`averageLessonPrice`), from which\n`estimatedTotalLessons` / `estimatedRemainingLessons` follow. Those are an ESTIMATE and nothing is\nbilled from them — a lesson is charged at its own course's price on the day it was held, so the\nexact figures are the amounts beside them. Both are `null` when no average price is recorded, which\nis not the same as zero.\n\nSupports pagination and sorting: send an optional `Range` request header (`0-49` = first 50,\n`-50` = last 50, `50` = from index 50; 0-based, end inclusive) plus the `orderBy` (a property\nname of the returned object, case-insensitive) and `desc` query parameters. The body is a plain\nJSON array; the total count is returned in the `Content-Range` response header\n(`items {start}-{end}/{total}`). Status is `206` when a `Range` is sent, `416` if the range is invalid.",
        "operationId": "GetBudgetsCustomer",
        "parameters": [
          {
            "name": "SearchTerm",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ShowRemoved",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "SponsorCustomerId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "BeneficiaryCustomerId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "MinTotalAmount",
            "in": "query",
            "schema": {
              "type": "number",
              "format": "double"
            }
          },
          {
            "name": "MaxTotalAmount",
            "in": "query",
            "schema": {
              "type": "number",
              "format": "double"
            }
          },
          {
            "name": "Range",
            "in": "header",
            "description": "Pagination window (zero-based, end inclusive): `{start}-{end}` e.g. `0-49`; `-{n}` = last n; `{n}` = first n. When set, the response is 206 with a `Content-Range` header.",
            "schema": {
              "type": "string",
              "example": "0-49"
            }
          },
          {
            "name": "orderBy",
            "in": "query",
            "description": "Sort by this result property name (case-insensitive). Unknown property → 400.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "desc",
            "in": "query",
            "description": "Sort descending when true (default false). Applied before pagination.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/BudgetGet"
                  }
                }
              }
            }
          },
          "206": {
            "description": "Partial Content — returned when a `Range` header is present. Body is the requested window.",
            "headers": {
              "Content-Range": {
                "description": "`items {start}-{end}/{total}` (empty page → `items */{total}`).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/BudgetGet"
                  }
                }
              }
            }
          },
          "416": {
            "description": "Range Not Satisfiable — the `Range` header is malformed or starts beyond the last item."
          }
        }
      },
      "post": {
        "tags": [
          "Budget (Customer)"
        ],
        "summary": "Create a budget (company customers only) assigned to an employee by email.",
        "description": "Creates a new budget from the `BudgetPost` body and returns the created `BudgetGet` (with its\ngenerated id). This is a company-customer feature: a company funds a budget and assigns it to one\nof its employees (identified by email), who becomes the beneficiary that can spend it on lessons\nand materials. The company MAY name its own address — a budget funded for its own tuition is an\nordinary case.\n\n**`averageLessonPrice`** is optional: what one lesson is expected to cost on average, which is what\nlets the budget report a number of lessons and what the \"budget running low\" letter states. Nothing\nis billed from it, and a negative amount is `400`.\n\nReturns `403` when the signed-in customer is a private person rather than a company, and `400` with\nvalidation details if the body is invalid.",
        "operationId": "CreateBudgetCustomer",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BudgetPost"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BudgetGet"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/budgets/{id}": {
      "get": {
        "tags": [
          "Budget (Customer)"
        ],
        "summary": "Get a single budget by id.",
        "description": "Returns a single budget by its id as a `BudgetGet`. Returns `404` if no such budget exists or if\nit does not involve the signed-in customer (as sponsor or beneficiary).",
        "operationId": "GetBudgetCustomerById",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BudgetGet"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/packages": {
      "get": {
        "tags": [
          "Package (Customer)"
        ],
        "summary": "List packages (customer).",
        "description": "Returns the package catalog — the lesson bundles a customer can purchase — each a `PackageGet`\nwith its marketing title, description, sale price (CHF) and the credit it provides. This is a\npublic catalog, the same for every customer and not restricted to any one account; it is\nread-only (customers buy via `/customer/package-orders`, they cannot create packages).\nSoft-deleted packages are excluded by default. Filter with `searchTerm` (matches title, billing\ntitle and description), a `minPrice` / `maxPrice` range and a `minCredit` / `maxCredit` range.\n\n**This list is the CATALOGUE: what is on offer.** A DRAFT package is left out — its wording and\nabove all its price are still provisional, and a package bought at a provisional price cannot be\nun-bought. A PRIVATE package is left out too: the office arranges one with a single customer, so it\nis not on sale to anybody. Neither can be purchased through `/customer/package-purchases` either —\nthe checkout answers `400` and names the package.\n\nA private package the customer ALREADY HOLDS stays out of this list (they cannot order another) but\nIS readable by id — see `GET /customer/packages/{id}`.\n\nSupports pagination and sorting: send an optional `Range` request header (`0-49` = first 50,\n`-50` = last 50, `50` = from index 50; 0-based, end inclusive) plus the `orderBy` (a property\nname of the returned object, case-insensitive) and `desc` query parameters. The body is a plain\nJSON array; the total count is returned in the `Content-Range` response header\n(`items {start}-{end}/{total}`). Status is `206` when a `Range` is sent, `416` if the range is invalid.",
        "operationId": "GetPackagesCustomer",
        "parameters": [
          {
            "name": "SearchTerm",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ShowRemoved",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "MinPrice",
            "in": "query",
            "schema": {
              "type": "number",
              "format": "double"
            }
          },
          {
            "name": "MaxPrice",
            "in": "query",
            "schema": {
              "type": "number",
              "format": "double"
            }
          },
          {
            "name": "MinCredit",
            "in": "query",
            "schema": {
              "type": "number",
              "format": "double"
            }
          },
          {
            "name": "MaxCredit",
            "in": "query",
            "schema": {
              "type": "number",
              "format": "double"
            }
          },
          {
            "name": "Range",
            "in": "header",
            "description": "Pagination window (zero-based, end inclusive): `{start}-{end}` e.g. `0-49`; `-{n}` = last n; `{n}` = first n. When set, the response is 206 with a `Content-Range` header.",
            "schema": {
              "type": "string",
              "example": "0-49"
            }
          },
          {
            "name": "orderBy",
            "in": "query",
            "description": "Sort by this result property name (case-insensitive). Unknown property → 400.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "desc",
            "in": "query",
            "description": "Sort descending when true (default false). Applied before pagination.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PackageGet"
                  }
                }
              }
            }
          },
          "206": {
            "description": "Partial Content — returned when a `Range` header is present. Body is the requested window.",
            "headers": {
              "Content-Range": {
                "description": "`items {start}-{end}/{total}` (empty page → `items */{total}`).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PackageGet"
                  }
                }
              }
            }
          },
          "416": {
            "description": "Range Not Satisfiable — the `Range` header is malformed or starts beyond the last item."
          }
        }
      }
    },
    "/customer/packages/{id}": {
      "get": {
        "tags": [
          "Package (Customer)"
        ],
        "summary": "Get a single package by id.",
        "description": "Returns a single package by its id as a `PackageGet`.\n\nReadable is **what is on the catalogue, plus any package this customer already holds an order on** —\ndeliberately wider than the list. A PRIVATE package linked to them behaves like any other one here\n(title, credit, everything the consumption display needs): the office arranged that package for\nthem, so withholding it would leave them an order they can spend and cannot read. It still does not\nappear in the catalogue list and still cannot be bought.\n\nReturns `404` if no such package exists, and for a DRAFT or a PRIVATE package the customer has\nnothing to do with — so the by-id read is no way around the catalogue.",
        "operationId": "GetPackageCustomerById",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PackageGet"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/course-prices": {
      "get": {
        "tags": [
          "CoursePrice (Customer)"
        ],
        "summary": "List private-lesson prices (customer portal).",
        "description": "Returns the per-lesson rate card the customer needs to price a private-lesson request\n(the \"Request private lessons\" flow), each a `CoursePriceGet` with the teaching level,\ncourse type, whether the rate is for children and the price per lesson (CHF). Only\nPRIVATE-LESSON course types are ever returned — Private (one-to-one) and Duo\n(semi-private, group of two); group-course prices are office-internal and never exposed\nto the customer. This is a public rate card, the same for every customer and not\nrestricted to any one account; it is read-only. Soft-deleted rows are excluded by\ndefault. Filter with `searchTerm` (matches the custom product name), `levelId`,\n`courseTypeId` (restricted to Private/Duo), `isForChildren` and a `priceMin`/`priceMax`\nrange; the enum ids come from the matching `/lookups/...` endpoints.\n\nSupports pagination and sorting: send an optional `Range` request header (`0-49` = first 50,\n`-50` = last 50, `50` = from index 50; 0-based, end inclusive) plus the `orderBy` (a property\nname of the returned object, case-insensitive) and `desc` query parameters. The body is a plain\nJSON array; the total count is returned in the `Content-Range` response header\n(`items {start}-{end}/{total}`). Status is `206` when a `Range` is sent, `416` if the range is invalid.",
        "operationId": "GetCoursePricesCustomer",
        "parameters": [
          {
            "name": "SearchTerm",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ShowRemoved",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "LevelId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "CourseTypeId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "IsForChildren",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "PriceMin",
            "in": "query",
            "schema": {
              "type": "number",
              "format": "double"
            }
          },
          {
            "name": "PriceMax",
            "in": "query",
            "schema": {
              "type": "number",
              "format": "double"
            }
          },
          {
            "name": "Range",
            "in": "header",
            "description": "Pagination window (zero-based, end inclusive): `{start}-{end}` e.g. `0-49`; `-{n}` = last n; `{n}` = first n. When set, the response is 206 with a `Content-Range` header.",
            "schema": {
              "type": "string",
              "example": "0-49"
            }
          },
          {
            "name": "orderBy",
            "in": "query",
            "description": "Sort by this result property name (case-insensitive). Unknown property → 400.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "desc",
            "in": "query",
            "description": "Sort descending when true (default false). Applied before pagination.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CoursePriceGet"
                  }
                }
              }
            }
          },
          "206": {
            "description": "Partial Content — returned when a `Range` header is present. Body is the requested window.",
            "headers": {
              "Content-Range": {
                "description": "`items {start}-{end}/{total}` (empty page → `items */{total}`).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CoursePriceGet"
                  }
                }
              }
            }
          },
          "416": {
            "description": "Range Not Satisfiable — the `Range` header is malformed or starts beyond the last item."
          }
        }
      }
    },
    "/customer/course-prices/{id}": {
      "get": {
        "tags": [
          "CoursePrice (Customer)"
        ],
        "summary": "Get a single private-lesson price by id.",
        "description": "Returns a single private-lesson rate by its id as a `CoursePriceGet`. Returns `404` if no\nsuch rate exists or if it is not a private-lesson (Private/Duo) row — group-course prices\nare not addressable from the customer portal.",
        "operationId": "GetCoursePriceCustomerById",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CoursePriceGet"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/package-orders": {
      "get": {
        "tags": [
          "PackageOrder (Customer)"
        ],
        "summary": "List package orders (customer).",
        "description": "Returns the package orders (purchases) that belong to the signed-in customer — orders the\ncustomer either bought or received from another customer — each a `PackageOrderGet` with its\nstatus, the underlying catalog package, the credit used and remaining, per-student consumption\nbreakdown, the booked lessons and any pass-on / assignment info. Orders belonging only to other\ncustomers are never returned. Soft-deleted orders are excluded by default. Filter with\n`searchTerm` (matches the order and package title), `statusId`, `packageId` (resolvable via\n`/lookups/…`) and a `minUsedCredit` / `maxUsedCredit` range.\n\n**A SETTLED order (`settledAt` set) is closed for booking.** Its `remainingCredit` is no longer\ncredit the customer can spend — it is money coming back to them as a credit on the next invoice,\nand `residualCredit` reports exactly that amount (null while the package is still open). Present\nthe two differently: the same number means opposite things before and after settlement, and\nshowing a settled package's remainder as available lessons offers something that can no longer be\nbooked.\n\nSupports pagination and sorting: send an optional `Range` request header (`0-49` = first 50,\n`-50` = last 50, `50` = from index 50; 0-based, end inclusive) plus the `orderBy` (a property\nname of the returned object, case-insensitive) and `desc` query parameters. The body is a plain\nJSON array; the total count is returned in the `Content-Range` response header\n(`items {start}-{end}/{total}`). Status is `206` when a `Range` is sent, `416` if the range is invalid.",
        "operationId": "GetPackageOrdersCustomer",
        "parameters": [
          {
            "name": "SearchTerm",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ShowRemoved",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "StatusId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "PackageId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Range",
            "in": "header",
            "description": "Pagination window (zero-based, end inclusive): `{start}-{end}` e.g. `0-49`; `-{n}` = last n; `{n}` = first n. When set, the response is 206 with a `Content-Range` header.",
            "schema": {
              "type": "string",
              "example": "0-49"
            }
          },
          {
            "name": "orderBy",
            "in": "query",
            "description": "Sort by this result property name (case-insensitive). Unknown property → 400.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "desc",
            "in": "query",
            "description": "Sort descending when true (default false). Applied before pagination.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PackageOrderGet"
                  }
                }
              }
            }
          },
          "206": {
            "description": "Partial Content — returned when a `Range` header is present. Body is the requested window.",
            "headers": {
              "Content-Range": {
                "description": "`items {start}-{end}/{total}` (empty page → `items */{total}`).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PackageOrderGet"
                  }
                }
              }
            }
          },
          "416": {
            "description": "Range Not Satisfiable — the `Range` header is malformed or starts beyond the last item."
          }
        }
      }
    },
    "/customer/package-orders/{id}": {
      "get": {
        "tags": [
          "PackageOrder (Customer)"
        ],
        "summary": "Get a single package order by id.",
        "description": "Returns a single package order by its id as a `PackageOrderGet`, including credit usage and booked\nlessons. Returns `404` if no such order exists or if it does not belong to the signed-in customer\n(as buyer or recipient).",
        "operationId": "GetPackageOrderCustomerById",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PackageOrderGet"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/package-orders/{id}/refundable-amount": {
      "get": {
        "tags": [
          "PackageOrder (Customer)"
        ],
        "summary": "Get the refundable amount for a package order (customer).",
        "description": "Returns how much of the package order could currently be refunded as a `RefundableAmountGet`.\nA refund can be requested only when `refundableAmount` is greater than 0.\n\n⚠️ PLACEHOLDER: the concrete refund calculation is NOT yet implemented. This endpoint currently\nreturns a fixed positive stub and sets `isPlaceholder = true`; treat the amount as indicative\nonly. The real amount (used lessons charged at the standard rate, non-refundable fees, materials\nbilled separately, …) is still to be defined — see the TODO in `PackageOrderCrudService`.\n\nReturns `404` if no such order exists or it does not belong to the signed-in customer.",
        "operationId": "GetPackageOrderRefundableAmountCustomer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RefundableAmountGet"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/package-orders/{id}/request-refund": {
      "post": {
        "tags": [
          "PackageOrder (Customer)"
        ],
        "summary": "Request a refund for a package order (customer).",
        "description": "Submits a refund request for the customer's own package order and returns the updated\n`PackageOrderGet` (now in the `RefundRequested` status, with `refundRequestedAt` stamped). The\noffice subsequently fulfils the request (→ `Refunded`) or declines it; the customer is notified\nof the outcome. Only a PERSONAL package the customer purchased (not one passed on to / received\nfrom someone else) in the PAID status with a positive refundable amount can be refunded.\n\nReturns `404` if no such order exists or it does not belong to the signed-in customer, and `400`\nif a business rule rejects the request (not personal, wrong status, already requested/refunded,\nor nothing left to refund).",
        "operationId": "RequestPackageOrderRefundCustomer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PackageOrderGet"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/package-purchases": {
      "get": {
        "tags": [
          "PackagePurchase (Customer)"
        ],
        "summary": "List the signed-in customer's package purchases.",
        "description": "Returns the package purchases (checkouts) made by the signed-in customer, each a\n`PackagePurchaseGet` with the member package orders bought together, whether the bracket is\nFINISHED (`isCompleted`) and computed item count / total price. A purchase has no status of its\nown — `isCompleted` is derived from its packages and means none of them is `Ordered` or `Invoiced`\nany more (a refunded, settled or cancelled package counts as done); the state of an individual\npackage is on the package itself. Purchases belonging to other customers are never returned, and\npurchases with no remaining orders (all removed) are not listed. Soft-deleted purchases are\nexcluded by default. Filter with `isCompleted` (`false` = still open, `true` = finished, omit for\nboth).\n\nSupports pagination and sorting: send an optional `Range` request header (`0-49` = first 50,\n`-50` = last 50, `50` = from index 50; 0-based, end inclusive) plus the `orderBy` and `desc` query\nparameters. The body is a plain JSON array; the total count is returned in the `Content-Range`\nresponse header. Status is `206` when a `Range` is sent, `416` if the range is invalid.",
        "operationId": "GetPackagePurchasesCustomer",
        "parameters": [
          {
            "name": "SearchTerm",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ShowRemoved",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "IsCompleted",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "Range",
            "in": "header",
            "description": "Pagination window (zero-based, end inclusive): `{start}-{end}` e.g. `0-49`; `-{n}` = last n; `{n}` = first n. When set, the response is 206 with a `Content-Range` header.",
            "schema": {
              "type": "string",
              "example": "0-49"
            }
          },
          {
            "name": "orderBy",
            "in": "query",
            "description": "Sort by this result property name (case-insensitive). Unknown property → 400.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "desc",
            "in": "query",
            "description": "Sort descending when true (default false). Applied before pagination.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PackagePurchaseGet"
                  }
                }
              }
            }
          },
          "206": {
            "description": "Partial Content — returned when a `Range` header is present. Body is the requested window.",
            "headers": {
              "Content-Range": {
                "description": "`items {start}-{end}/{total}` (empty page → `items */{total}`).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PackagePurchaseGet"
                  }
                }
              }
            }
          },
          "416": {
            "description": "Range Not Satisfiable — the `Range` header is malformed or starts beyond the last item."
          }
        }
      },
      "post": {
        "tags": [
          "PackagePurchase (Customer)"
        ],
        "summary": "Purchase one or more packages (checkout).",
        "description": "Buys the packages listed in the `PackagePurchasePost` body in a single atomic checkout. The buying\ncustomer (payer) is taken from the session; each item may optionally assign its package to another\ncustomer by email. All package orders are created together under one purchase header; because\npackages are prepaid, one prepayment invoice is raised for the whole purchase and every order on it\nmoves to `Invoiced` in the same save. Returns the created `PackagePurchaseGet`. Returns `400` with\nvalidation details if the body is invalid (e.g. an empty basket or an invalid beneficiary email).\n\n**Only what is on the catalogue may be bought.** A DRAFT package (still being priced) and a PRIVATE\none (an arrangement the office made with a single customer) are each refused with `400`, and the\nmessage names the package. That holds even for a private package the customer already HOLDS — they\nmay read that one, but not order another.\n\nAn item's `beneficiaryCustomerEmail` is RESOLVED at checkout: if the address belongs to a customer,\nthe order is assigned to them (`assignedToCustomerId`, which is what makes the package visible in\nthat customer's portal) and the address is cleared; if it belongs to nobody, it is kept as a\npending note and completed later, when a customer is created with — or renamed to — that address.\nThe assignment type (`passedOnType`) is DERIVED from the result and needs not be sent.\nAssigning an item to your OWN address is rejected with `400` — that is not a pass-on, and it would\nblock your own refund.",
        "operationId": "CreatePackagePurchaseCustomer",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PackagePurchasePost"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PackagePurchaseGet"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/package-purchases/{id}": {
      "get": {
        "tags": [
          "PackagePurchase (Customer)"
        ],
        "summary": "Get a single package purchase by id.",
        "description": "Returns a single package purchase by its id as a `PackagePurchaseGet`, including its member\npackage orders. Returns `404` if no such purchase exists or it does not belong to the signed-in\ncustomer.",
        "operationId": "GetPackagePurchaseCustomerById",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PackagePurchaseGet"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/student-invites": {
      "get": {
        "tags": [
          "StudentInvite (Customer)"
        ],
        "summary": "List student invites (customer).",
        "description": "Returns the course invitations addressed to students that belong to the signed-in customer — each\na `StudentInviteGet` with the invited student and course, the invitation status (Pending,\nAccepted, Declined), timestamps and the material-choice workflow (per-material confirmation,\nchosen delivery method and address). Invitations for other customers' students are never\nreturned. Soft-deleted invites are excluded by default. Filter with `searchTerm` (matches student\nand course display names), `courseId`, `studentId` and `statusId` (resolvable via `/lookups/…`).\n\nSupports pagination and sorting: send an optional `Range` request header (`0-49` = first 50,\n`-50` = last 50, `50` = from index 50; 0-based, end inclusive) plus the `orderBy` (a property\nname of the returned object, case-insensitive) and `desc` query parameters. The body is a plain\nJSON array; the total count is returned in the `Content-Range` response header\n(`items {start}-{end}/{total}`). Status is `206` when a `Range` is sent, `416` if the range is invalid.",
        "operationId": "GetStudentInvitesCustomer",
        "parameters": [
          {
            "name": "SearchTerm",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ShowRemoved",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "CourseId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "StudentId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "StatusId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Range",
            "in": "header",
            "description": "Pagination window (zero-based, end inclusive): `{start}-{end}` e.g. `0-49`; `-{n}` = last n; `{n}` = first n. When set, the response is 206 with a `Content-Range` header.",
            "schema": {
              "type": "string",
              "example": "0-49"
            }
          },
          {
            "name": "orderBy",
            "in": "query",
            "description": "Sort by this result property name (case-insensitive). Unknown property → 400.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "desc",
            "in": "query",
            "description": "Sort descending when true (default false). Applied before pagination.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/StudentInviteGet"
                  }
                }
              }
            }
          },
          "206": {
            "description": "Partial Content — returned when a `Range` header is present. Body is the requested window.",
            "headers": {
              "Content-Range": {
                "description": "`items {start}-{end}/{total}` (empty page → `items */{total}`).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/StudentInviteGet"
                  }
                }
              }
            }
          },
          "416": {
            "description": "Range Not Satisfiable — the `Range` header is malformed or starts beyond the last item."
          }
        }
      }
    },
    "/customer/student-invites/{id}": {
      "get": {
        "tags": [
          "StudentInvite (Customer)"
        ],
        "summary": "Get a single student invite by id.",
        "description": "Returns a single student invitation by its id as a `StudentInviteGet`, including its material\nchoices. Returns `404` if no such invitation exists or if it is not addressed to a student of\nthe signed-in customer.",
        "operationId": "GetStudentInviteCustomerById",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StudentInviteGet"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "StudentInvite (Customer)"
        ],
        "summary": "Accept or decline an invitation and submit material choices (customer).",
        "description": "Responds to a course invitation for one of the customer's students: only the fields present in\nthe `StudentInvitePatch` body are changed — typically accepting or declining the invitation and\nsubmitting the material choices (per-material confirmation, delivery method and address). Returns\nthe updated `StudentInviteGet`. Returns `404` if no such invitation exists or it is not addressed\nto a student of the signed-in customer; `400` on validation errors.\n\nAccepting ENROLS the student, so it answers `409` when the course has meanwhile become **full** —\nplaces are counted as everybody enrolled plus everybody holding an open invitation, and the\ninvitee's own invitation holds theirs, so this only fires when the places were taken after it went\nout (the office overbooking, or a lowered maximum).\n\nAccepting requires an answer for **every** article on the material list, and every article the\nstudent does not already own is then ordered. **How that material is delivered may be stated\neither way**: per article in `materialChoices[].deliveryMethodId`, or once for the whole\nconfirmation in the top-level `deliveryMethodId` — the per-article value wins, then the one for\nthe whole confirmation, then whatever the invitation already holds from an earlier round. An\narticle that ends up with no delivery method at all is a `400` naming it. If anything goes by\nmail, a `deliveryAddress` is required unless the invitation already carries one.\n\n`alreadyInPossession` is **required** per article — omitting it is a `400`, never a silent \"please\norder it\". `false` is the only value that creates or changes an order, and what it does depends on\nthe article's state: while its order line is still `confirmed` it REVISES that line (change the\ndelivery method, or `true` withdraws it) — the same article never produces a second order that way.\nOnce the office has marked the line `ordered`/`delivered` the article reads back as\n`alreadyInPossession: true`, so a `false` there is a deliberate RE-ORDER of a lost or damaged book\nand is charged again; sending `true` for it changes nothing.",
        "operationId": "UpdateStudentInviteCustomer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StudentInvitePatch"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StudentInviteGet"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/notifications": {
      "get": {
        "tags": [
          "Notification (Customer)"
        ],
        "summary": "List notifications (customer).",
        "description": "Returns the notifications addressed to the signed-in customer — each a `NotificationGet` with the\nissue date, message, read state, category (used for icon/grouping), an optional deep-link URL and,\nwhen the notification concerns one of the customer's students, a reference to that student.\nNotifications for other parties, including the customer's own students, are never returned: each\nrecipient has their own inbox. Soft-deleted notifications are excluded by default.\n\nThe message and the deep-link URL are COMPOSED per request from the notification's key and the\nrecords it references, not stored — so a renamed student or course, or a changed portal route, is\nreflected in notifications that already exist.\n\nFilter with `typeId` / `keyId` (resolvable via `/lookups/notification-type` and\n`/lookups/notification-key`) and `isRead`. **`searchTerm` is not supported here** and is ignored:\nsince the message is composed rather than stored, there is no text column to search, and filtering\nafter the fact would break the pagination contract below.\n\nSupports pagination and sorting: send an optional `Range` request header (`0-49` = first 50,\n`-50` = last 50, `50` = from index 50; 0-based, end inclusive) plus the `orderBy` (a property\nname of the returned object, case-insensitive) and `desc` query parameters. The body is a plain\nJSON array; the total count is returned in the `Content-Range` response header\n(`items {start}-{end}/{total}`). Status is `206` when a `Range` is sent, `416` if the range is invalid.",
        "operationId": "GetNotificationsCustomer",
        "parameters": [
          {
            "name": "SearchTerm",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ShowRemoved",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "TypeId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "KeyId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "IsRead",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "Range",
            "in": "header",
            "description": "Pagination window (zero-based, end inclusive): `{start}-{end}` e.g. `0-49`; `-{n}` = last n; `{n}` = first n. When set, the response is 206 with a `Content-Range` header.",
            "schema": {
              "type": "string",
              "example": "0-49"
            }
          },
          {
            "name": "orderBy",
            "in": "query",
            "description": "Sort by this result property name (case-insensitive). Unknown property → 400.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "desc",
            "in": "query",
            "description": "Sort descending when true (default false). Applied before pagination.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/NotificationGet"
                  }
                }
              }
            }
          },
          "206": {
            "description": "Partial Content — returned when a `Range` header is present. Body is the requested window.",
            "headers": {
              "Content-Range": {
                "description": "`items {start}-{end}/{total}` (empty page → `items */{total}`).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/NotificationGet"
                  }
                }
              }
            }
          },
          "416": {
            "description": "Range Not Satisfiable — the `Range` header is malformed or starts beyond the last item."
          }
        }
      }
    },
    "/customer/notifications/{id}": {
      "get": {
        "tags": [
          "Notification (Customer)"
        ],
        "summary": "Get a single notification by id.",
        "description": "Returns a single notification by its id as a `NotificationGet`. Returns `404` if no such\nnotification exists or if it is not addressed to the signed-in customer or one of their students.",
        "operationId": "GetNotificationCustomerById",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationGet"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Notification (Customer)"
        ],
        "summary": "Mark a notification as read/unread (customer).",
        "description": "Updates the read state of one of the customer's notifications: only the fields present in the\n`NotificationPatch` body are changed (typically the read/unread flag). Returns the updated\n`NotificationGet`. Returns `404` if no such notification exists or it is not addressed to the\nsigned-in customer or one of their students; `400` on validation errors.",
        "operationId": "UpdateNotificationCustomer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NotificationPatch"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationGet"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/notifications/unread-count": {
      "get": {
        "tags": [
          "Notification (Customer)"
        ],
        "summary": "Count the customer's unread notifications.",
        "description": "Returns how many of the signed-in customer's notifications are currently unread, as\n`{ \"unread\": n }`. Intended for a badge or bell indicator: it answers the same question as\nlisting with `isRead=false` but transfers only the number instead of the notifications.\nNotifications addressed to anybody else — including the customer's own students, who have\ntheir own inbox — are never counted.",
        "operationId": "GetNotificationUnreadCountCustomer",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationUnreadCountGet"
                }
              }
            }
          }
        }
      }
    },
    "/customer/notifications/mark-all-read": {
      "post": {
        "tags": [
          "Notification (Customer)"
        ],
        "summary": "Mark all of the customer's notifications as read.",
        "description": "Marks every unread notification of the signed-in customer as read and returns\n`{ \"updated\": n }` — the number of notifications that actually changed. Already-read\nnotifications are not counted, so calling this twice reports `0` the second time. Only the\ncustomer's own inbox is affected; their students' notifications are untouched.",
        "operationId": "MarkAllNotificationsReadCustomer",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationMarkReadResultGet"
                }
              }
            }
          }
        }
      }
    },
    "/customer/notifications/mark-read": {
      "post": {
        "tags": [
          "Notification (Customer)"
        ],
        "summary": "Mark several notifications as read (customer).",
        "description": "Marks the notifications named in the `NotificationMarkReadPost` body (`ids`) as read and\nreturns `{ \"updated\": n }` — the number that actually changed. Ids that are unknown, already\nread, or addressed to somebody else match nothing and are ignored rather than reported\nindividually, so the response cannot be used to probe for other people's notifications.\nReturns `400` when `ids` is missing, empty, contains an empty Guid, or exceeds the per-request\nlimit.",
        "operationId": "MarkNotificationsReadCustomer",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NotificationMarkReadPost"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationMarkReadResultGet"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/enrollment-requests": {
      "get": {
        "tags": [
          "EnrollmentRequest (Customer)"
        ],
        "summary": "List the current customer's course enrollment requests.",
        "description": "Returns the course enrollment requests submitted by the signed-in customer — each a\n`CourseEnrollmentRequestGet` with its status, request date, the requested students (from the\ncustomer's own list), any notes and, on this standalone list, the full customer-portal view of\nthe requested course so the \"requested courses\" screen renders without a second lookup. Requests\nsubmitted by other customers are never returned. Soft-deleted requests are excluded by default.\nFilter with `searchTerm` (matches notes, requester and student names), `courseId`,\n`requestingCustomerId` and `statusId` (resolvable via `/lookups/…`).\n\nSupports pagination and sorting: send an optional `Range` request header (`0-49` = first 50,\n`-50` = last 50, `50` = from index 50; 0-based, end inclusive) plus the `orderBy` (a property\nname of the returned object, case-insensitive) and `desc` query parameters. The body is a plain\nJSON array; the total count is returned in the `Content-Range` response header\n(`items {start}-{end}/{total}`). Status is `206` when a `Range` is sent, `416` if the range is invalid.",
        "operationId": "GetEnrollmentRequestsCustomer",
        "parameters": [
          {
            "name": "SearchTerm",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "ShowRemoved",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "CourseId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "RequestingCustomerId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "StatusId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Range",
            "in": "header",
            "description": "Pagination window (zero-based, end inclusive): `{start}-{end}` e.g. `0-49`; `-{n}` = last n; `{n}` = first n. When set, the response is 206 with a `Content-Range` header.",
            "schema": {
              "type": "string",
              "example": "0-49"
            }
          },
          {
            "name": "orderBy",
            "in": "query",
            "description": "Sort by this result property name (case-insensitive). Unknown property → 400.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "desc",
            "in": "query",
            "description": "Sort descending when true (default false). Applied before pagination.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CourseEnrollmentRequestGet"
                  }
                }
              }
            }
          },
          "206": {
            "description": "Partial Content — returned when a `Range` header is present. Body is the requested window.",
            "headers": {
              "Content-Range": {
                "description": "`items {start}-{end}/{total}` (empty page → `items */{total}`).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CourseEnrollmentRequestGet"
                  }
                }
              }
            }
          },
          "416": {
            "description": "Range Not Satisfiable — the `Range` header is malformed or starts beyond the last item."
          }
        }
      },
      "post": {
        "tags": [
          "EnrollmentRequest (Customer)"
        ],
        "summary": "Submit a course enrollment request.",
        "description": "Submits a request to enrol one or more of the customer's own students into an existing course,\nfrom the `CourseEnrollmentRequestPost` body, and returns the created `CourseEnrollmentRequestGet`\n(with its generated id and an open status; the office reviews and accepts or declines it). Returns\n`400` with validation details if the body is invalid or if a referenced course or student does\nnot belong to / is not accessible by the signed-in customer, and `409` when one of the requested\nstudents is currently INACTIVE (paused) — the response names them.",
        "operationId": "CreateEnrollmentRequestCustomer",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CourseEnrollmentRequestPost"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CourseEnrollmentRequestGet"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/enrollment-requests/{id}": {
      "get": {
        "tags": [
          "EnrollmentRequest (Customer)"
        ],
        "summary": "Get a single course enrollment request by id (customer).",
        "description": "Returns a single course enrollment request by its id as a `CourseEnrollmentRequestGet`. Returns\n`404` if no such request exists or if it was not submitted by the signed-in customer.",
        "operationId": "GetEnrollmentRequestCustomerById",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CourseEnrollmentRequestGet"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "EnrollmentRequest (Customer)"
        ],
        "summary": "Update or withdraw a course enrollment request.",
        "description": "Partially updates an existing enrollment request (e.g. adjusting the requested students or notes,\nor withdrawing the request): only the fields present in the `CourseEnrollmentRequestPatch` body\nare changed, the rest stay as they are. Returns the updated `CourseEnrollmentRequestGet`. Returns\n`404` if no such request exists or it was not submitted by the signed-in customer; `400` on\nvalidation errors.",
        "operationId": "UpdateEnrollmentRequestCustomer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CourseEnrollmentRequestPatch"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CourseEnrollmentRequestGet"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/myprofile": {
      "get": {
        "tags": [
          "Customer MyProfile"
        ],
        "summary": "Get the signed-in customer's own profile.",
        "description": "Returns the signed-in customer's own account as a `CustomerGet` — customer type, company name,\ncorrespondence language, contact person, billing address, the profile-confirmation flag, the\ncustomer's students and their own `loginNumber` (the 10-digit name they sign in with; the email is\nonly a contact detail). Office-internal fields are excluded. The account is resolved from the signed-in\nuser; no id is taken from the client. Returns `404` if the signed-in user has no linked customer\nrecord.",
        "operationId": "GetCustomerMyProfile",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerGet"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Customer MyProfile"
        ],
        "summary": "Partially update the signed-in customer's own profile (reduced self-edit DTO).",
        "description": "Partially updates the signed-in customer's own profile from the reduced `MyProfilePatch` body:\nonly the fields present are changed. This self-edit surface is limited to person details,\ncommunication, billing address, correspondence language, the profile-confirmation flag AND the own\nEMAIL address — company name, VAT number, notes and activity status stay office-only. A changed\nemail is refused with `409` when another record already uses it, and is carried through to the\nlogin account (whose login NUMBER never changes). Returns the\nupdated `CustomerGet`. The account is resolved from the signed-in user; returns `404` if the\nsigned-in user has no linked customer record, and `400` on validation errors.",
        "operationId": "UpdateCustomerMyProfile",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MyProfilePatch"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerGet"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/customer/myprofile/reset-password": {
      "post": {
        "tags": [
          "Customer MyProfile"
        ],
        "summary": "Send the signed-in customer their own password-reset link.",
        "description": "Triggers the identity provider's password-reset mail for the signed-in customer's own login. The\nlink goes to the address on their record and is rendered and delivered by Keycloak itself — this\napplication never learns or sets the password.\n\nReturns `204` once the mail was handed over. `400` if the record has no email address (there is\nnowhere to send it), `409` if the record has no login account yet (it is invited first, and that\ninvitation is what sets the initial password), `404` when the signed-in user has no linked\ncustomer record, and `503` when no identity provider is configured.",
        "operationId": "ResetCustomerMyPassword",
        "responses": {
          "204": {
            "description": "No Content"
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "AddressInfoDto": {
        "type": "object",
        "properties": {
          "street": {
            "type": "string"
          },
          "houseNumber": {
            "type": "string",
            "nullable": true
          },
          "additionalLine": {
            "type": "string",
            "nullable": true
          },
          "postalCode": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "poBox": {
            "type": "string",
            "nullable": true
          }
        },
        "nullable": true
      },
      "AddressInfoDto2": {
        "type": "object",
        "properties": {
          "street": {
            "type": "string"
          },
          "houseNumber": {
            "type": "string",
            "nullable": true
          },
          "additionalLine": {
            "type": "string",
            "nullable": true
          },
          "postalCode": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "poBox": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "AnnualOverviewGet": {
        "type": "object",
        "properties": {
          "year": {
            "type": "integer",
            "format": "int32"
          },
          "totalAmount": {
            "type": "number",
            "format": "double"
          },
          "invoiceCount": {
            "type": "integer",
            "format": "int32"
          },
          "months": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AnnualOverviewMonth"
            }
          },
          "byStatus": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AnnualOverviewStatus"
            }
          },
          "invoices": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InvoiceGet"
            }
          }
        }
      },
      "AnnualOverviewMonth": {
        "type": "object",
        "properties": {
          "month": {
            "type": "integer",
            "format": "int32"
          },
          "totalAmount": {
            "type": "number",
            "format": "double"
          },
          "invoiceCount": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "AnnualOverviewStatus": {
        "type": "object",
        "properties": {
          "status": {
            "$ref": "#/components/schemas/EnumDtoOfEInvoiceStatus"
          },
          "totalAmount": {
            "type": "number",
            "format": "double"
          },
          "invoiceCount": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "AttendanceRecordGet": {
        "type": "object",
        "properties": {
          "ownerRef": {
            "type": "string",
            "format": "uuid"
          },
          "ownerTypeName": {
            "type": "string"
          },
          "studentId": {
            "type": "string",
            "format": "uuid"
          },
          "student": {
            "$ref": "#/components/schemas/StudentRef"
          },
          "status": {
            "$ref": "#/components/schemas/EnumDtoOfEAttendanceStatus"
          },
          "absenceDocumentPath": {
            "type": "string",
            "nullable": true
          },
          "absenceDocumentId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "absenceDocumentSizeBytes": {
            "type": "integer",
            "format": "int64",
            "nullable": true
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "BudgetGet": {
        "type": "object",
        "properties": {
          "status": {
            "$ref": "#/components/schemas/EnumDtoOfEBudgetStatus"
          },
          "totalAmount": {
            "type": "number",
            "format": "double"
          },
          "consumedAmount": {
            "type": "number",
            "format": "double"
          },
          "invoicedAmount": {
            "type": "number",
            "format": "double"
          },
          "itemCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "sponsorCustomerId": {
            "type": "string",
            "format": "uuid"
          },
          "sponsorCustomer": {
            "$ref": "#/components/schemas/CustomerRef"
          },
          "beneficiaryCustomerId": {
            "type": "string",
            "format": "uuid"
          },
          "beneficiaryCustomer": {
            "$ref": "#/components/schemas/CustomerRef"
          },
          "remainingAmount": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "averageLessonPrice": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "estimatedTotalLessons": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "estimatedRemainingLessons": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "sponsorCustomerDisplay": {
            "type": "string",
            "nullable": true
          },
          "beneficiaryCustomerDisplay": {
            "type": "string",
            "nullable": true
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "BudgetPost": {
        "type": "object",
        "properties": {
          "totalAmount": {
            "type": "number",
            "format": "double"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "beneficiaryCustomerEmail": {
            "type": "string"
          },
          "averageLessonPrice": {
            "type": "number",
            "format": "double",
            "nullable": true
          }
        }
      },
      "CourseColorEnumDto": {
        "type": "object",
        "properties": {
          "propertyName": {
            "type": "string"
          },
          "value": {
            "type": "string"
          },
          "enumValue": {
            "$ref": "#/components/schemas/ECourseColor"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "CourseEnrollmentRequestGet": {
        "type": "object",
        "properties": {
          "courseId": {
            "type": "string",
            "format": "uuid"
          },
          "course": {
            "$ref": "#/components/schemas/CourseGet2"
          },
          "requestingCustomerId": {
            "type": "string",
            "format": "uuid"
          },
          "requestingCustomer": {
            "$ref": "#/components/schemas/CustomerRef"
          },
          "requestedStudentIds": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            }
          },
          "requestedStudents": {
            "type": "array",
            "items": { }
          },
          "requestDate": {
            "type": "string",
            "format": "date-time"
          },
          "status": {
            "$ref": "#/components/schemas/EnumDtoOfECourseEnrollmentStatus2"
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "declineReason": {
            "type": "string",
            "nullable": true
          },
          "invitations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StudentInviteRef"
            }
          },
          "requesterDisplay": {
            "type": "string",
            "nullable": true
          },
          "studentsDisplay": {
            "type": "string",
            "nullable": true
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "CourseEnrollmentRequestPatch": {
        "type": "object",
        "properties": {
          "requestedStudentIds": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "nullable": true
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "statusId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "declineReason": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "CourseEnrollmentRequestPost": {
        "type": "object",
        "properties": {
          "courseId": {
            "type": "string",
            "format": "uuid"
          },
          "requestingCustomerId": {
            "type": "string",
            "format": "uuid"
          },
          "requestedStudentIds": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            }
          },
          "notes": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "CourseGet": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "courseType": {
            "$ref": "#/components/schemas/EnumDtoOfECourseType"
          },
          "subject": {
            "$ref": "#/components/schemas/EnumDtoOfELanguage"
          },
          "level": {
            "$ref": "#/components/schemas/EnumDtoOfETeachingLevel"
          },
          "status": {
            "$ref": "#/components/schemas/EnumDtoOfECourseStatus"
          },
          "capacity": {
            "$ref": "#/components/schemas/EnumDtoOfECourseCapacity"
          },
          "color": {
            "$ref": "#/components/schemas/CourseColorEnumDto"
          },
          "startDate": {
            "type": "string",
            "format": "date"
          },
          "endDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "weeklySchedule": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WeeklyScheduleSlotDto"
            }
          },
          "room": {
            "$ref": "#/components/schemas/RoomRef"
          },
          "teacher": {
            "$ref": "#/components/schemas/TeacherRef"
          },
          "requiredMaterials": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MaterialRef2"
            },
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "isAvailable": {
            "type": "boolean"
          },
          "isEnrolled": {
            "type": "boolean"
          },
          "isRequested": {
            "type": "boolean"
          },
          "enrollmentStatus": {
            "$ref": "#/components/schemas/EnumDtoOfECourseEnrollmentStatus"
          },
          "enrolledStudents": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StudentRef2"
            },
            "nullable": true
          },
          "enrollmentRequests": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CourseEnrollmentRequestGet"
            },
            "nullable": true
          },
          "lessons": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CourseLessonGet"
            },
            "nullable": true
          },
          "displayName": {
            "type": "string",
            "nullable": true
          },
          "studentCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "lessonCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "CourseGet2": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "courseType": { },
          "subject": { },
          "level": { },
          "status": { },
          "capacity": {
            "nullable": true
          },
          "color": { },
          "startDate": {
            "type": "string",
            "format": "date"
          },
          "endDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "weeklySchedule": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WeeklyScheduleSlotDto"
            }
          },
          "room": {
            "nullable": true
          },
          "teacher": {
            "nullable": true
          },
          "requiredMaterials": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MaterialRef2"
            },
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "isAvailable": {
            "type": "boolean"
          },
          "isEnrolled": {
            "type": "boolean"
          },
          "isRequested": {
            "type": "boolean"
          },
          "enrollmentStatus": {
            "nullable": true
          },
          "enrolledStudents": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StudentRef2"
            },
            "nullable": true
          },
          "enrollmentRequests": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CourseEnrollmentRequestGet"
            },
            "nullable": true
          },
          "lessons": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CourseLessonGet"
            },
            "nullable": true
          },
          "displayName": {
            "type": "string",
            "nullable": true
          },
          "studentCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "lessonCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        },
        "nullable": true
      },
      "CourseLessonGet": {
        "type": "object",
        "properties": {
          "courseId": {
            "type": "string",
            "format": "uuid"
          },
          "startDate": {
            "type": "string",
            "format": "date"
          },
          "endDate": {
            "type": "string",
            "format": "date"
          },
          "startTime": {
            "pattern": "^-?(\\d+\\.)?\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,7})?$",
            "type": "string"
          },
          "endTime": {
            "pattern": "^-?(\\d+\\.)?\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,7})?$",
            "type": "string"
          },
          "teacher": {
            "$ref": "#/components/schemas/TeacherRef"
          },
          "room": {
            "$ref": "#/components/schemas/RoomRef"
          },
          "status": {
            "$ref": "#/components/schemas/EnumDtoOfELessonStatus"
          },
          "isCancelled": {
            "type": "boolean"
          },
          "homeworks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HomeworkGet"
            },
            "nullable": true
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "CoursePriceGet": {
        "type": "object",
        "properties": {
          "level": {
            "$ref": "#/components/schemas/EnumDtoOfETeachingLevel"
          },
          "courseType": {
            "$ref": "#/components/schemas/EnumDtoOfECourseType"
          },
          "isForChildren": {
            "type": "boolean"
          },
          "price": {
            "type": "number",
            "format": "double"
          },
          "productName": {
            "type": "string",
            "nullable": true
          },
          "isCustomProduct": {
            "type": "boolean"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "CourseRef": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "courseType": {
            "$ref": "#/components/schemas/EnumDtoOfECourseType"
          },
          "name": {
            "type": "string"
          },
          "displayName": {
            "type": "string",
            "nullable": true
          },
          "subject": {
            "$ref": "#/components/schemas/EnumDtoOfELanguage"
          },
          "level": {
            "$ref": "#/components/schemas/EnumDtoOfETeachingLevel"
          },
          "status": {
            "$ref": "#/components/schemas/EnumDtoOfECourseStatus"
          },
          "color": {
            "$ref": "#/components/schemas/CourseColorEnumDto"
          },
          "teacher": {
            "$ref": "#/components/schemas/TeacherRef"
          },
          "price": {
            "type": "number",
            "format": "double"
          },
          "roomId": {
            "type": "string",
            "format": "uuid"
          },
          "startDate": {
            "type": "string",
            "format": "date-time"
          },
          "endDate": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "weeklySchedule": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WeeklyScheduleSlotDto"
            }
          }
        },
        "nullable": true
      },
      "CourseRef2": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "courseType": {
            "$ref": "#/components/schemas/EnumDtoOfECourseType"
          },
          "name": {
            "type": "string"
          },
          "displayName": {
            "type": "string",
            "nullable": true
          },
          "subject": {
            "$ref": "#/components/schemas/EnumDtoOfELanguage"
          },
          "level": {
            "$ref": "#/components/schemas/EnumDtoOfETeachingLevel"
          },
          "status": {
            "$ref": "#/components/schemas/EnumDtoOfECourseStatus"
          },
          "color": {
            "$ref": "#/components/schemas/CourseColorEnumDto"
          },
          "teacher": {
            "$ref": "#/components/schemas/TeacherRef"
          },
          "price": {
            "type": "number",
            "format": "double"
          },
          "roomId": {
            "type": "string",
            "format": "uuid"
          },
          "startDate": {
            "type": "string",
            "format": "date-time"
          },
          "endDate": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "weeklySchedule": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WeeklyScheduleSlotDto"
            }
          }
        }
      },
      "CustomerContactInfoGet": {
        "type": "object",
        "properties": {
          "birthdate": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "salutation": {
            "type": "string",
            "nullable": true
          },
          "firstName": {
            "type": "string"
          },
          "lastName": {
            "type": "string"
          },
          "gender": {
            "$ref": "#/components/schemas/EnumDtoOfEGender"
          },
          "email": {
            "type": "string"
          },
          "mobilePhone": {
            "type": "string"
          },
          "phone": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "CustomerContactInfoPatch": {
        "type": "object",
        "properties": {
          "birthdate": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "firstName": {
            "type": "string",
            "nullable": true
          },
          "lastName": {
            "type": "string",
            "nullable": true
          },
          "genderId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "removeGenderId": {
            "type": "boolean"
          },
          "email": {
            "type": "string",
            "nullable": true
          },
          "mobilePhone": {
            "type": "string",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "nullable": true
          }
        },
        "nullable": true
      },
      "CustomerContactInfoPost": {
        "type": "object",
        "properties": {
          "birthdate": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "firstName": {
            "type": "string"
          },
          "lastName": {
            "type": "string"
          },
          "genderId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "email": {
            "type": "string"
          },
          "mobilePhone": {
            "type": "string"
          },
          "phone": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "CustomerDashboardGet": {
        "type": "object",
        "properties": {
          "upcomingLessons": {
            "$ref": "#/components/schemas/MiniListDataOfUpcomingLessonItem"
          },
          "pendingInvites": {
            "$ref": "#/components/schemas/MiniListDataOfPendingInviteItem"
          },
          "recentInvoices": {
            "$ref": "#/components/schemas/MiniListDataOfRecentInvoiceItem"
          },
          "notifications": {
            "$ref": "#/components/schemas/MiniListDataOfNotificationItem"
          }
        }
      },
      "CustomerGet": {
        "type": "object",
        "properties": {
          "customerType": {
            "$ref": "#/components/schemas/EnumDtoOfECustomerType"
          },
          "companyName": {
            "type": "string",
            "nullable": true
          },
          "correspondenceLanguage": {
            "$ref": "#/components/schemas/EnumDtoOfELanguage"
          },
          "profileConfirmed": {
            "type": "boolean"
          },
          "contactInfo": {
            "$ref": "#/components/schemas/CustomerContactInfoGet"
          },
          "billingAddress": {
            "$ref": "#/components/schemas/AddressInfoDto2"
          },
          "loginNumber": {
            "type": "string",
            "nullable": true
          },
          "students": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StudentRef2"
            }
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "CustomerPatch": {
        "type": "object",
        "properties": {
          "companyName": {
            "type": "string",
            "nullable": true
          },
          "correspondenceLanguageId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "profileConfirmed": {
            "type": "boolean",
            "nullable": true
          },
          "contactInfo": {
            "$ref": "#/components/schemas/CustomerContactInfoPatch"
          },
          "billingAddress": {
            "$ref": "#/components/schemas/AddressInfoDto"
          }
        }
      },
      "CustomerPost": {
        "type": "object",
        "properties": {
          "correspondenceLanguageId": {
            "type": "string",
            "format": "uuid"
          },
          "contactInfo": {
            "$ref": "#/components/schemas/CustomerContactInfoPost"
          },
          "billingAddress": {
            "$ref": "#/components/schemas/AddressInfoDto2"
          }
        }
      },
      "CustomerRef": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "displayName": {
            "type": "string"
          },
          "customerType": {
            "$ref": "#/components/schemas/EnumDtoOfECustomerType"
          },
          "isActive": {
            "type": "boolean"
          },
          "address": {
            "$ref": "#/components/schemas/AddressInfoDto"
          }
        },
        "nullable": true
      },
      "DayOfWeek": {
        "type": "integer"
      },
      "EAccountStatus": {
        "type": "integer"
      },
      "EAttendanceStatus": {
        "type": "integer"
      },
      "EBudgetStatus": {
        "type": "integer"
      },
      "ECourseCapacity": {
        "type": "integer"
      },
      "ECourseColor": {
        "type": "integer"
      },
      "ECourseEnrollmentStatus": {
        "type": "integer"
      },
      "ECourseStatus": {
        "type": "integer"
      },
      "ECourseType": {
        "type": "integer"
      },
      "ECustomerType": {
        "type": "integer"
      },
      "EGender": {
        "type": "integer"
      },
      "EInterestStatus": {
        "type": "integer"
      },
      "EInterestType": {
        "type": "integer"
      },
      "EInviteMaterialStatus": {
        "type": "integer"
      },
      "EInviteStatus": {
        "type": "integer"
      },
      "EInvoiceStatus": {
        "type": "integer"
      },
      "ELanguage": {
        "type": "integer"
      },
      "ELessonStatus": {
        "type": "integer"
      },
      "EMaterialDeliveryMethod": {
        "type": "integer"
      },
      "EMaterialLevel": {
        "type": "integer"
      },
      "EMaterialType": {
        "type": "integer"
      },
      "ENotificationKey": {
        "type": "integer"
      },
      "ENotificationType": {
        "type": "integer"
      },
      "EnumDtoOfEAccountStatus": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/EAccountStatus"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "EnumDtoOfEAttendanceStatus": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/EAttendanceStatus"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "EnumDtoOfEBudgetStatus": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/EBudgetStatus"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "EnumDtoOfECourseCapacity": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/ECourseCapacity"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        },
        "nullable": true
      },
      "EnumDtoOfECourseEnrollmentStatus": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/ECourseEnrollmentStatus"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        },
        "nullable": true
      },
      "EnumDtoOfECourseEnrollmentStatus2": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/ECourseEnrollmentStatus"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "EnumDtoOfECourseStatus": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/ECourseStatus"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "EnumDtoOfECourseType": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/ECourseType"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "EnumDtoOfECustomerType": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/ECustomerType"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "EnumDtoOfEGender": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/EGender"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        },
        "nullable": true
      },
      "EnumDtoOfEInterestStatus": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/EInterestStatus"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "EnumDtoOfEInterestType": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/EInterestType"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "EnumDtoOfEInviteMaterialStatus": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/EInviteMaterialStatus"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        },
        "nullable": true
      },
      "EnumDtoOfEInviteMaterialStatus2": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/EInviteMaterialStatus"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "EnumDtoOfEInviteStatus": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/EInviteStatus"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "EnumDtoOfEInvoiceStatus": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/EInvoiceStatus"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "EnumDtoOfELanguage": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/ELanguage"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "EnumDtoOfELanguage2": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/ELanguage"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        },
        "nullable": true
      },
      "EnumDtoOfELessonStatus": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/ELessonStatus"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "EnumDtoOfEMaterialDeliveryMethod": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/EMaterialDeliveryMethod"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        },
        "nullable": true
      },
      "EnumDtoOfEMaterialLevel": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/EMaterialLevel"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "EnumDtoOfEMaterialType": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/EMaterialType"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "EnumDtoOfENotificationKey": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/ENotificationKey"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "EnumDtoOfENotificationType": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/ENotificationType"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "EnumDtoOfEPackageAssignment": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/EPackageAssignment"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "EnumDtoOfEPackageOrderStatus": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/EPackageOrderStatus"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "EnumDtoOfEPreferredLocation": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/EPreferredLocation"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        },
        "nullable": true
      },
      "EnumDtoOfEPreferredTeachingFormat": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/EPreferredTeachingFormat"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        },
        "nullable": true
      },
      "EnumDtoOfERoomStatus": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/ERoomStatus"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "EnumDtoOfEStudentStatus": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/EStudentStatus"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "EnumDtoOfETeachingLevel": {
        "type": "object",
        "properties": {
          "enumValue": {
            "$ref": "#/components/schemas/ETeachingLevel"
          },
          "displayName": {
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "EPackageAssignment": {
        "type": "integer"
      },
      "EPackageOrderStatus": {
        "type": "integer"
      },
      "EPreferredLocation": {
        "type": "integer"
      },
      "EPreferredTeachingFormat": {
        "type": "integer"
      },
      "ERoomStatus": {
        "type": "integer"
      },
      "EStudentStatus": {
        "type": "integer"
      },
      "ETeachingLevel": {
        "type": "integer"
      },
      "HomeworkDocumentRef": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "fileName": {
            "type": "string"
          },
          "contentType": {
            "type": "string"
          },
          "sizeBytes": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "HomeworkGet": {
        "type": "object",
        "properties": {
          "lessonId": {
            "type": "string",
            "format": "uuid"
          },
          "description": {
            "type": "string"
          },
          "dueDate": {
            "type": "string",
            "format": "date"
          },
          "lessonStartDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "course": {
            "$ref": "#/components/schemas/CourseRef"
          },
          "documents": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HomeworkDocumentRef"
            }
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "HomeworkRef": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "description": {
            "type": "string"
          },
          "dueDate": {
            "type": "string",
            "format": "date"
          },
          "documents": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HomeworkDocumentRef"
            }
          }
        }
      },
      "HttpValidationProblemDetails": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "detail": {
            "type": "string",
            "nullable": true
          },
          "instance": {
            "type": "string",
            "nullable": true
          },
          "errors": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        }
      },
      "InterestGet": {
        "type": "object",
        "properties": {
          "studentId": {
            "type": "string",
            "format": "uuid"
          },
          "studentRef": {
            "$ref": "#/components/schemas/StudentRef"
          },
          "requestingCustomerId": {
            "type": "string",
            "format": "uuid"
          },
          "requestingCustomer": {
            "$ref": "#/components/schemas/CustomerRef"
          },
          "requestedStudentIds": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            }
          },
          "requestedStudents": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StudentRef2"
            },
            "nullable": true
          },
          "preferredLocation": {
            "$ref": "#/components/schemas/EnumDtoOfEPreferredLocation"
          },
          "preferredAddress": {
            "type": "string",
            "nullable": true
          },
          "numberOfLessons": {
            "type": "integer",
            "format": "int32"
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "estimatedPrice": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "language": {
            "$ref": "#/components/schemas/EnumDtoOfELanguage"
          },
          "level": {
            "$ref": "#/components/schemas/EnumDtoOfETeachingLevel"
          },
          "interestType": {
            "$ref": "#/components/schemas/EnumDtoOfEInterestType"
          },
          "status": {
            "$ref": "#/components/schemas/EnumDtoOfEInterestStatus"
          },
          "declinedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "declineReason": {
            "type": "string",
            "nullable": true
          },
          "startDate": {
            "type": "string",
            "format": "date-time"
          },
          "endDate": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "lessonsPerWeek": {
            "type": "integer",
            "format": "int32"
          },
          "lessonDurationMinutes": {
            "type": "integer",
            "format": "int32"
          },
          "timeSlots": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TimeSlotDto"
            }
          },
          "displayName": {
            "type": "string",
            "nullable": true
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "InterestPatch": {
        "type": "object",
        "properties": {
          "startDate": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "endDate": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "removeEndDate": {
            "type": "boolean"
          },
          "lessonsPerWeek": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "lessonDurationMinutes": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "timeSlots": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TimeSlotDto"
            },
            "nullable": true
          },
          "requestedStudentIds": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "nullable": true
          },
          "preferredLocationId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "preferredAddress": {
            "type": "string",
            "nullable": true
          },
          "removePreferredAddress": {
            "type": "boolean"
          },
          "numberOfLessons": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "removeNotes": {
            "type": "boolean"
          },
          "statusId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          }
        }
      },
      "InterestPost": {
        "type": "object",
        "properties": {
          "studentId": {
            "type": "string",
            "format": "uuid"
          },
          "requestedStudentIds": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "nullable": true
          },
          "languageId": {
            "type": "string",
            "format": "uuid"
          },
          "levelId": {
            "type": "string",
            "format": "uuid"
          },
          "interestTypeId": {
            "type": "string",
            "format": "uuid"
          },
          "startDate": {
            "type": "string",
            "format": "date-time"
          },
          "endDate": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "lessonsPerWeek": {
            "type": "integer",
            "format": "int32"
          },
          "lessonDurationMinutes": {
            "type": "integer",
            "format": "int32"
          },
          "timeSlots": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TimeSlotDto"
            },
            "nullable": true
          },
          "preferredLocationId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "preferredAddress": {
            "type": "string",
            "nullable": true
          },
          "numberOfLessons": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "InviteMaterialChoiceGet": {
        "type": "object",
        "properties": {
          "materialId": {
            "type": "string",
            "format": "uuid"
          },
          "material": {
            "$ref": "#/components/schemas/MaterialRef"
          },
          "alreadyInPossession": {
            "type": "boolean"
          },
          "status": {
            "$ref": "#/components/schemas/EnumDtoOfEInviteMaterialStatus2"
          },
          "deliveryMethod": {
            "$ref": "#/components/schemas/EnumDtoOfEMaterialDeliveryMethod"
          },
          "answeredAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "InviteMaterialChoicePost": {
        "type": "object",
        "properties": {
          "materialId": {
            "type": "string",
            "format": "uuid"
          },
          "alreadyInPossession": {
            "type": "boolean",
            "nullable": true
          },
          "deliveryMethodId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          }
        }
      },
      "InvoiceExtraItemGet": {
        "type": "object",
        "properties": {
          "description": {
            "type": "string"
          },
          "amount": {
            "type": "number",
            "format": "double"
          }
        }
      },
      "InvoiceGet": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "invoiceDate": {
            "type": "string",
            "format": "date-time"
          },
          "periodYear": {
            "type": "integer",
            "format": "int32"
          },
          "periodMonth": {
            "type": "integer",
            "format": "int32"
          },
          "dueDate": {
            "type": "string",
            "format": "date-time"
          },
          "invoiceNumber": {
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/EnumDtoOfEInvoiceStatus"
          },
          "isOverdue": {
            "type": "boolean"
          },
          "totalAmount": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "fileUrl": {
            "type": "string",
            "nullable": true
          },
          "itemCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "purchaseOrderNumber": {
            "type": "string",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "lineItems": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InvoiceLineItemGet"
            }
          },
          "extraItems": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InvoiceExtraItemGet"
            }
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "InvoiceLineItemGet": {
        "type": "object",
        "properties": {
          "description": {
            "type": "string"
          },
          "courseDisplay": {
            "type": "string",
            "nullable": true
          },
          "studentDisplay": {
            "type": "string",
            "nullable": true
          },
          "units": {
            "type": "integer",
            "format": "int32"
          },
          "amount": {
            "type": "number",
            "format": "double"
          },
          "serviceDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          }
        }
      },
      "LessonGet": {
        "type": "object",
        "properties": {
          "courseId": {
            "type": "string",
            "format": "uuid"
          },
          "course": {
            "$ref": "#/components/schemas/CourseRef"
          },
          "startDate": {
            "type": "string",
            "format": "date"
          },
          "endDate": {
            "type": "string",
            "format": "date"
          },
          "startTime": {
            "pattern": "^-?(\\d+\\.)?\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,7})?$",
            "type": "string"
          },
          "endTime": {
            "pattern": "^-?(\\d+\\.)?\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,7})?$",
            "type": "string"
          },
          "teacher": {
            "$ref": "#/components/schemas/TeacherRef"
          },
          "room": {
            "$ref": "#/components/schemas/RoomRef"
          },
          "status": {
            "$ref": "#/components/schemas/EnumDtoOfELessonStatus"
          },
          "isCancelled": {
            "type": "boolean"
          },
          "homeworks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HomeworkGet"
            },
            "nullable": true
          },
          "attendanceRecords": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AttendanceRecordGet"
            },
            "nullable": true
          },
          "enrolledStudents": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StudentRef2"
            },
            "nullable": true
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "LessonRef": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "displayName": {
            "type": "string"
          },
          "startDate": {
            "type": "string",
            "format": "date"
          },
          "startTime": {
            "pattern": "^-?(\\d+\\.)?\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,7})?$",
            "type": "string"
          },
          "endTime": {
            "pattern": "^-?(\\d+\\.)?\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,7})?$",
            "type": "string"
          },
          "isCancelled": {
            "type": "boolean"
          },
          "travelAllowance": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "courseDisplay": {
            "type": "string"
          },
          "lessonPrice": {
            "type": "number",
            "format": "double"
          },
          "status": {
            "$ref": "#/components/schemas/EnumDtoOfELessonStatus"
          },
          "course": {
            "$ref": "#/components/schemas/CourseRef"
          },
          "teacher": {
            "$ref": "#/components/schemas/TeacherRef"
          },
          "homeworks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HomeworkRef"
            },
            "nullable": true
          }
        }
      },
      "MaterialChangeRequestAnswer": {
        "type": "object",
        "properties": {
          "materialId": {
            "type": "string",
            "format": "uuid"
          },
          "alreadyInPossession": {
            "type": "boolean",
            "nullable": true
          },
          "deliveryMethodId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          }
        }
      },
      "MaterialChangeRequestGet": {
        "type": "object",
        "properties": {
          "courseId": {
            "type": "string",
            "format": "uuid"
          },
          "course": {
            "$ref": "#/components/schemas/CourseRef"
          },
          "studentId": {
            "type": "string",
            "format": "uuid"
          },
          "student": {
            "$ref": "#/components/schemas/StudentRef"
          },
          "requestedAt": {
            "type": "string",
            "format": "date-time"
          },
          "answeredAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "isAnswered": {
            "type": "boolean"
          },
          "deliveryMethod": {
            "$ref": "#/components/schemas/EnumDtoOfEMaterialDeliveryMethod"
          },
          "deliveryAddress": {
            "$ref": "#/components/schemas/AddressInfoDto"
          },
          "defaultDeliveryAddress": {
            "$ref": "#/components/schemas/AddressInfoDto"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MaterialChangeRequestItemGet"
            }
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "MaterialChangeRequestItemGet": {
        "type": "object",
        "properties": {
          "materialId": {
            "type": "string",
            "format": "uuid"
          },
          "material": {
            "$ref": "#/components/schemas/MaterialRef"
          },
          "alreadyInPossession": {
            "type": "boolean"
          },
          "answeredAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "deliveryMethod": {
            "$ref": "#/components/schemas/EnumDtoOfEMaterialDeliveryMethod"
          },
          "status": {
            "$ref": "#/components/schemas/EnumDtoOfEInviteMaterialStatus"
          }
        }
      },
      "MaterialChangeRequestPatch": {
        "type": "object",
        "properties": {
          "answers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MaterialChangeRequestAnswer"
            },
            "nullable": true
          },
          "deliveryMethodId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "deliveryAddress": {
            "$ref": "#/components/schemas/AddressInfoDto"
          }
        }
      },
      "MaterialRef": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "title": {
            "type": "string"
          },
          "isbn": {
            "type": "string"
          },
          "language": {
            "$ref": "#/components/schemas/EnumDtoOfELanguage"
          },
          "level": {
            "$ref": "#/components/schemas/EnumDtoOfEMaterialLevel"
          },
          "price": {
            "type": "number",
            "format": "double"
          },
          "type": {
            "$ref": "#/components/schemas/EnumDtoOfEMaterialType"
          }
        },
        "nullable": true
      },
      "MaterialRef2": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "title": {
            "type": "string"
          },
          "isbn": {
            "type": "string"
          },
          "language": {
            "$ref": "#/components/schemas/EnumDtoOfELanguage"
          },
          "level": {
            "$ref": "#/components/schemas/EnumDtoOfEMaterialLevel"
          },
          "price": {
            "type": "number",
            "format": "double"
          },
          "type": {
            "$ref": "#/components/schemas/EnumDtoOfEMaterialType"
          }
        }
      },
      "MiniListDataOfNotificationItem": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NotificationItem"
            }
          },
          "viewAllUrl": {
            "type": "string",
            "nullable": true
          },
          "maxItems": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "MiniListDataOfPendingInviteItem": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PendingInviteItem"
            }
          },
          "viewAllUrl": {
            "type": "string",
            "nullable": true
          },
          "maxItems": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "MiniListDataOfRecentInvoiceItem": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RecentInvoiceItem"
            }
          },
          "viewAllUrl": {
            "type": "string",
            "nullable": true
          },
          "maxItems": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "MiniListDataOfUpcomingLessonItem": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UpcomingLessonItem"
            }
          },
          "viewAllUrl": {
            "type": "string",
            "nullable": true
          },
          "maxItems": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "MyProfilePatch": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "nullable": true
          },
          "firstName": {
            "type": "string",
            "nullable": true
          },
          "lastName": {
            "type": "string",
            "nullable": true
          },
          "genderId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "removeGenderId": {
            "type": "boolean"
          },
          "birthdate": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "mobilePhone": {
            "type": "string",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "nullable": true
          },
          "removePhone": {
            "type": "boolean"
          },
          "billingAddress": {
            "$ref": "#/components/schemas/AddressInfoDto"
          },
          "correspondenceLanguageId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "profileConfirmed": {
            "type": "boolean",
            "nullable": true
          }
        }
      },
      "NotificationGet": {
        "type": "object",
        "properties": {
          "targetId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "eventDate": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "date": {
            "type": "string",
            "format": "date-time"
          },
          "message": {
            "type": "string"
          },
          "isRead": {
            "type": "boolean"
          },
          "targetUrl": {
            "type": "string",
            "nullable": true
          },
          "type": {
            "$ref": "#/components/schemas/EnumDtoOfENotificationType"
          },
          "key": {
            "$ref": "#/components/schemas/EnumDtoOfENotificationKey"
          },
          "relatedStudent": {
            "$ref": "#/components/schemas/StudentRef"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "NotificationItem": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string"
          },
          "date": {
            "type": "string",
            "format": "date-time"
          },
          "type": {
            "$ref": "#/components/schemas/EnumDtoOfENotificationType"
          },
          "isRead": {
            "type": "boolean"
          }
        }
      },
      "NotificationMarkReadPost": {
        "type": "object",
        "properties": {
          "ids": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            }
          }
        }
      },
      "NotificationMarkReadResultGet": {
        "type": "object",
        "properties": {
          "updated": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "NotificationPatch": {
        "type": "object",
        "properties": {
          "isRead": {
            "type": "boolean",
            "nullable": true
          }
        }
      },
      "NotificationUnreadCountGet": {
        "type": "object",
        "properties": {
          "unread": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "NullableOfEAccountStatus": {
        "type": "integer"
      },
      "NullableOfEStudentStatus": {
        "type": "integer"
      },
      "PackageGet": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "billingTitle": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "price": {
            "type": "number",
            "format": "double"
          },
          "credit": {
            "type": "number",
            "format": "double"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "PackageGet2": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "billingTitle": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "price": {
            "type": "number",
            "format": "double"
          },
          "credit": {
            "type": "number",
            "format": "double"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        },
        "nullable": true
      },
      "PackageOrderGet": {
        "type": "object",
        "properties": {
          "status": {
            "$ref": "#/components/schemas/EnumDtoOfEPackageOrderStatus"
          },
          "refundRequestedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "refundedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "refundReason": {
            "type": "string",
            "nullable": true
          },
          "settledAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "packageId": {
            "type": "string",
            "format": "uuid"
          },
          "packageRef": {
            "$ref": "#/components/schemas/PackageGet2"
          },
          "customerId": {
            "type": "string",
            "format": "uuid"
          },
          "customerRef": {
            "$ref": "#/components/schemas/CustomerRef"
          },
          "assignedToCustomerId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "assignedToCustomer": {
            "$ref": "#/components/schemas/CustomerRef"
          },
          "assignedToCustomerEmail": {
            "type": "string",
            "nullable": true
          },
          "passedOnType": {
            "$ref": "#/components/schemas/EnumDtoOfEPackageAssignment"
          },
          "usageByStudent": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PackageStudentUsageDto"
            }
          },
          "displayName": {
            "type": "string",
            "nullable": true
          },
          "usedCredit": {
            "type": "number",
            "format": "double"
          },
          "purchasedPrice": {
            "type": "number",
            "format": "double"
          },
          "purchasedCredit": {
            "type": "number",
            "format": "double"
          },
          "remainingCredit": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "residualCredit": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "isCreditOpen": {
            "type": "boolean"
          },
          "creditedInvoiceId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "PackagePurchaseGet": {
        "type": "object",
        "properties": {
          "customerId": {
            "type": "string",
            "format": "uuid"
          },
          "customerRef": {
            "$ref": "#/components/schemas/CustomerRef"
          },
          "purchasedAt": {
            "type": "string",
            "format": "date-time"
          },
          "invoiceId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "orders": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PackageOrderGet"
            }
          },
          "itemCount": {
            "type": "integer",
            "format": "int32"
          },
          "isCompleted": {
            "type": "boolean"
          },
          "totalPrice": {
            "type": "number",
            "format": "double"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "PackagePurchaseItemPost": {
        "type": "object",
        "properties": {
          "packageId": {
            "type": "string",
            "format": "uuid"
          },
          "beneficiaryCustomerEmail": {
            "type": "string",
            "nullable": true
          },
          "passedOnTypeId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          }
        }
      },
      "PackagePurchasePost": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PackagePurchaseItemPost"
            }
          }
        }
      },
      "PackageStudentUsageDto": {
        "type": "object",
        "properties": {
          "studentId": {
            "type": "string",
            "format": "uuid"
          },
          "student": {
            "$ref": "#/components/schemas/StudentRef"
          },
          "usedCredit": {
            "type": "number",
            "format": "double"
          },
          "lessonCount": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "PendingInviteItem": {
        "type": "object",
        "properties": {
          "studentName": {
            "type": "string"
          },
          "courseName": {
            "type": "string"
          },
          "invitedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ProblemDetails": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "detail": {
            "type": "string",
            "nullable": true
          },
          "instance": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "RecentInvoiceItem": {
        "type": "object",
        "properties": {
          "invoiceNumber": {
            "type": "string"
          },
          "invoiceDate": {
            "type": "string",
            "format": "date-time"
          },
          "amount": {
            "type": "number",
            "format": "double"
          },
          "status": {
            "$ref": "#/components/schemas/EnumDtoOfEInvoiceStatus"
          },
          "dueDate": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "RefundableAmountGet": {
        "type": "object",
        "properties": {
          "packageOrderId": {
            "type": "string",
            "format": "uuid"
          },
          "refundableAmount": {
            "type": "number",
            "format": "double"
          },
          "isRefundable": {
            "type": "boolean"
          },
          "isPlaceholder": {
            "type": "boolean"
          }
        }
      },
      "RoomRef": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "displayName": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "maxStudents": {
            "type": "integer",
            "format": "int32"
          },
          "status": {
            "$ref": "#/components/schemas/EnumDtoOfERoomStatus"
          }
        },
        "nullable": true
      },
      "SetPasswordPost": {
        "type": "object",
        "properties": {
          "password": {
            "type": "string"
          }
        }
      },
      "StudentGet": {
        "type": "object",
        "properties": {
          "lastName": {
            "type": "string"
          },
          "firstName": {
            "type": "string"
          },
          "birthdate": {
            "type": "string",
            "format": "date-time"
          },
          "nativeLanguage": {
            "$ref": "#/components/schemas/EnumDtoOfELanguage2"
          },
          "gender": {
            "$ref": "#/components/schemas/EnumDtoOfEGender"
          },
          "correspondenceLanguage": {
            "$ref": "#/components/schemas/EnumDtoOfELanguage2"
          },
          "preferredTeachingFormat": {
            "$ref": "#/components/schemas/EnumDtoOfEPreferredTeachingFormat"
          },
          "status": {
            "$ref": "#/components/schemas/EnumDtoOfEStudentStatus"
          },
          "inactive": {
            "type": "boolean"
          },
          "email": {
            "type": "string",
            "nullable": true
          },
          "accountStatus": {
            "$ref": "#/components/schemas/EnumDtoOfEAccountStatus"
          },
          "loginNumber": {
            "type": "string",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "nullable": true
          },
          "useCustomerAddress": {
            "type": "boolean"
          },
          "address": {
            "$ref": "#/components/schemas/AddressInfoDto"
          },
          "subjects": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SubjectGet"
            }
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "courses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CourseRef2"
            },
            "nullable": true
          },
          "lessons": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LessonRef"
            },
            "nullable": true
          },
          "age": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "isChild": {
            "type": "boolean",
            "nullable": true
          },
          "displayName": {
            "type": "string",
            "nullable": true
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "StudentInviteGet": {
        "type": "object",
        "properties": {
          "courseId": {
            "type": "string",
            "format": "uuid"
          },
          "course": {
            "$ref": "#/components/schemas/CourseRef"
          },
          "studentId": {
            "type": "string",
            "format": "uuid"
          },
          "student": {
            "$ref": "#/components/schemas/StudentRef"
          },
          "status": {
            "$ref": "#/components/schemas/EnumDtoOfEInviteStatus"
          },
          "invitedAt": {
            "type": "string",
            "format": "date-time"
          },
          "respondedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "materialChoices": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InviteMaterialChoiceGet"
            }
          },
          "deliveryMethod": {
            "$ref": "#/components/schemas/EnumDtoOfEMaterialDeliveryMethod"
          },
          "deliveryAddress": {
            "$ref": "#/components/schemas/AddressInfoDto"
          },
          "defaultDeliveryAddress": {
            "$ref": "#/components/schemas/AddressInfoDto"
          },
          "acceptedDate": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "declinedDate": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "displayName": {
            "type": "string",
            "nullable": true
          },
          "isPending": {
            "type": "boolean"
          },
          "materialListComplete": {
            "type": "boolean"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "modifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "removed": {
            "type": "boolean"
          }
        }
      },
      "StudentInvitePatch": {
        "type": "object",
        "properties": {
          "statusId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "materialChoices": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InviteMaterialChoicePost"
            },
            "nullable": true
          },
          "deliveryMethodId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "deliveryAddress": {
            "$ref": "#/components/schemas/AddressInfoDto"
          }
        }
      },
      "StudentInviteRef": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "studentId": {
            "type": "string",
            "format": "uuid"
          },
          "student": {
            "$ref": "#/components/schemas/StudentRef"
          },
          "status": {
            "$ref": "#/components/schemas/EnumDtoOfEInviteStatus"
          },
          "invitedAt": {
            "type": "string",
            "format": "date-time"
          },
          "respondedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "isPending": {
            "type": "boolean"
          },
          "displayName": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "StudentPatch": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "nullable": true
          },
          "inactive": {
            "type": "boolean",
            "nullable": true
          },
          "lastName": {
            "type": "string",
            "nullable": true
          },
          "firstName": {
            "type": "string",
            "nullable": true
          },
          "birthdate": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "nativeLanguageId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "genderId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "removeGender": {
            "type": "boolean"
          },
          "correspondenceLanguageId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "removeCorrespondenceLanguage": {
            "type": "boolean"
          },
          "preferredTeachingFormatId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "removePreferredTeachingFormat": {
            "type": "boolean"
          },
          "phone": {
            "type": "string",
            "nullable": true
          },
          "useCustomerAddress": {
            "type": "boolean",
            "nullable": true
          },
          "address": {
            "$ref": "#/components/schemas/AddressInfoDto"
          },
          "removeAddress": {
            "type": "boolean"
          },
          "notes": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "StudentPost": {
        "type": "object",
        "properties": {
          "lastName": {
            "type": "string"
          },
          "firstName": {
            "type": "string"
          },
          "birthdate": {
            "type": "string",
            "format": "date-time"
          },
          "nativeLanguageId": {
            "type": "string",
            "format": "uuid"
          },
          "genderId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "correspondenceLanguageId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "preferredTeachingFormatId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "email": {
            "type": "string",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "nullable": true
          },
          "useCustomerAddress": {
            "type": "boolean"
          },
          "address": {
            "$ref": "#/components/schemas/AddressInfoDto"
          },
          "subjects": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SubjectPost"
            },
            "nullable": true
          },
          "notes": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "StudentRef": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "firstName": {
            "type": "string"
          },
          "lastName": {
            "type": "string"
          },
          "displayName": {
            "type": "string"
          },
          "nativeLanguage": {
            "$ref": "#/components/schemas/EnumDtoOfELanguage2"
          },
          "isChild": {
            "type": "boolean",
            "nullable": true
          },
          "age": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          }
        },
        "nullable": true
      },
      "StudentRef2": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "firstName": {
            "type": "string"
          },
          "lastName": {
            "type": "string"
          },
          "displayName": {
            "type": "string"
          },
          "nativeLanguage": {
            "$ref": "#/components/schemas/EnumDtoOfELanguage2"
          },
          "isChild": {
            "type": "boolean",
            "nullable": true
          },
          "age": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          }
        }
      },
      "SubjectGet": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "language": {
            "$ref": "#/components/schemas/EnumDtoOfELanguage"
          },
          "level": {
            "$ref": "#/components/schemas/EnumDtoOfETeachingLevel"
          }
        }
      },
      "SubjectPost": {
        "type": "object",
        "properties": {
          "languageId": {
            "type": "string",
            "format": "uuid"
          },
          "levelId": {
            "type": "string",
            "format": "uuid"
          }
        }
      },
      "TeacherRef": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "displayName": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "mobilePhone": {
            "type": "string"
          },
          "lessonsToChildren": {
            "type": "boolean"
          },
          "inactive": {
            "type": "boolean"
          },
          "teachingLanguages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EnumDtoOfELanguage"
            }
          }
        },
        "nullable": true
      },
      "TimeSlotDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "day": {
            "$ref": "#/components/schemas/DayOfWeek"
          },
          "startTime": {
            "pattern": "^-?(\\d+\\.)?\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,7})?$",
            "type": "string"
          },
          "endTime": {
            "pattern": "^-?(\\d+\\.)?\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,7})?$",
            "type": "string"
          }
        }
      },
      "UpcomingLessonItem": {
        "type": "object",
        "properties": {
          "studentName": {
            "type": "string"
          },
          "courseName": {
            "type": "string"
          },
          "startDate": {
            "type": "string",
            "format": "date-time"
          },
          "startTime": {
            "pattern": "^-?(\\d+\\.)?\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,7})?$",
            "type": "string"
          },
          "teacherName": {
            "type": "string"
          },
          "roomName": {
            "type": "string"
          }
        }
      },
      "WeeklyScheduleSlotDto": {
        "type": "object",
        "properties": {
          "day": {
            "$ref": "#/components/schemas/DayOfWeek"
          },
          "startTime": {
            "pattern": "^-?(\\d+\\.)?\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,7})?$",
            "type": "string"
          },
          "endTime": {
            "pattern": "^-?(\\d+\\.)?\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,7})?$",
            "type": "string"
          }
        }
      }
    },
    "securitySchemes": {
      "keycloak": {
        "type": "oauth2",
        "description": "Log in via Keycloak (Authorization Code + PKCE). Uses the public 'swagger-ui' client.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://auth.triskela.com/realms/softlanding/protocol/openid-connect/auth",
            "tokenUrl": "https://auth.triskela.com/realms/softlanding/protocol/openid-connect/token",
            "scopes": {
              "openid": "OpenID Connect",
              "profile": "User profile",
              "email": "User email"
            }
          }
        }
      }
    }
  },
  "security": [
    {
      "keycloak": [
        "openid",
        "profile",
        "email"
      ]
    }
  ],
  "tags": [
    {
      "name": "HomeworkDocument (Customer)"
    },
    {
      "name": "Dashboard (Customer)"
    },
    {
      "name": "Customer Invoices"
    },
    {
      "name": "MaterialChangeRequest (Customer)"
    },
    {
      "name": "Customer (Customer)"
    },
    {
      "name": "Student (Customer)"
    },
    {
      "name": "Course (Customer)"
    },
    {
      "name": "Interest (Customer)"
    },
    {
      "name": "Lesson (Customer)"
    },
    {
      "name": "Invoice (Customer)"
    },
    {
      "name": "Budget (Customer)"
    },
    {
      "name": "Package (Customer)"
    },
    {
      "name": "CoursePrice (Customer)"
    },
    {
      "name": "PackageOrder (Customer)"
    },
    {
      "name": "PackagePurchase (Customer)"
    },
    {
      "name": "StudentInvite (Customer)"
    },
    {
      "name": "Notification (Customer)"
    },
    {
      "name": "EnrollmentRequest (Customer)"
    },
    {
      "name": "Customer MyProfile"
    }
  ]
}