{"openapi":"3.1.0","info":{"title":"LinguaTrack API","description":"Backend for LinguaTrack Custom GPT App","version":"1.0.0"},"servers":[{"url":"https://lingotrack.duckdns.org"}],"paths":{"/api/v1/auth/keys":{"post":{"tags":["auth"],"summary":"Issue a personal LinguaTrack key (no signup)","description":"Create a fresh learner profile and hand back a long-lived MCP key.\n\nThis is what the landing page's \"Get your key\" button calls. There is no signup\nand no email: the key *is* the account, so whoever holds it owns that learner's\nerror history. Abuse is bounded by the nginx rate limit on this path.","operationId":"issueKey","requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/KeyRequest"},{"type":"null"}],"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/auth/dev-login":{"get":{"tags":["auth"],"summary":"Mock login for development","description":"Mock login endpoint to easily get a JWT for testing without real Google OAuth.","operationId":"devLogin","parameters":[{"name":"email","in":"query","required":false,"schema":{"type":"string","default":"test@linguatrack.com","title":"Email"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/auth/me":{"get":{"tags":["auth"],"summary":"Get current authenticated user info","description":"Returns info about the currently authenticated user.","operationId":"getCurrentUser","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/errors":{"get":{"tags":["errors"],"summary":"Get user's tracked errors","operationId":"getUserErrors","security":[{"HTTPBearer":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","description":"Filter: active, improving, resolved","title":"Status"},"description":"Filter: active, improving, resolved"},{"name":"category","in":"query","required":false,"schema":{"type":"string","description":"Filter: GRAMMAR, VOCABULARY, PRONUNCIATION, STYLE","title":"Category"},"description":"Filter: GRAMMAR, VOCABULARY, PRONUNCIATION, STYLE"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","description":"Max entries to return","default":50,"title":"Limit"},"description":"Max entries to return"},{"name":"order_by","in":"query","required":false,"schema":{"type":"string","description":"Sorting: frequency_desc, last_seen_desc, created_desc","default":"frequency_desc","title":"Order By"},"description":"Sorting: frequency_desc, last_seen_desc, created_desc"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/errors/batch":{"post":{"tags":["errors"],"summary":"Save a batch of errors from the current session","operationId":"saveErrorsBatch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBatchCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBatchResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/errors/{error_id}/status":{"put":{"tags":["errors"],"summary":"Update error status","operationId":"updateErrorStatus","security":[{"HTTPBearer":[]}],"parameters":[{"name":"error_id","in":"path","required":true,"schema":{"type":"integer","title":"Error Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorStatusUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/sessions":{"post":{"tags":["sessions"],"summary":"Start a new learning session","operationId":"createSession","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/sessions/{session_id}":{"put":{"tags":["sessions"],"summary":"Update session with summary","operationId":"updateSession","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"integer","title":"Session Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/progress":{"get":{"tags":["progress"],"summary":"Get aggregated progress report","operationId":"getUserProgress","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProgressReportResponse"}}}}},"security":[{"HTTPBearer":[]}]}},"/health":{"get":{"tags":["system"],"summary":"Health check endpoint","description":"System health check endpoint","operationId":"health_check","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"ActiveErrorProgress":{"properties":{"id":{"type":"integer","title":"Id"},"category":{"type":"string","title":"Category"},"subcategory":{"type":"string","title":"Subcategory"},"frequency":{"type":"integer","title":"Frequency"},"last_example":{"type":"string","title":"Last Example"},"status":{"type":"string","title":"Status"},"first_seen_at":{"type":"string","format":"date-time","title":"First Seen At"}},"type":"object","required":["id","category","subcategory","frequency","last_example","status","first_seen_at"],"title":"ActiveErrorProgress"},"ErrorBatchCreate":{"properties":{"session_id":{"type":"integer","title":"Session Id"},"errors":{"items":{"$ref":"#/components/schemas/ErrorCreate"},"type":"array","title":"Errors"}},"type":"object","required":["session_id","errors"],"title":"ErrorBatchCreate"},"ErrorBatchResponse":{"properties":{"saved":{"type":"integer","title":"Saved"},"deduplicated":{"type":"integer","title":"Deduplicated"},"new":{"type":"integer","title":"New"},"updated_ids":{"items":{"type":"integer"},"type":"array","title":"Updated Ids"},"created_ids":{"items":{"type":"integer"},"type":"array","title":"Created Ids"}},"type":"object","required":["saved","deduplicated","new","updated_ids","created_ids"],"title":"ErrorBatchResponse"},"ErrorCreate":{"properties":{"category":{"type":"string","title":"Category"},"subcategory":{"type":"string","title":"Subcategory"},"student_said":{"type":"string","title":"Student Said"},"correct_version":{"type":"string","title":"Correct Version"},"explanation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Explanation"},"severity":{"type":"string","title":"Severity","default":"medium"}},"type":"object","required":["category","subcategory","student_said","correct_version"],"title":"ErrorCreate"},"ErrorListResponse":{"properties":{"total":{"type":"integer","title":"Total"},"errors":{"items":{"$ref":"#/components/schemas/ErrorResponse"},"type":"array","title":"Errors"}},"type":"object","required":["total","errors"],"title":"ErrorListResponse"},"ErrorResponse":{"properties":{"id":{"type":"integer","title":"Id"},"category":{"type":"string","title":"Category"},"subcategory":{"type":"string","title":"Subcategory"},"student_said":{"type":"string","title":"Student Said"},"correct_version":{"type":"string","title":"Correct Version"},"explanation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Explanation"},"severity":{"type":"string","title":"Severity"},"frequency":{"type":"integer","title":"Frequency"},"status":{"type":"string","title":"Status"},"first_seen_at":{"type":"string","format":"date-time","title":"First Seen At"},"last_seen_at":{"type":"string","format":"date-time","title":"Last Seen At"}},"type":"object","required":["id","category","subcategory","student_said","correct_version","severity","frequency","status","first_seen_at","last_seen_at"],"title":"ErrorResponse"},"ErrorStatusResponse":{"properties":{"id":{"type":"integer","title":"Id"},"status":{"type":"string","title":"Status"},"previous_status":{"type":"string","title":"Previous Status"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","status","previous_status","updated_at"],"title":"ErrorStatusResponse"},"ErrorStatusUpdate":{"properties":{"status":{"type":"string","title":"Status"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"}},"type":"object","required":["status"],"title":"ErrorStatusUpdate"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ImprovingErrorProgress":{"properties":{"id":{"type":"integer","title":"Id"},"category":{"type":"string","title":"Category"},"subcategory":{"type":"string","title":"Subcategory"},"frequency":{"type":"integer","title":"Frequency"},"last_example":{"type":"string","title":"Last Example"},"status":{"type":"string","title":"Status"},"improvement_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Improvement Note"}},"type":"object","required":["id","category","subcategory","frequency","last_example","status"],"title":"ImprovingErrorProgress"},"KeyRequest":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Name"},"cefr_level":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cefr Level","description":"A1…C2"},"native_language":{"anyOf":[{"type":"string","maxLength":10},{"type":"null"}],"title":"Native Language"}},"type":"object","title":"KeyRequest","description":"Everything is optional — the zero-friction path is an empty POST body."},"KeyResponse":{"properties":{"access_token":{"type":"string","title":"Access Token"},"token_type":{"type":"string","title":"Token Type","default":"bearer"},"expires_in":{"type":"integer","title":"Expires In"},"user_id":{"type":"string","title":"User Id"},"mcp_url":{"type":"string","title":"Mcp Url"},"api_url":{"type":"string","title":"Api Url"}},"type":"object","required":["access_token","expires_in","user_id","mcp_url","api_url"],"title":"KeyResponse"},"ProgressReportResponse":{"properties":{"user":{"$ref":"#/components/schemas/UserProgressInfo"},"active_errors":{"items":{"$ref":"#/components/schemas/ActiveErrorProgress"},"type":"array","title":"Active Errors"},"improving_errors":{"items":{"$ref":"#/components/schemas/ImprovingErrorProgress"},"type":"array","title":"Improving Errors"},"resolved_count":{"type":"integer","title":"Resolved Count"},"top_weak_areas":{"items":{"$ref":"#/components/schemas/WeakAreaProgress"},"type":"array","title":"Top Weak Areas"},"recent_improvement":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recent Improvement"},"recommendation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recommendation"}},"type":"object","required":["user","active_errors","improving_errors","resolved_count","top_weak_areas"],"title":"ProgressReportResponse"},"SessionCreate":{"properties":{"mode":{"type":"string","title":"Mode"}},"type":"object","required":["mode"],"title":"SessionCreate"},"SessionResponse":{"properties":{"id":{"type":"integer","title":"Id"},"mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mode"},"started_at":{"type":"string","format":"date-time","title":"Started At"}},"type":"object","required":["id","mode","started_at"],"title":"SessionResponse"},"SessionUpdate":{"properties":{"messages_count":{"type":"integer","title":"Messages Count"},"errors_found":{"type":"integer","title":"Errors Found"},"topic":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Topic"},"cefr_level_observed":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cefr Level Observed"},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary"}},"type":"object","required":["messages_count","errors_found"],"title":"SessionUpdate"},"UserProgressInfo":{"properties":{"cefr_level":{"type":"string","title":"Cefr Level"},"sessions_count":{"type":"integer","title":"Sessions Count"},"total_errors_tracked":{"type":"integer","title":"Total Errors Tracked"},"member_since":{"type":"string","title":"Member Since"}},"type":"object","required":["cefr_level","sessions_count","total_errors_tracked","member_since"],"title":"UserProgressInfo"},"UserResponse":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"cefr_level":{"type":"string","title":"Cefr Level","default":"A2"},"native_language":{"type":"string","title":"Native Language","default":"ru"},"id":{"type":"string","format":"uuid","title":"Id"},"email":{"type":"string","format":"email","title":"Email"},"session_count":{"type":"integer","title":"Session Count"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","email","session_count","created_at"],"title":"UserResponse"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"WeakAreaProgress":{"properties":{"category":{"type":"string","title":"Category"},"subcategory":{"type":"string","title":"Subcategory"},"total_frequency":{"type":"integer","title":"Total Frequency"}},"type":"object","required":["category","subcategory","total_frequency"],"title":"WeakAreaProgress"}},"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}}},"security":[{"BearerAuth":[]}]}