{"openapi":"3.0.1","info":{"title":"GeoPass API","description":"REST API powering GeoPass (geopass.ge), the Georgian citizenship exam preparation app operated by Individual Entrepreneur Bakur Jobava. This API currently serves the official GeoPass web client; it is documented here so agents and developers can understand its surface. It is not yet offered as a self-service third-party integration product - contact us if you want to integrate as a partner.","contact":{"name":"GeoPass Support","url":"https://www.geopass.ge/contact","email":"geopasscitizien@gmail.com"},"version":"1.0"},"servers":[{"url":"https://api.geopass.ge","description":"Production"}],"tags":[{"name":"Auth","description":"Registration, login, token refresh, and password-recovery endpoints. All endpoints are public and do not require authentication."},{"name":"Feedback","description":"Endpoint for authenticated users to submit a feedback message. Requires an authenticated user."},{"name":"Admin: Topics","description":"Administrative CRUD endpoints for managing topics and their translations. Requires the ADMIN role."},{"name":"Flitt Webhooks","description":"Public server-to-server callback endpoints invoked by the Flitt payment gateway to update subscription status. No authentication required."},{"name":"Topics","description":"Endpoints for browsing citizenship exam topics. Reading topics requires an ADMIN role or an active subscription; creating, updating, and deleting a topic additionally requires the ADMIN role."},{"name":"Admin: Subscriptions","description":"Administrative endpoints for viewing all user subscriptions and pausing or resuming an individual subscription. Requires the ADMIN role."},{"name":"Flitt Redirects","description":"Public browser-redirect endpoints that send the user's browser back to the frontend after a Flitt payment attempt. No authentication required."},{"name":"Exam","description":"Endpoints for fetching a generated exam paper and submitting answers for grading. Requires an authenticated user."},{"name":"Subtopics","description":"Endpoint for listing the questions that belong to a subtopic. Requires an ADMIN role or an active subscription."},{"name":"Subscription Plans","description":"Endpoint for listing the available subscription plans. Requires an authenticated user."},{"name":"Admin: Questions","description":"Administrative CRUD endpoints for managing exam questions. Requires the ADMIN role."},{"name":"Subscriptions","description":"Endpoints for the authenticated user to view, start, and cancel their own subscription. Requires an authenticated user."},{"name":"Progress","description":"Endpoints for reading and updating the authenticated user's exam progress across topics and subtopics. Requires an ADMIN role or an active subscription."},{"name":"User","description":"Endpoint for fetching the authenticated user's own profile. Requires an authenticated user."}],"paths":{"/redirect/flitt/success":{"get":{"tags":["Flitt Redirects"],"summary":"Redirect after successful payment","description":"Issues a 303 redirect to the frontend's localized subscription-success page, preserving the original query string.","operationId":"flittRedirectSuccess","responses":{"200":{"description":"OK"}}},"post":{"tags":["Flitt Redirects"],"summary":"Redirect after successful payment","description":"Issues a 303 redirect to the frontend's localized subscription-success page, preserving the original query string.","operationId":"flittRedirectSuccess_1","responses":{"200":{"description":"OK"}}}},"/redirect/flitt/fail":{"get":{"tags":["Flitt Redirects"],"summary":"Redirect after failed payment","description":"Issues a 303 redirect to the frontend's localized subscription-fail page, preserving the original query string.","operationId":"flittRedirectFail","responses":{"200":{"description":"OK"}}},"post":{"tags":["Flitt Redirects"],"summary":"Redirect after failed payment","description":"Issues a 303 redirect to the frontend's localized subscription-fail page, preserving the original query string.","operationId":"flittRedirectFail_1","responses":{"200":{"description":"OK"}}}},"/api/topics/{id}":{"get":{"tags":["Topics"],"summary":"Get topic by ID","description":"Returns the single topic matching the given identifier.","operationId":"topicsGet","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TopicDto"}}}}},"security":[{"bearerAuth":[]}]},"put":{"tags":["Topics"],"summary":"Update a topic","description":"Updates the topic matching the given identifier with the supplied data. Restricted to users with the ADMIN role.","operationId":"adminTopicsUpdate","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopicRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TopicDto"}}}}},"security":[{"bearerAuth":[]}]},"delete":{"tags":["Topics"],"summary":"Delete a topic","description":"Deletes the topic matching the given identifier. Restricted to users with the ADMIN role.","operationId":"adminTopicsDelete","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OK"}},"security":[{"bearerAuth":[]}]}},"/api/business/topics/{id}":{"put":{"tags":["Admin: Topics"],"summary":"Update a topic","description":"Updates the topic matching the given identifier, including its per-language translations.","operationId":"adminBusinessTopicsUpdate","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopicRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TopicDto"}}}}},"security":[{"bearerAuth":[]}]},"delete":{"tags":["Admin: Topics"],"summary":"Delete a topic","description":"Deletes the topic matching the given identifier.","operationId":"adminBusinessTopicsDelete","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OK"}},"security":[{"bearerAuth":[]}]}},"/api/business/subscriptions/{id}/resume":{"put":{"tags":["Admin: Subscriptions"],"summary":"Resume a subscription","description":"Resumes the previously paused subscription matching the given identifier.","operationId":"adminSubscriptionsResume","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AdminSubscriptionDto"}}}}},"security":[{"bearerAuth":[]}]}},"/api/business/subscriptions/{id}/pause":{"put":{"tags":["Admin: Subscriptions"],"summary":"Pause a subscription","description":"Pauses the subscription matching the given identifier.","operationId":"adminSubscriptionsPause","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AdminSubscriptionDto"}}}}},"security":[{"bearerAuth":[]}]}},"/api/business/questions/{id}":{"put":{"tags":["Admin: Questions"],"summary":"Update a question","description":"Updates the question matching the given identifier with the supplied data.","operationId":"adminQuestionsUpdate","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuestionRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/QuestionDto"}}}}},"security":[{"bearerAuth":[]}]},"delete":{"tags":["Admin: Questions"],"summary":"Delete a question","description":"Deletes the question matching the given identifier.","operationId":"adminQuestionsDelete","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OK"}},"security":[{"bearerAuth":[]}]}},"/api/user/progress/subtopic/{subtopicId}":{"get":{"tags":["Progress"],"summary":"Get progress for a subtopic","description":"Returns the authenticated user's current progress within the given subtopic.","operationId":"progressGetSubtopic","parameters":[{"name":"subtopicId","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SubtopicProgressDto"}}}}},"security":[{"bearerAuth":[]}]},"post":{"tags":["Progress"],"summary":"Update subtopic progress","description":"Sets the authenticated user's current question index within the given subtopic to the value supplied under the 'currentIndex' key.","operationId":"progressUpdateSubtopic","parameters":[{"name":"subtopicId","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"integer","format":"int32"}}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SubtopicProgressDto"}}}}},"security":[{"bearerAuth":[]}]}},"/api/topics":{"get":{"tags":["Topics"],"summary":"List all topics","description":"Returns every exam topic available to subscribers and admins.","operationId":"topicsList","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TopicDto"}}}}}},"security":[{"bearerAuth":[]}]},"post":{"tags":["Topics"],"summary":"Create a topic","description":"Creates a new exam topic from the supplied request. Restricted to users with the ADMIN role.","operationId":"adminTopicsCreate","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopicRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TopicDto"}}}}},"security":[{"bearerAuth":[]}]}},"/api/subscriptions/checkout":{"post":{"tags":["Subscriptions"],"summary":"Create a checkout session","description":"Creates a Flitt redirect checkout for the given plan and returns the data needed to redirect the user to the payment page, defaulting the language to English if not supplied.","operationId":"subscriptionsCreateCheckout","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCheckoutRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CreateCheckoutResponse"}}}}},"security":[{"bearerAuth":[]}]}},"/api/subscriptions/cancel":{"post":{"tags":["Subscriptions"],"summary":"Cancel current subscription","description":"Cancels the authenticated user's active subscription, identified by their email.","operationId":"subscriptionsCancel","responses":{"200":{"description":"OK"}},"security":[{"bearerAuth":[]}]}},"/api/flitt/confirm":{"post":{"tags":["Flitt Webhooks"],"summary":"Confirm Flitt payment","description":"Marks the subscription matching the given order ID as active when Flitt reports the order status as approved.","operationId":"flittWebhookConfirm","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"object"}}}},"required":true},"responses":{"200":{"description":"OK"}}}},"/api/flitt/callback":{"post":{"tags":["Flitt Webhooks"],"summary":"Handle Flitt order callback","description":"Receives an order status callback from Flitt and updates the matching subscription's state accordingly.","operationId":"flittWebhookCallback","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"object"}}}},"required":true},"responses":{"200":{"description":"OK"}}}},"/api/feedback":{"post":{"tags":["Feedback"],"summary":"Submit feedback","description":"Saves a feedback message with a subject and body, attributed to the authenticated user's email.","operationId":"feedbackSubmit","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackRequest"}}},"required":true},"responses":{"200":{"description":"OK"}},"security":[{"bearerAuth":[]}]}},"/api/exam/submit":{"post":{"tags":["Exam"],"summary":"Submit exam answers","description":"Grades the supplied list of answers and returns a review detailing correctness per question.","operationId":"examSubmit","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnswerRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ExamReview"}}}}},"security":[{"bearerAuth":[]}]}},"/api/business/topics":{"get":{"tags":["Admin: Topics"],"summary":"List all topics","description":"Returns all topics formatted as TopicDto objects, including their translations.","operationId":"adminBusinessTopicsList","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TopicDto"}}}}}},"security":[{"bearerAuth":[]}]},"post":{"tags":["Admin: Topics"],"summary":"Create a topic","description":"Creates a new topic from the supplied request, including its per-language translations.","operationId":"adminBusinessTopicsCreate","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopicRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TopicDto"}}}}},"security":[{"bearerAuth":[]}]}},"/api/business/questions":{"get":{"tags":["Admin: Questions"],"summary":"List all questions","description":"Returns a paginated list of all exam questions across every topic.","operationId":"adminQuestionsList","parameters":[{"name":"pageable","in":"query","required":true,"schema":{"$ref":"#/components/schemas/Pageable"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PageQuestionDto"}}}}},"security":[{"bearerAuth":[]}]},"post":{"tags":["Admin: Questions"],"summary":"Create a question","description":"Creates a new exam question from the supplied request.","operationId":"adminQuestionsCreate","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuestionRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/QuestionDto"}}}}},"security":[{"bearerAuth":[]}]}},"/api/auth/reset-password":{"post":{"tags":["Auth"],"summary":"Reset password with token","description":"Validates the password-reset token and updates the user's password to the supplied new value.","operationId":"authResetPassword","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}},"required":true},"responses":{"200":{"description":"OK"}}}},"/api/auth/register":{"post":{"tags":["Auth"],"summary":"Register a new user","description":"Creates a new user account from the supplied registration details and sends a localized confirmation/notification according to the given language.","operationId":"authRegister","parameters":[{"name":"lang","in":"query","description":"Language code used for user-facing confirmation messages","required":false,"schema":{"type":"string","default":"en"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterRequest"}}},"required":true},"responses":{"200":{"description":"OK"}}}},"/api/auth/refresh":{"post":{"tags":["Auth"],"summary":"Refresh access token","description":"Exchanges a valid refresh token for a new pair of access and refresh tokens.","operationId":"authRefreshToken","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}}}}},"/api/auth/login":{"post":{"tags":["Auth"],"summary":"Log in with credentials","description":"Authenticates a user with email and password and returns access and refresh tokens.","operationId":"authLogin","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}}}}},"/api/auth/google":{"post":{"tags":["Auth"],"summary":"Log in with Google","description":"Verifies the supplied Google ID token and logs the user in, creating an account if one does not already exist, then returns access and refresh tokens.","operationId":"authGoogleLogin","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GoogleLoginRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AuthResponse"}}}}}}},"/api/auth/forgot-password":{"post":{"tags":["Auth"],"summary":"Request password reset","description":"Sends a localized password-reset email to the given address if a matching account exists.","operationId":"authForgotPassword","parameters":[{"name":"lang","in":"query","description":"Language code used for the password-reset email","required":false,"schema":{"type":"string","default":"en"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}},"required":true},"responses":{"200":{"description":"OK"}}}},"/api/user/progress/topics":{"get":{"tags":["Progress"],"summary":"Get progress for all topics","description":"Returns the authenticated user's progress summary across every topic.","operationId":"progressGetAllTopics","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TopicProgressDto"}}}}}},"security":[{"bearerAuth":[]}]}},"/api/user/progress/topic/{topicId}":{"get":{"tags":["Progress"],"summary":"Get progress for a topic","description":"Returns the authenticated user's progress for each subtopic within the given topic.","operationId":"progressGetTopic","parameters":[{"name":"topicId","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SubtopicProgressDto"}}}}}},"security":[{"bearerAuth":[]}]}},"/api/user/profile":{"get":{"tags":["User"],"summary":"Get current user profile","description":"Returns the profile of the currently authenticated user, looked up by the email in their security principal.","operationId":"userGetProfile","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UserProfileDto"}}}}},"security":[{"bearerAuth":[]}]}},"/api/topics/{topicId}/subtopics/{subtopicId}/questions":{"get":{"tags":["Subtopics"],"summary":"List questions for a subtopic","description":"Returns the questions belonging to the given subtopic, under the given topic, translated into the requested language.","operationId":"subtopicsGetQuestions","parameters":[{"name":"topicId","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"subtopicId","in":"path","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"lang","in":"query","description":"Language code for the returned question text","required":false,"schema":{"type":"string","default":"en"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/QuestionDto"}}}}}},"security":[{"bearerAuth":[]}]}},"/api/subscriptions/me":{"get":{"tags":["Subscriptions"],"summary":"Get current user's subscription","description":"Returns the authenticated user's own subscription details, looked up by their email.","operationId":"subscriptionsGetMine","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SubscriptionMeDto"}}}}},"security":[{"bearerAuth":[]}]}},"/api/subscription/plans":{"get":{"tags":["Subscription Plans"],"summary":"List subscription plans","description":"Returns every subscription plan defined by the system, mapped from the SubscriptionPlan enum to its display DTO.","operationId":"subscriptionPlansList","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SubscriptionPlanDto"}}}}}},"security":[{"bearerAuth":[]}]}},"/api/exam/paper":{"get":{"tags":["Exam"],"summary":"Get generated exam paper","description":"Builds and returns an exam paper composed of topic sections, each containing a number of randomly selected questions per topic in the requested language.","operationId":"examGetPaper","parameters":[{"name":"lang","in":"query","description":"Language code for the returned question text","required":false,"schema":{"type":"string","default":"en"}},{"name":"perTopic","in":"query","description":"Number of questions to include per topic","required":false,"schema":{"type":"integer","format":"int32","default":10}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ExamTopicSection"}}}}}},"security":[{"bearerAuth":[]}]}},"/api/business/subscriptions":{"get":{"tags":["Admin: Subscriptions"],"summary":"List all subscriptions","description":"Returns every user subscription in the system.","operationId":"adminSubscriptionsList","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AdminSubscriptionDto"}}}}}},"security":[{"bearerAuth":[]}]}},"/api/business/questions/topic/{topicId}":{"get":{"tags":["Admin: Questions"],"summary":"List questions by topic","description":"Returns every question belonging to the given topic.","operationId":"adminQuestionsListByTopic","parameters":[{"name":"topicId","in":"path","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/QuestionDto"}}}}}},"security":[{"bearerAuth":[]}]}}},"components":{"schemas":{"TopicRequest":{"type":"object","properties":{"translations":{"type":"array","items":{"$ref":"#/components/schemas/TranslationDto"}}}},"TranslationDto":{"type":"object","properties":{"languageCode":{"type":"string"},"text":{"type":"string"}}},"SubTopicDto":{"type":"object","properties":{"id":{"type":"integer","format":"int32"},"translations":{"type":"array","items":{"$ref":"#/components/schemas/TranslationDto"}},"topic":{"$ref":"#/components/schemas/TopicDto"},"totalQuestions":{"type":"integer","format":"int32"}}},"TopicDto":{"type":"object","properties":{"id":{"type":"integer","format":"int32"},"translations":{"type":"array","items":{"$ref":"#/components/schemas/TranslationDto"}},"subTopics":{"type":"array","items":{"$ref":"#/components/schemas/SubTopicDto"}}}},"AdminSubscriptionDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"},"plan":{"type":"string"},"priceCents":{"type":"integer","format":"int32"},"currency":{"type":"string"},"startDate":{"type":"string","format":"date-time"},"currentPeriodEnd":{"type":"string","format":"date-time"},"userEmail":{"type":"string"}}},"ChoiceRequest":{"type":"object","properties":{"textEn":{"type":"string"},"textKa":{"type":"string"},"textRu":{"type":"string"},"correct":{"type":"boolean"}}},"QuestionRequest":{"type":"object","properties":{"subTopicId":{"type":"integer","format":"int32"},"textEn":{"type":"string"},"textKa":{"type":"string"},"textRu":{"type":"string"},"choices":{"type":"array","items":{"$ref":"#/components/schemas/ChoiceRequest"}}}},"ChoiceDto":{"type":"object","properties":{"id":{"type":"integer","format":"int32"},"translations":{"type":"array","items":{"$ref":"#/components/schemas/TranslationDto"}},"correct":{"type":"boolean"}}},"QuestionDto":{"type":"object","properties":{"id":{"type":"integer","format":"int32"},"subTopic":{"$ref":"#/components/schemas/SubTopicDto"},"translations":{"type":"array","items":{"$ref":"#/components/schemas/TranslationDto"}},"choices":{"type":"array","items":{"$ref":"#/components/schemas/ChoiceDto"}}}},"SubtopicProgressDto":{"type":"object","properties":{"subtopicId":{"type":"integer","format":"int32"},"currentIndex":{"type":"integer","format":"int32"},"answeredCount":{"type":"integer","format":"int32"},"totalQuestions":{"type":"integer","format":"int64"},"percentage":{"type":"integer","format":"int32"}}},"CreateCheckoutRequest":{"type":"object","properties":{"plan":{"type":"string","enum":["ONE_MONTH","THREE_MONTH","SIX_MONTH"]},"lang":{"type":"string"}}},"CreateCheckoutResponse":{"type":"object","properties":{"data":{"type":"object","additionalProperties":{"type":"object"}}}},"FeedbackRequest":{"type":"object","properties":{"subject":{"type":"string"},"textBody":{"type":"string"}}},"AnswerRequest":{"type":"object","properties":{"answers":{"type":"object","additionalProperties":{"type":"integer","format":"int32"}}}},"CorrectedAnswer":{"type":"object","properties":{"questionId":{"type":"integer","format":"int32"},"correctChoiceId":{"type":"integer","format":"int32"},"userChoiceId":{"type":"integer","format":"int32"}}},"ExamReview":{"type":"object","properties":{"score":{"type":"integer","format":"int32"},"totalQuestions":{"type":"integer","format":"int32"},"incorrectAnswers":{"type":"array","items":{"$ref":"#/components/schemas/CorrectedAnswer"}}}},"RegisterRequest":{"type":"object","properties":{"email":{"type":"string"},"password":{"type":"string"}}},"AuthResponse":{"type":"object","properties":{"token":{"type":"string"},"refreshToken":{"type":"string"},"id":{"type":"string","format":"uuid"},"email":{"type":"string"},"role":{"type":"string","enum":["USER","ADMIN"]}}},"LoginRequest":{"type":"object","properties":{"email":{"type":"string"},"password":{"type":"string"}}},"GoogleLoginRequest":{"type":"object","properties":{"idToken":{"type":"string"}}},"TopicProgressDto":{"type":"object","properties":{"topicId":{"type":"integer","format":"int32"},"answered":{"type":"integer","format":"int64"},"total":{"type":"integer","format":"int64"},"percentage":{"type":"integer","format":"int32"}}},"UserProfileDto":{"type":"object","properties":{"email":{"type":"string"},"roles":{"type":"array","items":{"type":"string"}},"hasSubscription":{"type":"boolean"},"subscriptionStart":{"type":"string","format":"date-time"},"subscriptionEnd":{"type":"string","format":"date-time"}}},"SubscriptionMeDto":{"type":"object","properties":{"status":{"type":"string","enum":["ACTIVE","PAUSED","CANCELED","EXPIRED"]},"plan":{"type":"string","enum":["ONE_MONTH","THREE_MONTH","SIX_MONTH"]},"priceCents":{"type":"integer","format":"int32"},"currency":{"type":"string"},"startDate":{"type":"string","format":"date-time"},"currentPeriodEnd":{"type":"string","format":"date-time"}}},"SubscriptionPlanDto":{"type":"object","properties":{"code":{"type":"string"},"label":{"type":"string"},"months":{"type":"integer","format":"int32"},"priceCents":{"type":"integer","format":"int32"},"salePriceCents":{"type":"integer","format":"int32"},"saleActive":{"type":"boolean"},"activePrice":{"type":"integer","format":"int32"}}},"ChoiceResponse":{"type":"object","properties":{"id":{"type":"integer","format":"int32"},"text":{"type":"string"}}},"ExamTopicSection":{"type":"object","properties":{"topicId":{"type":"integer","format":"int32"},"topicTranslations":{"type":"array","items":{"$ref":"#/components/schemas/TranslationDto"}},"questions":{"type":"array","items":{"$ref":"#/components/schemas/QuestionResponse"}}}},"QuestionResponse":{"type":"object","properties":{"id":{"type":"integer","format":"int32"},"text":{"type":"string"},"choices":{"type":"array","items":{"$ref":"#/components/schemas/ChoiceResponse"}}}},"Pageable":{"type":"object","properties":{"page":{"minimum":0,"type":"integer","format":"int32"},"size":{"minimum":1,"type":"integer","format":"int32"},"sort":{"type":"array","items":{"type":"string"}}}},"PageQuestionDto":{"type":"object","properties":{"totalElements":{"type":"integer","format":"int64"},"totalPages":{"type":"integer","format":"int32"},"first":{"type":"boolean"},"last":{"type":"boolean"},"pageable":{"$ref":"#/components/schemas/PageableObject"},"size":{"type":"integer","format":"int32"},"content":{"type":"array","items":{"$ref":"#/components/schemas/QuestionDto"}},"number":{"type":"integer","format":"int32"},"sort":{"type":"array","items":{"$ref":"#/components/schemas/SortObject"}},"numberOfElements":{"type":"integer","format":"int32"},"empty":{"type":"boolean"}}},"PageableObject":{"type":"object","properties":{"paged":{"type":"boolean"},"pageNumber":{"type":"integer","format":"int32"},"pageSize":{"type":"integer","format":"int32"},"offset":{"type":"integer","format":"int64"},"sort":{"type":"array","items":{"$ref":"#/components/schemas/SortObject"}},"unpaged":{"type":"boolean"}}},"SortObject":{"type":"object","properties":{"direction":{"type":"string"},"nullHandling":{"type":"string"},"ascending":{"type":"boolean"},"property":{"type":"string"},"ignoreCase":{"type":"boolean"}}}},"securitySchemes":{"bearerAuth":{"type":"http","description":"JWT access token issued by POST /api/auth/login, /api/auth/google or /api/auth/refresh. Send as 'Authorization: Bearer <token>'.","scheme":"bearer","bearerFormat":"JWT"}}}}