{"openapi":"3.1.0","info":{"title":"DMS Simulation Platform","version":"1.0.0"},"paths":{"/health":{"get":{"tags":["Meta"],"summary":"Health","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Health Health Get"},"example":{"status":"success","data":{"ok":true,"service":"DMS Simulation Platform","env":"production"},"message":"Success"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"422":{"description":"Validation Error – invalid request body","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Validation error. Please check your input.","errors":{"detail":[{"type":"missing","loc":["body","email"],"msg":"Field required","input":{}}],"request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[]}},"/api/v1/auth/master/verify-otp":{"post":{"tags":["Auth Master"],"summary":"Master Verify Otp Route","operationId":"master_verify_otp_route_api_v1_auth_master_verify_otp_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyOtpIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"purpose":"first_login","token":"<otp-verify-token>","expires_in_minutes":10},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[]}},"/api/v1/auth/master/set-password":{"post":{"tags":["Auth Master"],"summary":"Master Set Password Route","operationId":"master_set_password_route_api_v1_auth_master_set_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPasswordIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"ok":true},"message":"Password set successfully"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[]}},"/api/v1/auth/master/check-email":{"post":{"tags":["Auth Master"],"summary":"Master Check Email Route","operationId":"master_check_email_route_api_v1_auth_master_check_email_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckEmailIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[]}},"/api/v1/auth/master/login":{"post":{"tags":["Auth Master"],"summary":"Master Login Route","operationId":"master_login_route_api_v1_auth_master_login_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"access_token":"<jwt-access-token>","refresh_token":"<jwt-refresh-token>","token_type":"bearer","user":{"id":1,"email":"user@example.com","full_name":"Jane Doe","country":"ZA","contact_no":"+27821234567","user_type":"org_admin","role":"Organisation Admin","organisation_id":1,"organisation_name":"Acme Mining","first_login_complete":true,"is_active":true}},"message":"Login successful"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[]}},"/api/v1/auth/master/login/request-otp":{"post":{"tags":["Auth Master"],"summary":"Master Login Request Otp Route","operationId":"master_login_request_otp_route_api_v1_auth_master_login_request_otp_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginOtpRequestIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"ok":true},"message":"OTP sent to your email"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[]}},"/api/v1/auth/master/login/verify-otp":{"post":{"tags":["Auth Master"],"summary":"Master Login Verify Otp Route","operationId":"master_login_verify_otp_route_api_v1_auth_master_login_verify_otp_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginOtpVerifyIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"access_token":"<jwt-access-token>","refresh_token":"<jwt-refresh-token>","token_type":"bearer","user":{"id":1,"email":"user@example.com","full_name":"Jane Doe","country":"ZA","contact_no":"+27821234567","user_type":"org_admin","role":"Organisation Admin","organisation_id":1,"organisation_name":"Acme Mining","first_login_complete":true,"is_active":true}},"message":"Login successful"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[]}},"/api/v1/auth/master/forgot-password":{"post":{"tags":["Auth Master"],"summary":"Master Forgot Password Route","operationId":"master_forgot_password_route_api_v1_auth_master_forgot_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForgotPasswordIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"ok":true},"message":"Password reset link sent"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[]}},"/api/v1/auth/master/reset-password":{"post":{"tags":["Auth Master"],"summary":"Master Reset Password Route","operationId":"master_reset_password_route_api_v1_auth_master_reset_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"ok":true},"message":"Password reset successfully"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[]}},"/api/v1/auth/master/refresh":{"post":{"tags":["Auth Master"],"summary":"Master Refresh Route","operationId":"master_refresh_route_api_v1_auth_master_refresh_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"access_token":"<jwt-access-token>","refresh_token":"<jwt-refresh-token>","token_type":"bearer","user":{"id":1,"email":"user@example.com","full_name":"Jane Doe","country":"ZA","contact_no":"+27821234567","user_type":"org_admin","role":"Organisation Admin","organisation_id":1,"organisation_name":"Acme Mining","first_login_complete":true,"is_active":true}},"message":"Token refreshed"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[]}},"/api/v1/auth/master/logout":{"post":{"tags":["Auth Master"],"summary":"Master Logout Route","operationId":"master_logout_route_api_v1_auth_master_logout_post","requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/LogoutIn"},{"type":"null"}],"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"ok":true},"message":"Logged out successfully"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/auth/master/logout-sessions":{"post":{"tags":["Auth Master"],"summary":"Master Logout Sessions Route","operationId":"master_logout_sessions_route_api_v1_auth_master_logout_sessions_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogoutSessionsIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/auth/master/sessions":{"get":{"tags":["Auth Master"],"summary":"Master Sessions Route","operationId":"master_sessions_route_api_v1_auth_master_sessions_get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/users/me":{"get":{"tags":["Users"],"summary":"Get Me Route","operationId":"get_me_route_api_v1_users_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":1,"email":"user@example.com","full_name":"Jane Doe","country":"ZA","contact_no":"+27821234567","user_type":"org_admin","role":"Organisation Admin","organisation_id":1,"organisation_name":"Acme Mining","first_login_complete":true,"is_active":true},"message":"Success"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"422":{"description":"Validation Error – invalid request body","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Validation error. Please check your input.","errors":{"detail":[{"type":"missing","loc":["body","email"],"msg":"Field required","input":{}}],"request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]},"patch":{"tags":["Users"],"summary":"Update Me Route","operationId":"update_me_route_api_v1_users_me_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeUpdateIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":1,"email":"user@example.com","full_name":"Jane Doe","country":"ZA","contact_no":"+27821234567","user_type":"org_admin","role":"Organisation Admin","organisation_id":1,"organisation_name":"Acme Mining","first_login_complete":true,"is_active":true},"message":"Profile updated"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/users/me/change-password":{"post":{"tags":["Users"],"summary":"Change Password Route","operationId":"change_password_route_api_v1_users_me_change_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePasswordIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"ok":true},"message":"Password changed successfully"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/users/{user_id}/resend-welcome":{"post":{"tags":["Admin Users"],"summary":"Resend Welcome Route","operationId":"resend_welcome_route_api_v1_admin_users__user_id__resend_welcome_post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"ok":true},"message":"Welcome email resent"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/roles":{"get":{"tags":["Roles"],"summary":"List Roles Route","operationId":"list_roles_route_api_v1_roles_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":[{"id":1,"name":"Master Admin","description":"Full platform access"},{"id":2,"name":"Organisation Admin","description":"Manage own organisation"},{"id":3,"name":"Student","description":"Access assigned simulations"}],"message":"Success"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"422":{"description":"Validation Error – invalid request body","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Validation error. Please check your input.","errors":{"detail":[{"type":"missing","loc":["body","email"],"msg":"Field required","input":{}}],"request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/modules":{"get":{"tags":["Modules"],"summary":"List Modules Route","operationId":"list_modules_route_api_v1_modules_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by module name or slug","title":"Q"},"description":"Search by module name or slug"},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/SimulationStatus"},{"type":"null"}],"title":"Status"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"items":[{"id":1,"name":"Mining Fundamentals","slug":"mining-fundamentals","description":"Core mining operations module.","icon":"https://s3.example.com/icons/mining.png","status":"active","display_order":1,"simulation_count":2,"simulations":[{"id":10,"name":"Open Pit Simulation","slug":"open-pit-simulation","module_id":1,"module":{"id":1,"name":"Mining Fundamentals","slug":"mining-fundamentals","icon":"https://s3.example.com/icons/mining.png"},"description":"Realistic open-pit mine simulation.","status":"active","passing_score":70,"duration_minutes":60,"expires_at":null,"cover_image_url":"https://s3.example.com/covers/open-pit.jpg","runner_url":"https://sim.dms-mining.com/open-pit","enrolled":95,"pass_rate":82.5,"avg_score":78.4}]}],"total":1,"page":1,"size":20,"pages":1},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]},"post":{"tags":["Modules"],"summary":"Create Module Route","operationId":"create_module_route_api_v1_modules_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModuleCreateIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":1,"name":"Mining Fundamentals","slug":"mining-fundamentals","description":"Core mining operations module.","icon":"https://s3.example.com/icons/mining.png","status":"active","display_order":1,"simulation_count":2,"simulations":[{"id":10,"name":"Open Pit Simulation","slug":"open-pit-simulation","module_id":1,"module":{"id":1,"name":"Mining Fundamentals","slug":"mining-fundamentals","icon":"https://s3.example.com/icons/mining.png"},"description":"Realistic open-pit mine simulation.","status":"active","passing_score":70,"duration_minutes":60,"expires_at":null,"cover_image_url":"https://s3.example.com/covers/open-pit.jpg","runner_url":"https://sim.dms-mining.com/open-pit","enrolled":95,"pass_rate":82.5,"avg_score":78.4}]},"message":"Module created"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/modules/{module_id}/analytics":{"get":{"tags":["Modules"],"summary":"Module Analytics Route","description":"Module detail with per-simulation attempt analytics (master admin).\n\nFor every simulation under the module: aggregate stats plus a per-player\nbreakdown — how many times each user played, their best/average score, and\nthe score of every individual attempt.","operationId":"module_analytics_route_api_v1_modules__module_id__analytics_get","parameters":[{"name":"module_id","in":"path","required":true,"schema":{"type":"integer","title":"Module Id"}},{"name":"simulation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Restrict to a single simulation in the module","title":"Simulation Id"},"description":"Restrict to a single simulation in the module"},{"name":"organisation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Restrict players to one organisation","title":"Organisation Id"},"description":"Restrict players to one organisation"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/modules/{module_id}":{"get":{"tags":["Modules"],"summary":"Get Module Route","operationId":"get_module_route_api_v1_modules__module_id__get","parameters":[{"name":"module_id","in":"path","required":true,"schema":{"type":"integer","title":"Module Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":1,"name":"Mining Fundamentals","slug":"mining-fundamentals","description":"Core mining operations module.","icon":"https://s3.example.com/icons/mining.png","status":"active","display_order":1,"simulation_count":2,"simulations":[{"id":10,"name":"Open Pit Simulation","slug":"open-pit-simulation","module_id":1,"module":{"id":1,"name":"Mining Fundamentals","slug":"mining-fundamentals","icon":"https://s3.example.com/icons/mining.png"},"description":"Realistic open-pit mine simulation.","status":"active","passing_score":70,"duration_minutes":60,"expires_at":null,"cover_image_url":"https://s3.example.com/covers/open-pit.jpg","runner_url":"https://sim.dms-mining.com/open-pit","enrolled":95,"pass_rate":82.5,"avg_score":78.4}]},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]},"patch":{"tags":["Modules"],"summary":"Update Module Route","operationId":"update_module_route_api_v1_modules__module_id__patch","parameters":[{"name":"module_id","in":"path","required":true,"schema":{"type":"integer","title":"Module Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModuleUpdateIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":1,"name":"Mining Fundamentals","slug":"mining-fundamentals","description":"Core mining operations module.","icon":"https://s3.example.com/icons/mining.png","status":"active","display_order":1,"simulation_count":2,"simulations":[{"id":10,"name":"Open Pit Simulation","slug":"open-pit-simulation","module_id":1,"module":{"id":1,"name":"Mining Fundamentals","slug":"mining-fundamentals","icon":"https://s3.example.com/icons/mining.png"},"description":"Realistic open-pit mine simulation.","status":"active","passing_score":70,"duration_minutes":60,"expires_at":null,"cover_image_url":"https://s3.example.com/covers/open-pit.jpg","runner_url":"https://sim.dms-mining.com/open-pit","enrolled":95,"pass_rate":82.5,"avg_score":78.4}]},"message":"Module updated"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]},"delete":{"tags":["Modules"],"summary":"Delete Module Route","operationId":"delete_module_route_api_v1_modules__module_id__delete","parameters":[{"name":"module_id","in":"path","required":true,"schema":{"type":"integer","title":"Module Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"ok":true},"message":"Module deleted"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/simulations":{"get":{"tags":["Simulations"],"summary":"List Simulations Route","operationId":"list_simulations_route_api_v1_simulations_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by simulation name or slug","title":"Q"},"description":"Search by simulation name or slug"},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/SimulationStatus"},{"type":"null"}],"title":"Status"}},{"name":"module_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Module Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"items":[{"id":10,"name":"Open Pit Simulation","slug":"open-pit-simulation","module_id":1,"module":{"id":1,"name":"Mining Fundamentals","slug":"mining-fundamentals","icon":"https://s3.example.com/icons/mining.png"},"description":"Realistic open-pit mine simulation.","status":"active","passing_score":70,"duration_minutes":60,"expires_at":null,"cover_image_url":"https://s3.example.com/covers/open-pit.jpg","runner_url":"https://sim.dms-mining.com/open-pit","enrolled":95,"pass_rate":82.5,"avg_score":78.4}],"total":1,"page":1,"size":20,"pages":1},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]},"post":{"tags":["Simulations"],"summary":"Create Simulation Route","operationId":"create_simulation_route_api_v1_simulations_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SimulationCreateIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":10,"name":"Open Pit Simulation","slug":"open-pit-simulation","module_id":1,"module":{"id":1,"name":"Mining Fundamentals","slug":"mining-fundamentals","icon":"https://s3.example.com/icons/mining.png"},"description":"Realistic open-pit mine simulation.","status":"active","passing_score":70,"duration_minutes":60,"expires_at":null,"cover_image_url":"https://s3.example.com/covers/open-pit.jpg","runner_url":"https://sim.dms-mining.com/open-pit","enrolled":95,"pass_rate":82.5,"avg_score":78.4},"message":"Simulation created"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/simulations/{simulation_id}":{"get":{"tags":["Simulations"],"summary":"Get Simulation Route","operationId":"get_simulation_route_api_v1_simulations__simulation_id__get","parameters":[{"name":"simulation_id","in":"path","required":true,"schema":{"type":"integer","title":"Simulation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":10,"name":"Open Pit Simulation","slug":"open-pit-simulation","module_id":1,"module":{"id":1,"name":"Mining Fundamentals","slug":"mining-fundamentals","icon":"https://s3.example.com/icons/mining.png"},"description":"Realistic open-pit mine simulation.","status":"active","passing_score":70,"duration_minutes":60,"expires_at":null,"cover_image_url":"https://s3.example.com/covers/open-pit.jpg","runner_url":"https://sim.dms-mining.com/open-pit","enrolled":95,"pass_rate":82.5,"avg_score":78.4},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]},"patch":{"tags":["Simulations"],"summary":"Update Simulation Route","operationId":"update_simulation_route_api_v1_simulations__simulation_id__patch","parameters":[{"name":"simulation_id","in":"path","required":true,"schema":{"type":"integer","title":"Simulation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SimulationUpdateIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":10,"name":"Open Pit Simulation","slug":"open-pit-simulation","module_id":1,"module":{"id":1,"name":"Mining Fundamentals","slug":"mining-fundamentals","icon":"https://s3.example.com/icons/mining.png"},"description":"Realistic open-pit mine simulation.","status":"active","passing_score":70,"duration_minutes":60,"expires_at":null,"cover_image_url":"https://s3.example.com/covers/open-pit.jpg","runner_url":"https://sim.dms-mining.com/open-pit","enrolled":95,"pass_rate":82.5,"avg_score":78.4},"message":"Simulation updated"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]},"delete":{"tags":["Simulations"],"summary":"Delete Simulation Route","operationId":"delete_simulation_route_api_v1_simulations__simulation_id__delete","parameters":[{"name":"simulation_id","in":"path","required":true,"schema":{"type":"integer","title":"Simulation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"ok":true},"message":"Simulation deleted"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/dashboard/admin/summary":{"get":{"tags":["Dashboard"],"summary":"Admin Summary Route","description":"KPI cards + alert strip for the master-admin dashboard.","operationId":"admin_summary_route_api_v1_dashboard_admin_summary_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"alerts":{"pending_licence_requests":5,"pools_expiring_in_7_days":2},"kpis":{"b2c_students":{"count":1000,"delta":{"value":50,"period":"week"},"capacity":2000,"capacity_pct":50.0},"b2b_organisations":{"count":50,"delta":{"value":3,"period":"week"},"org_students_total":5000},"active_enrolments":{"count":2500,"delta":{"value":200,"period":"week"},"split":{"b2c":1500,"b2b":1000}},"avg_score":{"value_pct":78.5,"total_completions":1200,"scope":"all"}}},"message":"Success"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"422":{"description":"Validation Error – invalid request body","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Validation error. Please check your input.","errors":{"detail":[{"type":"missing","loc":["body","email"],"msg":"Field required","input":{}}],"request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/dashboard/admin/module-performance":{"get":{"tags":["Dashboard"],"summary":"Admin Module Performance Route","description":"Per-simulation enrolled / completed / pass_rate / avg_score table.","operationId":"admin_module_performance_route_api_v1_dashboard_admin_module_performance_get","parameters":[{"name":"sort","in":"query","required":false,"schema":{"type":"string","pattern":"^(enrolled|completed|pass_rate_pct|avg_score|name)$","default":"enrolled","title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"modules":[{"simulation_id":10,"name":"Open Pit Simulation","slug":"open-pit-simulation","cover_image_url":"https://s3.example.com/covers/open-pit.jpg","passing_score":70,"enrolled":95,"completed":80,"avg_score":78.4,"pass_rate_pct":82.5}]},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/dashboard/admin/activity-feed":{"get":{"tags":["Dashboard"],"summary":"Admin Activity Feed Route","description":"Mixed activity_logs + synthesised system alerts, paginated.","operationId":"admin_activity_feed_route_api_v1_dashboard_admin_activity_feed_get","parameters":[{"name":"kinds","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"title":"Kinds"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"items":[{"kind":"user","title":"New student enrolled","secondary":"Alice Miner joined Open Pit Simulation","occurred_at":"2024-01-01T10:00:00","actor":{"id":2,"name":"John Smith"},"ref":{"table":"users","id":1002}}],"total":1,"page":1,"size":20,"pages":1},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/dashboard/admin":{"get":{"tags":["Dashboard"],"summary":"Admin Dashboard Route","description":"**Deprecated.** Use ``/dashboard/admin/summary`` for the alerts + KPI\ncards, ``/dashboard/admin/module-performance`` for the per-sim table, and\n``/dashboard/admin/activity-feed`` for the recent-activity stream.\n\nKept for one release cycle so existing UI clients don't break. The shape\nis unchanged.","operationId":"admin_dashboard_route_api_v1_dashboard_admin_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"total_organisations":50,"active_organisations":48,"total_b2c_students":1000,"total_b2b_students":5000,"pending_licence_requests":5,"expiring_in_7_days":2,"total_simulations":100,"active_simulations":95,"attempts_last_7_days":500},"message":"Success"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"422":{"description":"Validation Error – invalid request body","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Validation error. Please check your input.","errors":{"detail":[{"type":"missing","loc":["body","email"],"msg":"Field required","input":{}}],"request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"deprecated":true,"security":[{"BearerAuth":[]}]}},"/api/v1/dashboard/org":{"get":{"tags":["Dashboard"],"summary":"Org Dashboard Route","operationId":"org_dashboard_route_api_v1_dashboard_org_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"organisation_id":1,"students":100,"active_licences":50,"pending_requests":3,"expiring_in_7_days":2,"attempts_last_7_days":50},"message":"Success"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"422":{"description":"Validation Error – invalid request body","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Validation error. Please check your input.","errors":{"detail":[{"type":"missing","loc":["body","email"],"msg":"Field required","input":{}}],"request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/dashboard/org/licence-pools":{"get":{"tags":["Dashboard"],"summary":"Org Licence Pools Route","description":"'My licence pools' widget: approved pools with used/total + expiry.","operationId":"org_licence_pools_route_api_v1_dashboard_org_licence_pools_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":5,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/dashboard/org/student-activity":{"get":{"tags":["Dashboard"],"summary":"Org Student Activity Route","description":"'Recent student activity' widget: latest attempts by org students.","operationId":"org_student_activity_route_api_v1_dashboard_org_student_activity_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":10,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/dashboard/student":{"get":{"tags":["Dashboard"],"summary":"Student Dashboard Route","operationId":"student_dashboard_route_api_v1_dashboard_student_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"user_id":1001,"available_simulations":10,"completed_attempts":25,"in_progress_attempts":2},"message":"Success"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"422":{"description":"Validation Error – invalid request body","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Validation error. Please check your input.","errors":{"detail":[{"type":"missing","loc":["body","email"],"msg":"Field required","input":{}}],"request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/b2c-students":{"get":{"tags":["Admin B2C"],"summary":"List B2C Route","operationId":"list_b2c_route_api_v1_admin_b2c_students_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by email or name","title":"Q"},"description":"Search by email or name"},{"name":"country","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(active|inactive)$"},{"type":"null"}],"description":"Filter by activation status","title":"Status"},"description":"Filter by activation status"},{"name":"simulation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Filter to students with active access to this simulation","title":"Simulation Id"},"description":"Filter to students with active access to this simulation"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"items":[{"id":1001,"email":"student@direct.com","full_name":"Alice Miner","country":"ZA","contact_no":"+27820001111","first_login_complete":true,"is_active":true,"created_at":"2024-01-01T00:00:00","assigned_simulations":2,"best_score":90.0,"simulations":[{"id":10,"name":"Open Pit Simulation","slug":"open-pit-simulation"}]}],"total":1,"page":1,"size":20,"pages":1},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]},"post":{"tags":["Admin B2C"],"summary":"Create B2C Route","operationId":"create_b2c_route_api_v1_admin_b2c_students_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/B2CStudentCreateIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":1001,"email":"student@direct.com","full_name":"Alice Miner","country":"ZA","contact_no":"+27820001111","first_login_complete":true,"is_active":true,"created_at":"2024-01-01T00:00:00","assigned_simulations":2,"best_score":90.0,"simulations":[{"id":10,"name":"Open Pit Simulation","slug":"open-pit-simulation"}]},"message":"Student created"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]},"delete":{"tags":["Admin B2C"],"summary":"Delete B2C Route","operationId":"delete_b2c_route_api_v1_admin_b2c_students_delete","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteB2CStudentsIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"deleted":3},"message":"Students deleted"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/b2c-students/sample-csv":{"get":{"tags":["Admin B2C"],"summary":"Sample Csv Route","operationId":"sample_csv_route_api_v1_admin_b2c_students_sample_csv_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"422":{"description":"Validation Error – invalid request body","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Validation error. Please check your input.","errors":{"detail":[{"type":"missing","loc":["body","email"],"msg":"Field required","input":{}}],"request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/b2c-students/export":{"get":{"tags":["Admin B2C"],"summary":"Export B2C Route","operationId":"export_b2c_route_api_v1_admin_b2c_students_export_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by email or name","title":"Q"},"description":"Search by email or name"},{"name":"country","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(active|inactive)$"},{"type":"null"}],"description":"Filter by activation status","title":"Status"},"description":"Filter by activation status"},{"name":"simulation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Filter to students with active access to this simulation","title":"Simulation Id"},"description":"Filter to students with active access to this simulation"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"download_url":"https://s3.example.com/exports/file.csv?X-Amz-Signature=…"},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/b2c-students/bulk-preview":{"post":{"tags":["Admin B2C"],"summary":"Bulk Preview Route","operationId":"bulk_preview_route_api_v1_admin_b2c_students_bulk_preview_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_bulk_preview_route_api_v1_admin_b2c_students_bulk_preview_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"rows":[{"email":"s1@direct.com","full_name":"Alice","country":"ZA","contact_no":"+27820001111","status":"new","message":null}]},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/b2c-students/bulk-import":{"post":{"tags":["Admin B2C"],"summary":"Bulk Import Route","operationId":"bulk_import_route_api_v1_admin_b2c_students_bulk_import_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_bulk_import_route_api_v1_admin_b2c_students_bulk_import_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"imported":8,"updated":1,"failed":1,"details":[]},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/b2c-students/{user_id}/scores/export":{"get":{"tags":["Admin B2C"],"summary":"Export B2C Scores Route","operationId":"export_b2c_scores_route_api_v1_admin_b2c_students__user_id__scores_export_get","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by simulation name or module name","title":"Q"},"description":"Search by simulation name or module name"},{"name":"simulation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Simulation Id"}},{"name":"date_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Date From"}},{"name":"date_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Date To"}},{"name":"min_minutes","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"title":"Min Minutes"}},{"name":"max_minutes","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"title":"Max Minutes"}},{"name":"result","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(pass|fail)$"},{"type":"null"}],"title":"Result"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"download_url":"https://s3.example.com/exports/file.csv?X-Amz-Signature=…"},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/b2c-students/{user_id}":{"get":{"tags":["Admin B2C"],"summary":"Get B2C Detail Route","operationId":"get_b2c_detail_route_api_v1_admin_b2c_students__user_id__get","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":1001,"email":"student@direct.com","full_name":"Alice Miner","country":"ZA","contact_no":"+27820001111","first_login_complete":true,"is_active":true,"created_at":"2024-01-01T00:00:00","assigned_simulations":2,"best_score":90.0,"simulations":[{"id":10,"name":"Open Pit Simulation","slug":"open-pit-simulation"}]},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/b2c-students/{user_id}/scores":{"get":{"tags":["Admin B2C"],"summary":"List B2C Student Scores Route","operationId":"list_b2c_student_scores_route_api_v1_admin_b2c_students__user_id__scores_get","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by simulation name or module name","title":"Q"},"description":"Search by simulation name or module name"},{"name":"simulation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Simulation Id"}},{"name":"date_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"description":"Inclusive lower bound on started_at","title":"Date From"},"description":"Inclusive lower bound on started_at"},{"name":"date_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"description":"Inclusive upper bound on started_at","title":"Date To"},"description":"Inclusive upper bound on started_at"},{"name":"min_minutes","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"description":"Minimum duration in minutes","title":"Min Minutes"},"description":"Minimum duration in minutes"},{"name":"max_minutes","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"description":"Maximum duration in minutes","title":"Max Minutes"},"description":"Maximum duration in minutes"},{"name":"result","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(pass|fail)$"},{"type":"null"}],"title":"Result"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"items":[{"id":2001,"attempt_number":1,"simulation_id":10,"simulation_name":"Open Pit Simulation","simulation_slug":"open-pit-simulation","module_id":1,"module":{"id":1,"name":"Mining Fundamentals","slug":"mining-fundamentals","icon":"https://s3.example.com/icons/mining.png"},"started_at":"2024-01-01T10:00:00","completed_at":"2024-01-01T11:00:00","duration_seconds":3600,"score":85.5,"performance_band":"excellent","passing_score":70,"result":"pass","is_complete":true,"is_disconnected":false,"kpis":[{"label":"Profit","score":85.0},{"label":"Safety","score":90.0}],"metadata":{}}],"total":1,"page":1,"size":20,"pages":1},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/b2c-students/{user_id}/assign-simulations":{"post":{"tags":["Admin B2C"],"summary":"Assign Simulations Route","operationId":"assign_simulations_route_api_v1_admin_b2c_students__user_id__assign_simulations_post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignSimulationsIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"assigned":2},"message":"Simulations assigned"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/b2c-students/{user_id}/revoke-simulation":{"post":{"tags":["Admin B2C"],"summary":"Revoke Simulation Route","operationId":"revoke_simulation_route_api_v1_admin_b2c_students__user_id__revoke_simulation_post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apps__v1__api__b2c_student__schema__RevokeSimulationIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"ok":true},"message":"Simulation access revoked"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/organisations":{"get":{"tags":["Admin Orgs"],"summary":"List Orgs Route","operationId":"list_orgs_route_api_v1_admin_organisations_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/OrganisationStatus"},{"type":"null"}],"title":"Status"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"items":[{"id":1,"name":"Acme Mining","org_type":"college","country":"ZA","status":"active","contact_email":"contact@acme.com","contact_phone":"+27821234567","notes":"VIP account","student_count":120,"active_licences":80,"pending_requests":2,"created_at":"2024-01-01T00:00:00","org_admins":[{"id":2,"email":"admin@acme.com","full_name":"John Smith","country":"ZA","contact_no":"+27829876543","first_login_complete":true,"is_active":true,"created_at":"2024-01-01T00:00:00"}]}],"total":1,"page":1,"size":20,"pages":1},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]},"post":{"tags":["Admin Orgs"],"summary":"Create Organisation Route","operationId":"create_organisation_route_api_v1_admin_organisations_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgCreateIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"organisation":{"id":1,"name":"Acme Mining","org_type":"college","country":"ZA","status":"active","contact_email":"contact@acme.com","contact_phone":"+27821234567","notes":"VIP account","student_count":120,"active_licences":80,"pending_requests":2,"created_at":"2024-01-01T00:00:00","org_admins":[{"id":2,"email":"admin@acme.com","full_name":"John Smith","country":"ZA","contact_no":"+27829876543","first_login_complete":true,"is_active":true,"created_at":"2024-01-01T00:00:00"}]},"org_admin_user_id":2},"message":"Organisation created"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/organisations/export":{"get":{"tags":["Admin Orgs"],"summary":"Export Orgs Route","operationId":"export_orgs_route_api_v1_admin_organisations_export_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/OrganisationStatus"},{"type":"null"}],"title":"Status"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"download_url":"https://s3.example.com/exports/file.csv?X-Amz-Signature=…"},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/organisations/{org_id}/admins/{admin_id}":{"get":{"tags":["Admin Orgs"],"summary":"Get Org Admin Route","operationId":"get_org_admin_route_api_v1_admin_organisations__org_id__admins__admin_id__get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"integer","title":"Org Id"}},{"name":"admin_id","in":"path","required":true,"schema":{"type":"integer","title":"Admin Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":2,"email":"admin@acme.com","full_name":"John Smith","country":"ZA","contact_no":"+27829876543","first_login_complete":true,"is_active":true,"created_at":"2024-01-01T00:00:00"},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]},"patch":{"tags":["Admin Orgs"],"summary":"Update Org Admin Route","operationId":"update_org_admin_route_api_v1_admin_organisations__org_id__admins__admin_id__patch","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"integer","title":"Org Id"}},{"name":"admin_id","in":"path","required":true,"schema":{"type":"integer","title":"Admin Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgAdminPatchIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":2,"email":"admin@acme.com","full_name":"John Smith","country":"ZA","contact_no":"+27829876543","first_login_complete":true,"is_active":true,"created_at":"2024-01-01T00:00:00"},"message":"Admin updated"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]},"delete":{"tags":["Admin Orgs"],"summary":"Delete Org Admin Route","operationId":"delete_org_admin_route_api_v1_admin_organisations__org_id__admins__admin_id__delete","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"integer","title":"Org Id"}},{"name":"admin_id","in":"path","required":true,"schema":{"type":"integer","title":"Admin Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"ok":true},"message":"Admin removed"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/organisations/{org_id}/students/export":{"get":{"tags":["Admin Orgs"],"summary":"Export Org B2B Students Route","operationId":"export_org_b2b_students_route_api_v1_admin_organisations__org_id__students_export_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"integer","title":"Org Id"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by student name or email","title":"Q"},"description":"Search by student name or email"},{"name":"simulation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Simulation Id"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(active|expiring|expired)$"},{"type":"null"}],"title":"Status"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"download_url":"https://s3.example.com/exports/file.csv?X-Amz-Signature=…"},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/organisations/{org_id}/students":{"get":{"tags":["Admin Orgs"],"summary":"List Org B2B Students Route","operationId":"list_org_b2b_students_route_api_v1_admin_organisations__org_id__students_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"integer","title":"Org Id"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by student name or email","title":"Q"},"description":"Search by student name or email"},{"name":"simulation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Filter by simulation","title":"Simulation Id"},"description":"Filter by simulation"},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(active|expiring|expired)$"},{"type":"null"}],"description":"Allocation status tab: active | expiring | expired","title":"Status"},"description":"Allocation status tab: active | expiring | expired"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"items":[{"id":1002,"email":"student@acme.com","full_name":"Bob Miner","country":"ZA","contact_no":"+27820002222","organisation_id":1,"first_login_complete":true,"is_active":true,"created_at":"2024-01-01T00:00:00","best_score":78.0}],"total":1,"page":1,"size":20,"pages":1},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/organisations/{org_id}/students/{user_id}":{"get":{"tags":["Admin Orgs"],"summary":"Get Org B2B Student Route","operationId":"get_org_b2b_student_route_api_v1_admin_organisations__org_id__students__user_id__get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"integer","title":"Org Id"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":1002,"email":"student@acme.com","full_name":"Bob Miner","country":"ZA","contact_no":"+27820002222","organisation_id":1,"first_login_complete":true,"is_active":true,"created_at":"2024-01-01T00:00:00","best_score":78.0},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/organisations/{org_id}/students/{user_id}/scores/export":{"get":{"tags":["Admin Orgs"],"summary":"Export Org B2B Scores Route","operationId":"export_org_b2b_scores_route_api_v1_admin_organisations__org_id__students__user_id__scores_export_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"integer","title":"Org Id"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by simulation or module name","title":"Q"},"description":"Search by simulation or module name"},{"name":"simulation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Simulation Id"}},{"name":"date_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Date From"}},{"name":"date_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Date To"}},{"name":"min_minutes","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"title":"Min Minutes"}},{"name":"max_minutes","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"title":"Max Minutes"}},{"name":"result","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(pass|fail)$"},{"type":"null"}],"title":"Result"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"download_url":"https://s3.example.com/exports/file.csv?X-Amz-Signature=…"},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/organisations/{org_id}/students/{user_id}/scores":{"get":{"tags":["Admin Orgs"],"summary":"List Org B2B Scores Route","operationId":"list_org_b2b_scores_route_api_v1_admin_organisations__org_id__students__user_id__scores_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"integer","title":"Org Id"}},{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by simulation or module name","title":"Q"},"description":"Search by simulation or module name"},{"name":"simulation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Simulation Id"}},{"name":"date_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"description":"Inclusive lower bound on started_at","title":"Date From"},"description":"Inclusive lower bound on started_at"},{"name":"date_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"description":"Inclusive upper bound on started_at","title":"Date To"},"description":"Inclusive upper bound on started_at"},{"name":"min_minutes","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"title":"Min Minutes"}},{"name":"max_minutes","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"title":"Max Minutes"}},{"name":"result","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(pass|fail)$"},{"type":"null"}],"title":"Result"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"items":[{"id":2001,"attempt_number":1,"simulation_id":10,"simulation_name":"Open Pit Simulation","simulation_slug":"open-pit-simulation","module_id":1,"module":{"id":1,"name":"Mining Fundamentals","slug":"mining-fundamentals","icon":"https://s3.example.com/icons/mining.png"},"started_at":"2024-01-01T10:00:00","completed_at":"2024-01-01T11:00:00","duration_seconds":3600,"score":85.5,"performance_band":"excellent","passing_score":70,"result":"pass","is_complete":true,"is_disconnected":false,"kpis":[{"label":"Profit","score":85.0},{"label":"Safety","score":90.0}],"metadata":{}}],"total":1,"page":1,"size":20,"pages":1},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/organisations/{org_id}/simulations":{"get":{"tags":["Admin Orgs"],"summary":"List Org Simulations Route","description":"Simulations this organisation holds (approved, non-expired pools) with\npool usage + student-allocation stats — for the org-detail Simulations tab.","operationId":"list_org_simulations_route_api_v1_admin_organisations__org_id__simulations_get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"integer","title":"Org Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/organisations/{org_id}":{"get":{"tags":["Admin Orgs"],"summary":"Get Organisation Route","operationId":"get_organisation_route_api_v1_admin_organisations__org_id__get","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"integer","title":"Org Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":1,"name":"Acme Mining","org_type":"college","country":"ZA","status":"active","contact_email":"contact@acme.com","contact_phone":"+27821234567","notes":"VIP account","student_count":120,"active_licences":80,"pending_requests":2,"created_at":"2024-01-01T00:00:00","org_admins":[{"id":2,"email":"admin@acme.com","full_name":"John Smith","country":"ZA","contact_no":"+27829876543","first_login_complete":true,"is_active":true,"created_at":"2024-01-01T00:00:00"}]},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]},"patch":{"tags":["Admin Orgs"],"summary":"Update Organisation Route","operationId":"update_organisation_route_api_v1_admin_organisations__org_id__patch","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"integer","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgUpdateIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":1,"name":"Acme Mining","org_type":"college","country":"ZA","status":"active","contact_email":"contact@acme.com","contact_phone":"+27821234567","notes":"VIP account","student_count":120,"active_licences":80,"pending_requests":2,"created_at":"2024-01-01T00:00:00","org_admins":[{"id":2,"email":"admin@acme.com","full_name":"John Smith","country":"ZA","contact_no":"+27829876543","first_login_complete":true,"is_active":true,"created_at":"2024-01-01T00:00:00"}]},"message":"Organisation updated"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]},"delete":{"tags":["Admin Orgs"],"summary":"Delete Organisation Route","operationId":"delete_organisation_route_api_v1_admin_organisations__org_id__delete","parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"integer","title":"Org Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"ok":true},"message":"Organisation deleted"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/licence-requests":{"get":{"tags":["Admin Licence Requests"],"summary":"Admin List Requests Route","operationId":"admin_list_requests_route_api_v1_admin_licence_requests_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/LicenceRequestStatus"},{"type":"null"}],"title":"Status"}},{"name":"organisation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Organisation Id"}},{"name":"simulation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Simulation Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"items":[{"id":1,"organisation_id":1,"simulation_id":10,"simulation_name":"Open Pit Simulation","quantity":50,"duration_months":12,"status":"pending","requested_by":2,"reviewed_by":null,"reviewed_at":null,"reject_reason":null,"clock_start":null,"expiry_at":null,"is_topup":false,"parent_request_id":null,"notes":"Initial batch for Q1 intake","created_at":"2024-01-01T00:00:00"}],"total":1,"page":1,"size":20,"pages":1},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/licence-requests/pending":{"get":{"tags":["Admin Licence Requests"],"summary":"List Pending Requests Route","operationId":"list_pending_requests_route_api_v1_admin_licence_requests_pending_get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"items":[{"id":1,"org_id":1,"org_name":"Acme Mining","simulation_id":10,"simulation_name":"Open Pit Simulation","quantity":50,"duration_months":12,"requested_at":"2024-01-01T00:00:00","expiry_if_approved_today":"2025-01-01","is_topup":false,"parent_request_id":null,"notes":"Initial batch"}],"total":1,"page":1,"size":20,"pages":1},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/licence-requests/history/export":{"get":{"tags":["Admin Licence Requests"],"summary":"Export Request History Route","operationId":"export_request_history_route_api_v1_admin_licence_requests_history_export_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(approved|rejected)$"},{"type":"null"}],"title":"Status"}},{"name":"organisation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Organisation Id"}},{"name":"simulation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Simulation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"download_url":"https://s3.example.com/exports/file.csv?X-Amz-Signature=…"},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/licence-requests/history":{"get":{"tags":["Admin Licence Requests"],"summary":"List Request History Route","operationId":"list_request_history_route_api_v1_admin_licence_requests_history_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(approved|rejected)$"},{"type":"null"}],"title":"Status"}},{"name":"organisation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Organisation Id"}},{"name":"simulation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Simulation Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"items":[{"id":1,"organisation_id":1,"simulation_id":10,"simulation_name":"Open Pit Simulation","quantity":50,"duration_months":12,"status":"approved","requested_by":2,"reviewed_by":null,"reviewed_at":"2024-01-05T00:00:00","reject_reason":null,"clock_start":null,"expiry_at":null,"is_topup":false,"parent_request_id":null,"notes":"Initial batch for Q1 intake","created_at":"2024-01-01T00:00:00","org_id":1,"org_name":"Acme Mining","reviewer_name":"Master Admin"}],"total":1,"page":1,"size":20,"pages":1},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/licence-requests/{request_id}":{"get":{"tags":["Admin Licence Requests"],"summary":"Admin Request Detail Route","operationId":"admin_request_detail_route_api_v1_admin_licence_requests__request_id__get","parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"integer","title":"Request Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":1,"organisation_id":1,"simulation_id":10,"simulation_name":"Open Pit Simulation","quantity":50,"duration_months":12,"status":"pending","requested_by":2,"reviewed_by":null,"reviewed_at":null,"reject_reason":null,"clock_start":null,"expiry_at":null,"is_topup":false,"parent_request_id":null,"notes":"Initial batch for Q1 intake","created_at":"2024-01-01T00:00:00"},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/licence-requests/{request_id}/approve":{"post":{"tags":["Admin Licence Requests"],"summary":"Approve Route","operationId":"approve_route_api_v1_admin_licence_requests__request_id__approve_post","parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"integer","title":"Request Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":1,"organisation_id":1,"simulation_id":10,"simulation_name":"Open Pit Simulation","quantity":50,"duration_months":12,"status":"approved","requested_by":2,"reviewed_by":1,"reviewed_at":"2024-01-05T00:00:00","reject_reason":null,"clock_start":null,"expiry_at":null,"is_topup":false,"parent_request_id":null,"notes":"Initial batch for Q1 intake","created_at":"2024-01-01T00:00:00"},"message":"Request approved"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/licence-requests/{request_id}/reject":{"post":{"tags":["Admin Licence Requests"],"summary":"Reject Route","operationId":"reject_route_api_v1_admin_licence_requests__request_id__reject_post","parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"integer","title":"Request Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RejectIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":1,"organisation_id":1,"simulation_id":10,"simulation_name":"Open Pit Simulation","quantity":50,"duration_months":12,"status":"rejected","requested_by":2,"reviewed_by":1,"reviewed_at":"2024-01-05T00:00:00","reject_reason":"Quota exceeded","clock_start":null,"expiry_at":null,"is_topup":false,"parent_request_id":null,"notes":"Initial batch for Q1 intake","created_at":"2024-01-01T00:00:00"},"message":"Request rejected"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/licence-requests/assign":{"post":{"tags":["Admin Licence Requests"],"summary":"Admin Assign Route","description":"Master admin directly assigns one or many simulations to an organisation.\n\nEach item carries its own licence count and expiry date. Works for a single\nsimulation or a batch — the payload is always a list.","operationId":"admin_assign_route_api_v1_admin_licence_requests_assign_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminAssignLicenceIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/reports/tiles":{"get":{"tags":["Reports"],"summary":"Report Tiles Route","operationId":"report_tiles_route_api_v1_reports_tiles_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by student name, email or simulation name","title":"Q"},"description":"Search by student name, email or simulation name"},{"name":"simulation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Simulation Id"}},{"name":"organisation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Organisation Id"}},{"name":"band","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/PerformanceBand"},{"type":"null"}],"title":"Band"}},{"name":"user_type","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/UserType"},{"type":"null"}],"title":"User Type"}},{"name":"date_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Date From"}},{"name":"date_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Date To"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"total_attempts":500,"total_completions":450,"avg_score":78.5,"pass_rate_pct":82.5,"unique_students":100},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/reports/scores/export":{"get":{"tags":["Reports"],"summary":"Export Scores Csv Route","operationId":"export_scores_csv_route_api_v1_reports_scores_export_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by student name, email or simulation name","title":"Q"},"description":"Search by student name, email or simulation name"},{"name":"simulation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Simulation Id"}},{"name":"organisation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Organisation Id"}},{"name":"band","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/PerformanceBand"},{"type":"null"}],"title":"Band"}},{"name":"user_type","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/UserType"},{"type":"null"}],"title":"User Type"}},{"name":"date_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Date From"}},{"name":"date_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Date To"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"download_url":"https://s3.example.com/exports/file.csv?X-Amz-Signature=…"},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/reports/scores":{"get":{"tags":["Reports"],"summary":"List Scores Route","operationId":"list_scores_route_api_v1_reports_scores_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by student name, email or simulation name","title":"Q"},"description":"Search by student name, email or simulation name"},{"name":"simulation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Simulation Id"}},{"name":"organisation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Organisation Id"}},{"name":"band","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/PerformanceBand"},{"type":"null"}],"title":"Band"}},{"name":"user_type","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/UserType"},{"type":"null"}],"title":"User Type"}},{"name":"date_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Date From"}},{"name":"date_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Date To"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"items":[{"student_name":"Alice Miner","student_email":"student@direct.com","user_type":"b2c_student","organisation_name":null,"simulation_name":"Open Pit Simulation","started_at":"2024-01-01T10:00:00","completed_at":"2024-01-01T11:00:00","duration_seconds":3600,"score":85.5,"passing_score":70,"performance_band":"excellent","attempt_count":1}],"total":1,"page":1,"size":20,"pages":1},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/auth/portal/verify-otp":{"post":{"tags":["Auth Portal"],"summary":"Portal Verify Otp Route","operationId":"portal_verify_otp_route_api_v1_auth_portal_verify_otp_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyOtpIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"purpose":"first_login","token":"<otp-verify-token>","expires_in_minutes":10},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[]}},"/api/v1/auth/portal/set-password":{"post":{"tags":["Auth Portal"],"summary":"Portal Set Password Route","operationId":"portal_set_password_route_api_v1_auth_portal_set_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPasswordIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"ok":true},"message":"Password set successfully"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[]}},"/api/v1/auth/portal/check-email":{"post":{"tags":["Auth Portal"],"summary":"Portal Check Email Route","operationId":"portal_check_email_route_api_v1_auth_portal_check_email_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckEmailIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[]}},"/api/v1/auth/portal/login":{"post":{"tags":["Auth Portal"],"summary":"Portal Login Route","operationId":"portal_login_route_api_v1_auth_portal_login_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"access_token":"<jwt-access-token>","refresh_token":"<jwt-refresh-token>","token_type":"bearer","user":{"id":1,"email":"user@example.com","full_name":"Jane Doe","country":"ZA","contact_no":"+27821234567","user_type":"org_admin","role":"Organisation Admin","organisation_id":1,"organisation_name":"Acme Mining","first_login_complete":true,"is_active":true}},"message":"Login successful"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[]}},"/api/v1/auth/portal/login/request-otp":{"post":{"tags":["Auth Portal"],"summary":"Portal Login Request Otp Route","operationId":"portal_login_request_otp_route_api_v1_auth_portal_login_request_otp_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginOtpRequestIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"ok":true},"message":"OTP sent to your email"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[]}},"/api/v1/auth/portal/login/verify-otp":{"post":{"tags":["Auth Portal"],"summary":"Portal Login Verify Otp Route","operationId":"portal_login_verify_otp_route_api_v1_auth_portal_login_verify_otp_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginOtpVerifyIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"access_token":"<jwt-access-token>","refresh_token":"<jwt-refresh-token>","token_type":"bearer","user":{"id":1,"email":"user@example.com","full_name":"Jane Doe","country":"ZA","contact_no":"+27821234567","user_type":"org_admin","role":"Organisation Admin","organisation_id":1,"organisation_name":"Acme Mining","first_login_complete":true,"is_active":true}},"message":"Login successful"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[]}},"/api/v1/auth/portal/forgot-password":{"post":{"tags":["Auth Portal"],"summary":"Portal Forgot Password Route","operationId":"portal_forgot_password_route_api_v1_auth_portal_forgot_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForgotPasswordIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"ok":true},"message":"Password reset link sent"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[]}},"/api/v1/auth/portal/reset-password":{"post":{"tags":["Auth Portal"],"summary":"Portal Reset Password Route","operationId":"portal_reset_password_route_api_v1_auth_portal_reset_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"ok":true},"message":"Password reset successfully"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[]}},"/api/v1/auth/portal/refresh":{"post":{"tags":["Auth Portal"],"summary":"Portal Refresh Route","operationId":"portal_refresh_route_api_v1_auth_portal_refresh_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"access_token":"<jwt-access-token>","refresh_token":"<jwt-refresh-token>","token_type":"bearer","user":{"id":1,"email":"user@example.com","full_name":"Jane Doe","country":"ZA","contact_no":"+27821234567","user_type":"org_admin","role":"Organisation Admin","organisation_id":1,"organisation_name":"Acme Mining","first_login_complete":true,"is_active":true}},"message":"Token refreshed"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[]}},"/api/v1/auth/portal/logout":{"post":{"tags":["Auth Portal"],"summary":"Portal Logout Route","operationId":"portal_logout_route_api_v1_auth_portal_logout_post","requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/LogoutIn"},{"type":"null"}],"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"ok":true},"message":"Logged out successfully"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/auth/portal/logout-sessions":{"post":{"tags":["Auth Portal"],"summary":"Portal Logout Sessions Route","operationId":"portal_logout_sessions_route_api_v1_auth_portal_logout_sessions_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogoutSessionsIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/auth/portal/sessions":{"get":{"tags":["Auth Portal"],"summary":"Portal Sessions Route","operationId":"portal_sessions_route_api_v1_auth_portal_sessions_get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/org/students":{"get":{"tags":["Org Students"],"summary":"List B2B Route","operationId":"list_b2b_route_api_v1_org_students_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by student name or email","title":"Q"},"description":"Search by student name or email"},{"name":"simulation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Filter by simulation","title":"Simulation Id"},"description":"Filter by simulation"},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(active|expiring|expired)$"},{"type":"null"}],"description":"Allocation status tab: active | expiring | expired","title":"Status"},"description":"Allocation status tab: active | expiring | expired"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"items":[{"id":1002,"email":"student@acme.com","full_name":"Bob Miner","country":"ZA","contact_no":"+27820002222","organisation_id":1,"first_login_complete":true,"is_active":true,"created_at":"2024-01-01T00:00:00","best_score":78.0}],"total":1,"page":1,"size":20,"pages":1},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]},"post":{"tags":["Org Students"],"summary":"Create B2B Route","operationId":"create_b2b_route_api_v1_org_students_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/B2BStudentCreateIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":1002,"email":"student@acme.com","full_name":"Bob Miner","country":"ZA","contact_no":"+27820002222","organisation_id":1,"first_login_complete":true,"is_active":true,"created_at":"2024-01-01T00:00:00","best_score":78.0},"message":"Student created"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]},"delete":{"tags":["Org Students"],"summary":"Delete B2B Route","operationId":"delete_b2b_route_api_v1_org_students_delete","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteB2BStudentsIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"deleted":3},"message":"Students deleted"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/org/students/sample-csv":{"get":{"tags":["Org Students"],"summary":"Sample Csv Route","operationId":"sample_csv_route_api_v1_org_students_sample_csv_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"422":{"description":"Validation Error – invalid request body","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Validation error. Please check your input.","errors":{"detail":[{"type":"missing","loc":["body","email"],"msg":"Field required","input":{}}],"request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/org/students/export":{"get":{"tags":["Org Students"],"summary":"Export B2B Route","operationId":"export_b2b_route_api_v1_org_students_export_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by student name or email","title":"Q"},"description":"Search by student name or email"},{"name":"simulation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Simulation Id"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(active|expiring|expired)$"},{"type":"null"}],"title":"Status"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"download_url":"https://s3.example.com/exports/file.csv?X-Amz-Signature=…"},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/org/students/available-pools":{"get":{"tags":["Org Students"],"summary":"List Available Pools Route","operationId":"list_available_pools_route_api_v1_org_students_available_pools_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":[{"id":1,"name":"Request #1","quantity":50,"available":5}],"message":"Success"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"422":{"description":"Validation Error – invalid request body","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Validation error. Please check your input.","errors":{"detail":[{"type":"missing","loc":["body","email"],"msg":"Field required","input":{}}],"request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/org/students/bulk-preview":{"post":{"tags":["Org Students"],"summary":"Bulk Preview Route","operationId":"bulk_preview_route_api_v1_org_students_bulk_preview_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_bulk_preview_route_api_v1_org_students_bulk_preview_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"rows":[{"email":"s1@acme.com","full_name":"Bob","country":"ZA","contact_no":"+27820002222","status":"new","message":null}]},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/org/students/bulk-import":{"post":{"tags":["Org Students"],"summary":"Bulk Import Route","operationId":"bulk_import_route_api_v1_org_students_bulk_import_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_bulk_import_route_api_v1_org_students_bulk_import_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"imported":8,"updated":1,"failed":1,"details":[]},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/org/students/{user_id}/scores/export":{"get":{"tags":["Org Students"],"summary":"Export B2B Scores Route","operationId":"export_b2b_scores_route_api_v1_org_students__user_id__scores_export_get","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by simulation or module name","title":"Q"},"description":"Search by simulation or module name"},{"name":"simulation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Simulation Id"}},{"name":"date_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Date From"}},{"name":"date_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"title":"Date To"}},{"name":"min_minutes","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"title":"Min Minutes"}},{"name":"max_minutes","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"title":"Max Minutes"}},{"name":"result","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(pass|fail)$"},{"type":"null"}],"title":"Result"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"download_url":"https://s3.example.com/exports/file.csv?X-Amz-Signature=…"},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/org/students/{user_id}/scores":{"get":{"tags":["Org Students"],"summary":"List B2B Scores Route","operationId":"list_b2b_scores_route_api_v1_org_students__user_id__scores_get","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by simulation or module name","title":"Q"},"description":"Search by simulation or module name"},{"name":"simulation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Simulation Id"}},{"name":"date_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"description":"Inclusive lower bound on started_at","title":"Date From"},"description":"Inclusive lower bound on started_at"},{"name":"date_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"description":"Inclusive upper bound on started_at","title":"Date To"},"description":"Inclusive upper bound on started_at"},{"name":"min_minutes","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"title":"Min Minutes"}},{"name":"max_minutes","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"title":"Max Minutes"}},{"name":"result","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(pass|fail)$"},{"type":"null"}],"title":"Result"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"items":[{"id":2001,"attempt_number":1,"simulation_id":10,"simulation_name":"Open Pit Simulation","simulation_slug":"open-pit-simulation","module_id":1,"module":{"id":1,"name":"Mining Fundamentals","slug":"mining-fundamentals","icon":"https://s3.example.com/icons/mining.png"},"started_at":"2024-01-01T10:00:00","completed_at":"2024-01-01T11:00:00","duration_seconds":3600,"score":85.5,"performance_band":"excellent","passing_score":70,"result":"pass","is_complete":true,"is_disconnected":false,"kpis":[{"label":"Profit","score":85.0},{"label":"Safety","score":90.0}],"metadata":{}}],"total":1,"page":1,"size":20,"pages":1},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/org/students/{user_id}":{"get":{"tags":["Org Students"],"summary":"Get B2B Detail Route","operationId":"get_b2b_detail_route_api_v1_org_students__user_id__get","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":1002,"email":"student@acme.com","full_name":"Bob Miner","country":"ZA","contact_no":"+27820002222","organisation_id":1,"first_login_complete":true,"is_active":true,"created_at":"2024-01-01T00:00:00","best_score":78.0},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/org/licences/pools":{"get":{"tags":["Org Licences"],"summary":"List Org Pools Route","operationId":"list_org_pools_route_api_v1_org_licences_pools_get","parameters":[{"name":"simulation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Filter by simulation","title":"Simulation Id"},"description":"Filter by simulation"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"items":[{"id":1,"request_id":1,"organisation_id":1,"simulation_id":10,"simulation_name":"Open Pit Simulation","quantity":50,"duration_months":12,"status":"active","allocated":45,"available":5,"expiry_at":"2025-01-01T00:00:00","clock_start":"2024-01-01T00:00:00","created_at":"2024-01-01T00:00:00"}]},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/org/licences/request-history":{"get":{"tags":["Org Licences"],"summary":"List Org Request History Route","operationId":"list_org_request_history_route_api_v1_org_licences_request_history_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(pending|approved|rejected|expired)$"},{"type":"null"}],"description":"Filter by request status","title":"Status"},"description":"Filter by request status"},{"name":"simulation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Filter by simulation","title":"Simulation Id"},"description":"Filter by simulation"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"items":[{"id":1,"organisation_id":1,"simulation_id":10,"simulation_name":"Open Pit Simulation","quantity":50,"duration_months":12,"status":"pending","requested_by":2,"reviewed_by":null,"reviewed_at":null,"reject_reason":null,"clock_start":null,"expiry_at":null,"is_topup":false,"parent_request_id":null,"notes":"Initial batch for Q1 intake","created_at":"2024-01-01T00:00:00"}],"total":1,"page":1,"size":20,"pages":1},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/org/licences/access-requests":{"get":{"tags":["Org Licences"],"summary":"List Org Access Requests Route","description":"Student 'Request Access' submissions for this organisation.\n\nDefaults to the pending queue the org admin needs to action. The shared\nservice auto-scopes to the actor's own organisation, so org admins only ever\nsee their own students' requests.","operationId":"list_org_access_requests_route_api_v1_org_licences_access_requests_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/AccessRequestStatus"},{"type":"null"}],"description":"Filter by status; defaults to pending. Pass any status to widen.","default":"pending","title":"Status"},"description":"Filter by status; defaults to pending. Pass any status to widen."},{"name":"simulation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Filter by simulation","title":"Simulation Id"},"description":"Filter by simulation"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/org/licences/pools/{request_id}":{"get":{"tags":["Org Licences"],"summary":"Org Pool Detail Route","operationId":"org_pool_detail_route_api_v1_org_licences_pools__request_id__get","parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"integer","title":"Request Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":1,"request_id":1,"organisation_id":1,"simulation_id":10,"simulation_name":"Open Pit Simulation","quantity":50,"duration_months":12,"status":"active","allocated":45,"available":5,"expiry_at":"2025-01-01T00:00:00","clock_start":"2024-01-01T00:00:00","created_at":"2024-01-01T00:00:00","allocated_students":[]},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/org/licences/modules":{"get":{"tags":["Org Licences"],"summary":"List Org Modules Route","operationId":"list_org_modules_route_api_v1_org_licences_modules_get","parameters":[{"name":"org_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Organisation to view — required for master admin; org admins always see their own organisation","title":"Org Id"},"description":"Organisation to view — required for master admin; org admins always see their own organisation"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":[{"id":1,"name":"Mining Fundamentals","slug":"mining-fundamentals","icon":"url","simulations":[{"id":10,"name":"Open Pit Simulation","slug":"open-pit-simulation","module_id":1,"module":{"id":1,"name":"Mining Fundamentals","slug":"mining-fundamentals","icon":"https://s3.example.com/icons/mining.png"},"description":"Realistic open-pit mine simulation.","status":"active","passing_score":70,"duration_minutes":60,"expires_at":null,"cover_image_url":"https://s3.example.com/covers/open-pit.jpg","runner_url":"https://sim.dms-mining.com/open-pit","enrolled":95,"pass_rate":82.5,"avg_score":78.4}]}],"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/org/licences/simulations/{simulation_id}":{"get":{"tags":["Org Licences"],"summary":"Simulation Detail Route","operationId":"simulation_detail_route_api_v1_org_licences_simulations__simulation_id__get","parameters":[{"name":"simulation_id","in":"path","required":true,"schema":{"type":"integer","title":"Simulation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":10,"name":"Open Pit Simulation","slug":"open-pit-simulation","module_id":1,"module":{"id":1,"name":"Mining Fundamentals","slug":"mining-fundamentals","icon":"https://s3.example.com/icons/mining.png"},"description":"Realistic open-pit mine simulation.","status":"active","passing_score":70,"duration_minutes":60,"expires_at":null,"cover_image_url":"https://s3.example.com/covers/open-pit.jpg","runner_url":"https://sim.dms-mining.com/open-pit","enrolled":95,"pass_rate":82.5,"avg_score":78.4,"pools":[{"id":1,"request_id":1,"organisation_id":1,"simulation_id":10,"simulation_name":"Open Pit Simulation","quantity":50,"duration_months":12,"status":"active","allocated":45,"available":5,"expiry_at":"2025-01-01T00:00:00","clock_start":"2024-01-01T00:00:00","created_at":"2024-01-01T00:00:00"}],"allocated_students":[]},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/org/licences/simulations/{simulation_id}/assign":{"post":{"tags":["Org Licences"],"summary":"Assign Simulation Route","operationId":"assign_simulation_route_api_v1_org_licences_simulations__simulation_id__assign_post","parameters":[{"name":"simulation_id","in":"path","required":true,"schema":{"type":"integer","title":"Simulation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignSimulationIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"assigned":10},"message":"Licences assigned"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/org/licences/simulations/{simulation_id}/revoke":{"post":{"tags":["Org Licences"],"summary":"Revoke Simulation Route","operationId":"revoke_simulation_route_api_v1_org_licences_simulations__simulation_id__revoke_post","parameters":[{"name":"simulation_id","in":"path","required":true,"schema":{"type":"integer","title":"Simulation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apps__v1__api__org_licences__schema__RevokeSimulationIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"revoked":5},"message":"Licences revoked"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/org/licence-requests":{"post":{"tags":["Org Licence Requests"],"summary":"Create Request Route","operationId":"create_request_route_api_v1_org_licence_requests_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LicenceRequestIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":1,"organisation_id":1,"simulation_id":10,"simulation_name":"Open Pit Simulation","quantity":50,"duration_months":12,"status":"pending","requested_by":2,"reviewed_by":null,"reviewed_at":null,"reject_reason":null,"clock_start":null,"expiry_at":null,"is_topup":false,"parent_request_id":null,"notes":"Initial batch for Q1 intake","created_at":"2024-01-01T00:00:00"},"message":"Licence request submitted"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]},"get":{"tags":["Org Licence Requests"],"summary":"Org List Requests Route","operationId":"org_list_requests_route_api_v1_org_licence_requests_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/LicenceRequestStatus"},{"type":"null"}],"title":"Status"}},{"name":"simulation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Simulation Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"items":[{"id":1,"organisation_id":1,"simulation_id":10,"simulation_name":"Open Pit Simulation","quantity":50,"duration_months":12,"status":"pending","requested_by":2,"reviewed_by":null,"reviewed_at":null,"reject_reason":null,"clock_start":null,"expiry_at":null,"is_topup":false,"parent_request_id":null,"notes":"Initial batch for Q1 intake","created_at":"2024-01-01T00:00:00"}],"total":1,"page":1,"size":20,"pages":1},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/org/licence-requests/{request_id}":{"get":{"tags":["Org Licence Requests"],"summary":"Org Request Detail Route","operationId":"org_request_detail_route_api_v1_org_licence_requests__request_id__get","parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"integer","title":"Request Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":1,"organisation_id":1,"simulation_id":10,"simulation_name":"Open Pit Simulation","quantity":50,"duration_months":12,"status":"pending","requested_by":2,"reviewed_by":null,"reviewed_at":null,"reject_reason":null,"clock_start":null,"expiry_at":null,"is_topup":false,"parent_request_id":null,"notes":"Initial batch for Q1 intake","created_at":"2024-01-01T00:00:00"},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/licence-allocations":{"post":{"tags":["Licence Allocations"],"summary":"Allocate Licence Route","operationId":"allocate_licence_route_api_v1_licence_allocations_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AllocateIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":5001,"request_id":1,"organisation_id":1,"simulation_id":10,"simulation_name":"Open Pit Simulation","user_id":1001,"user_email":"student@acme.com","expiry_at":"2025-01-01T00:00:00","attempted":false,"first_cta_at":null,"returned_at":null,"created_at":"2024-01-01T00:00:00"},"message":"Licence allocated"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]},"get":{"tags":["Licence Allocations"],"summary":"List Allocations Route","operationId":"list_allocations_route_api_v1_licence_allocations_get","parameters":[{"name":"request_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Request Id"}},{"name":"user_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"User Id"}},{"name":"only_active","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Only Active"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"items":[{"id":5001,"request_id":1,"organisation_id":1,"simulation_id":10,"simulation_name":"Open Pit Simulation","user_id":1001,"user_email":"student@acme.com","expiry_at":"2025-01-01T00:00:00","attempted":false,"first_cta_at":null,"returned_at":null,"created_at":"2024-01-01T00:00:00"}],"total":1,"page":1,"size":20,"pages":1},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/licence-allocations/{allocation_id}/return":{"post":{"tags":["Licence Allocations"],"summary":"Return Licence Route","operationId":"return_licence_route_api_v1_licence_allocations__allocation_id__return_post","parameters":[{"name":"allocation_id","in":"path","required":true,"schema":{"type":"integer","title":"Allocation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":5001,"request_id":1,"organisation_id":1,"simulation_id":10,"simulation_name":"Open Pit Simulation","user_id":1001,"user_email":"student@acme.com","expiry_at":"2025-01-01T00:00:00","attempted":false,"first_cta_at":null,"returned_at":"2024-06-01T00:00:00","created_at":"2024-01-01T00:00:00"},"message":"Licence returned"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/student/modules":{"get":{"tags":["Student"],"summary":"List Modules For Me Route","description":"Module-grouped catalogue of assigned simulations.\n\nReturns only simulations the student has been allocated, grouped by module.\nEach card carries:\n  - licence_status  : active | expiring | expired  (null for B2C lifetime access)\n  - action          : launch | resume | retry | no_access\n  - best_score      : max score from completed attempts  (null if none)\n  - days_until_expiry: positive int when expiry is within 7 days, else null","operationId":"list_modules_for_me_route_api_v1_student_modules_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":[{"id":1,"name":"Mining Fundamentals","slug":"mining-fundamentals","icon":"https://s3.example.com/icons/mining.png","simulations":[{"id":10,"name":"Open Pit Simulation","slug":"open-pit-simulation","module_id":1,"module":{"id":1,"name":"Mining Fundamentals","slug":"mining-fundamentals","icon":"https://s3.example.com/icons/mining.png"},"description":"Realistic open-pit mine simulation.","status":"active","is_assigned":true,"expiry_at":"2025-01-01T00:00:00","allocation_id":5001,"cover_image_url":"https://s3.example.com/covers/open-pit.jpg","runner_url":"https://sim.dms-mining.com/open-pit","licence_status":"active","action":"launch","best_score":85.5,"days_until_expiry":240}]}],"message":"Success"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"422":{"description":"Validation Error – invalid request body","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Validation error. Please check your input.","errors":{"detail":[{"type":"missing","loc":["body","email"],"msg":"Field required","input":{}}],"request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/student/modules/new":{"get":{"tags":["Student"],"summary":"List New Modules Route","description":"New-modules banner.\n\nReturns simulations allocated within the org-configured window\n(``OrganisationSetting`` flag key ``new_module_days``, default 7 days).\nMost recently allocated first.","operationId":"list_new_modules_route_api_v1_student_modules_new_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":[{"id":10,"name":"Open Pit Simulation","slug":"open-pit-simulation","module_id":1,"module":{"id":1,"name":"Mining Fundamentals","slug":"mining-fundamentals","icon":"https://s3.example.com/icons/mining.png"},"description":"Realistic open-pit mine simulation.","status":"active","is_assigned":true,"expiry_at":"2025-01-01T00:00:00","allocation_id":5001,"cover_image_url":"https://s3.example.com/covers/open-pit.jpg","runner_url":"https://sim.dms-mining.com/open-pit","licence_status":"active","action":"launch","best_score":85.5,"days_until_expiry":240}],"message":"Success"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"422":{"description":"Validation Error – invalid request body","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Validation error. Please check your input.","errors":{"detail":[{"type":"missing","loc":["body","email"],"msg":"Field required","input":{}}],"request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/student/simulations":{"get":{"tags":["Student"],"summary":"List Simulations For Me Route","description":"Flat list of all simulations with assignment, licence, and score metadata.\n\nAssigned simulations carry full licence/action/score data; unassigned ones\nhave ``is_assigned=false`` and ``action=\"no_access\"`` so the UI can grey them out.","operationId":"list_simulations_for_me_route_api_v1_student_simulations_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":[{"id":10,"name":"Open Pit Simulation","slug":"open-pit-simulation","module_id":1,"module":{"id":1,"name":"Mining Fundamentals","slug":"mining-fundamentals","icon":"https://s3.example.com/icons/mining.png"},"description":"Realistic open-pit mine simulation.","status":"active","is_assigned":true,"expiry_at":"2025-01-01T00:00:00","allocation_id":5001,"cover_image_url":"https://s3.example.com/covers/open-pit.jpg","runner_url":"https://sim.dms-mining.com/open-pit","licence_status":"active","action":"launch","best_score":85.5,"days_until_expiry":240}],"message":"Success"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"422":{"description":"Validation Error – invalid request body","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Validation error. Please check your input.","errors":{"detail":[{"type":"missing","loc":["body","email"],"msg":"Field required","input":{}}],"request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/student/simulations/{simulation_id}/access":{"get":{"tags":["Student"],"summary":"Check Simulation Access Route","description":"Whether the current student has access to this simulation (B2B or B2C),\nplus pending-request / can-request state for the 'Request Access' button.","operationId":"check_simulation_access_route_api_v1_student_simulations__simulation_id__access_get","parameters":[{"name":"simulation_id","in":"path","required":true,"schema":{"type":"integer","title":"Simulation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/student/attempts":{"get":{"tags":["Student"],"summary":"List My Attempts Route","operationId":"list_my_attempts_route_api_v1_student_attempts_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":[{"id":2001,"attempt_number":1,"simulation_id":10,"simulation_name":"Open Pit Simulation","simulation_slug":"open-pit-simulation","module_id":1,"module":{"id":1,"name":"Mining Fundamentals","slug":"mining-fundamentals","icon":"https://s3.example.com/icons/mining.png"},"started_at":"2024-01-01T10:00:00","completed_at":"2024-01-01T11:00:00","duration_seconds":3600,"score":85.5,"performance_band":"excellent","passing_score":70,"result":"pass","is_complete":true,"is_disconnected":false,"kpis":[{"label":"Profit","score":85.0},{"label":"Safety","score":90.0}],"metadata":{}}],"message":"Success"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"422":{"description":"Validation Error – invalid request body","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Validation error. Please check your input.","errors":{"detail":[{"type":"missing","loc":["body","email"],"msg":"Field required","input":{}}],"request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/student/scores/export":{"get":{"tags":["Student"],"summary":"Export My Scores Route","description":"Export student's own scores to CSV with the same filters as GET /student/scores.\n\nReturns a presigned S3 download URL. CSV columns: Attempt #, Module,\nSimulation, Started At, Completed At, Duration (min), Score, Passing Score,\nResult, Performance Band, KPI Breakdown.","operationId":"export_my_scores_route_api_v1_student_scores_export_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by simulation name or module name","title":"Q"},"description":"Search by simulation name or module name"},{"name":"module_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Filter by module","title":"Module Id"},"description":"Filter by module"},{"name":"simulation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Filter by simulation","title":"Simulation Id"},"description":"Filter by simulation"},{"name":"date_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"description":"Inclusive lower bound on started_at","title":"Date From"},"description":"Inclusive lower bound on started_at"},{"name":"date_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"description":"Inclusive upper bound on started_at","title":"Date To"},"description":"Inclusive upper bound on started_at"},{"name":"min_minutes","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"description":"Minimum duration in minutes","title":"Min Minutes"},"description":"Minimum duration in minutes"},{"name":"max_minutes","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"description":"Maximum duration in minutes","title":"Max Minutes"},"description":"Maximum duration in minutes"},{"name":"result","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(pass|fail)$"},{"type":"null"}],"title":"Result"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"download_url":"https://s3.example.com/exports/file.csv?X-Amz-Signature=…"},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/student/scores":{"get":{"tags":["Student"],"summary":"List My Scores Route","operationId":"list_my_scores_route_api_v1_student_scores_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Search by simulation name or module name","title":"Q"},"description":"Search by simulation name or module name"},{"name":"module_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Filter by module","title":"Module Id"},"description":"Filter by module"},{"name":"simulation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Filter by simulation","title":"Simulation Id"},"description":"Filter by simulation"},{"name":"date_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"description":"Inclusive lower bound on started_at","title":"Date From"},"description":"Inclusive lower bound on started_at"},{"name":"date_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"description":"Inclusive upper bound on started_at","title":"Date To"},"description":"Inclusive upper bound on started_at"},{"name":"min_minutes","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"description":"Minimum duration in minutes","title":"Min Minutes"},"description":"Minimum duration in minutes"},{"name":"max_minutes","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"description":"Maximum duration in minutes","title":"Max Minutes"},"description":"Maximum duration in minutes"},{"name":"result","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(pass|fail)$"},{"type":"null"}],"title":"Result"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"items":[{"id":2001,"attempt_number":1,"simulation_id":10,"simulation_name":"Open Pit Simulation","simulation_slug":"open-pit-simulation","module_id":1,"module":{"id":1,"name":"Mining Fundamentals","slug":"mining-fundamentals","icon":"https://s3.example.com/icons/mining.png"},"started_at":"2024-01-01T10:00:00","completed_at":"2024-01-01T11:00:00","duration_seconds":3600,"score":85.5,"performance_band":"excellent","passing_score":70,"result":"pass","is_complete":true,"is_disconnected":false,"kpis":[{"label":"Profit","score":85.0},{"label":"Safety","score":90.0}],"metadata":{}}],"total":1,"page":1,"size":20,"pages":1},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/student/simulations/start":{"post":{"tags":["Student"],"summary":"Start Attempt Route","operationId":"start_attempt_route_api_v1_student_simulations_start_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":2001,"simulation_id":10,"simulation_name":"Open Pit Simulation","started_at":"2024-01-01T10:00:00","completed_at":null,"duration_seconds":null,"score":null,"performance_band":null,"is_complete":false,"is_disconnected":false},"message":"Simulation started"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/student/attempts/{attempt_id}/first-cta":{"post":{"tags":["Student"],"summary":"First Cta Route","operationId":"first_cta_route_api_v1_student_attempts__attempt_id__first_cta_post","parameters":[{"name":"attempt_id","in":"path","required":true,"schema":{"type":"integer","title":"Attempt Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":2001,"attempt_number":1,"simulation_id":10,"simulation_name":"Open Pit Simulation","simulation_slug":"open-pit-simulation","module_id":1,"module":{"id":1,"name":"Mining Fundamentals","slug":"mining-fundamentals","icon":"https://s3.example.com/icons/mining.png"},"started_at":"2024-01-01T10:00:00","completed_at":"2024-01-01T11:00:00","duration_seconds":3600,"score":85.5,"performance_band":"excellent","passing_score":70,"result":"pass","is_complete":true,"is_disconnected":false,"kpis":[{"label":"Profit","score":85.0},{"label":"Safety","score":90.0}],"metadata":{},"first_cta_at":"2024-01-01T10:05:00"},"message":"First CTA recorded"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/student/attempts/{attempt_id}/complete":{"post":{"tags":["Student"],"summary":"Complete Attempt Route","operationId":"complete_attempt_route_api_v1_student_attempts__attempt_id__complete_post","parameters":[{"name":"attempt_id","in":"path","required":true,"schema":{"type":"integer","title":"Attempt Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompleteIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"id":2001,"attempt_number":1,"simulation_id":10,"simulation_name":"Open Pit Simulation","simulation_slug":"open-pit-simulation","module_id":1,"module":{"id":1,"name":"Mining Fundamentals","slug":"mining-fundamentals","icon":"https://s3.example.com/icons/mining.png"},"started_at":"2024-01-01T10:00:00","completed_at":"2024-01-01T11:00:00","duration_seconds":3600,"score":85.5,"performance_band":"excellent","passing_score":70,"result":"pass","is_complete":true,"is_disconnected":false,"kpis":[{"label":"Profit","score":85.0},{"label":"Safety","score":90.0}],"metadata":{}},"message":"Simulation completed"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/student/access-requests":{"post":{"tags":["Student Access Requests"],"summary":"Create Access Request Route","operationId":"create_access_request_route_api_v1_student_access_requests_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAccessRequestIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]},"get":{"tags":["Student Access Requests"],"summary":"List My Access Requests Route","operationId":"list_my_access_requests_route_api_v1_student_access_requests_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/AccessRequestStatus"},{"type":"null"}],"title":"Status"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/student/access-requests/{request_id}/cancel":{"post":{"tags":["Student Access Requests"],"summary":"Cancel Access Request Route","operationId":"cancel_access_request_route_api_v1_student_access_requests__request_id__cancel_post","parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"integer","title":"Request Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/access-requests":{"get":{"tags":["Admin Access Requests"],"summary":"List Access Requests Route","operationId":"list_access_requests_route_api_v1_admin_access_requests_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/AccessRequestStatus"},{"type":"null"}],"title":"Status"}},{"name":"simulation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Simulation Id"}},{"name":"organisation_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"title":"Organisation Id"}},{"name":"user_type","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/UserType"},{"type":"null"}],"title":"User Type"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/access-requests/{request_id}/approve":{"post":{"tags":["Admin Access Requests"],"summary":"Approve Access Request Route","operationId":"approve_access_request_route_api_v1_admin_access_requests__request_id__approve_post","parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"integer","title":"Request Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/access-requests/{request_id}/reject":{"post":{"tags":["Admin Access Requests"],"summary":"Reject Access Request Route","operationId":"reject_access_request_route_api_v1_admin_access_requests__request_id__reject_post","parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"integer","title":"Request Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RejectAccessRequestIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/org/access-requests/{request_id}/approve":{"post":{"tags":["Org Access Requests"],"summary":"Org Approve Access Request Route","operationId":"org_approve_access_request_route_api_v1_org_access_requests__request_id__approve_post","parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"integer","title":"Request Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/org/access-requests/{request_id}/reject":{"post":{"tags":["Org Access Requests"],"summary":"Org Reject Access Request Route","operationId":"org_reject_access_request_route_api_v1_org_access_requests__request_id__reject_post","parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"integer","title":"Request Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RejectAccessRequestIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/b2c-access-requests/{request_id}/approve":{"post":{"tags":["Admin B2C Access Requests"],"summary":"B2C Approve Access Request Route","operationId":"b2c_approve_access_request_route_api_v1_admin_b2c_access_requests__request_id__approve_post","parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"integer","title":"Request Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/b2c-access-requests/{request_id}/reject":{"post":{"tags":["Admin B2C Access Requests"],"summary":"B2C Reject Access Request Route","operationId":"b2c_reject_access_request_route_api_v1_admin_b2c_access_requests__request_id__reject_post","parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"integer","title":"Request Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RejectAccessRequestIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/admin/requests/pending":{"get":{"tags":["Admin Requests"],"summary":"List Pending Requests Route","description":"Unified pending queue: licence requests + B2C access requests in one list,\neach tagged with `request_type`.","operationId":"list_pending_requests_route_api_v1_admin_requests_pending_get","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/notifications":{"get":{"tags":["Notifications"],"summary":"List Notifications Route","operationId":"list_notifications_route_api_v1_notifications_get","parameters":[{"name":"only_unread","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Only Unread"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"items":[{"id":1,"type":"system","title":"Licence approved","message":"Your licence request #1 for Open Pit Simulation has been approved.","link":null,"read_at":null,"created_at":"2024-01-01T10:00:00"}],"total":1,"page":1,"size":20,"pages":1},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/notifications/unread-count":{"get":{"tags":["Notifications"],"summary":"Unread Count Route","operationId":"unread_count_route_api_v1_notifications_unread_count_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"count":5},"message":"Success"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"422":{"description":"Validation Error – invalid request body","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Validation error. Please check your input.","errors":{"detail":[{"type":"missing","loc":["body","email"],"msg":"Field required","input":{}}],"request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/notifications/{notification_id}/read":{"post":{"tags":["Notifications"],"summary":"Mark Read Route","operationId":"mark_read_route_api_v1_notifications__notification_id__read_post","parameters":[{"name":"notification_id","in":"path","required":true,"schema":{"type":"integer","title":"Notification Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"ok":true},"message":"Notification marked as read"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/notifications/mark-all-read":{"post":{"tags":["Notifications"],"summary":"Mark All Read Route","operationId":"mark_all_read_route_api_v1_notifications_mark_all_read_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"marked":12},"message":"All notifications marked as read"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"422":{"description":"Validation Error – invalid request body","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Validation error. Please check your input.","errors":{"detail":[{"type":"missing","loc":["body","email"],"msg":"Field required","input":{}}],"request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/notifications/devices":{"post":{"tags":["Notifications"],"summary":"Register Device Route","operationId":"register_device_route_api_v1_notifications_devices_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FcmRegisterIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"ok":true},"message":"Device token registered"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/notifications/devices/{token}":{"delete":{"tags":["Notifications"],"summary":"Unregister Device Route","operationId":"unregister_device_route_api_v1_notifications_devices__token__delete","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"ok":true},"message":"Device token removed"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/activity-logs":{"get":{"tags":["Activity Logs"],"summary":"List Activity Logs Route","operationId":"list_activity_logs_route_api_v1_activity_logs_get","parameters":[{"name":"activity","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Activity"}},{"name":"action","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/ActivityAction"},{"type":"null"}],"title":"Action"}},{"name":"mapping_table","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mapping Table"}},{"name":"mapping_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Mapping Id"}},{"name":"actor_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Actor Id"}},{"name":"date_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Date From"}},{"name":"date_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Date To"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Free-text search in description","title":"Q"},"description":"Free-text search in description"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Size"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"type":"string","pattern":"^(asc|desc)$","default":"desc","title":"Order"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"items":[{"id":1,"description":"User John Smith created B2B student student@acme.com","mapping_id":1002,"mapping_table":"users","created_by":2,"activity":"student_creation","action":"create","request_id":"req-abc123","created_at":"2024-01-01T10:00:00","updated_at":"2024-01-01T10:00:00","deleted_at":null}],"total":1,"page":1,"size":20,"pages":1},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/settings/flags":{"get":{"tags":["Settings"],"summary":"List Global Flags Route","operationId":"list_global_flags_route_api_v1_settings_flags_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":[{"flag_key":"ENABLE_EMAIL_NOTIFICATIONS","enabled":true,"value":null,"description":"Send email notifications to users","source":"global"}],"message":"Success"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"422":{"description":"Validation Error – invalid request body","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Validation error. Please check your input.","errors":{"detail":[{"type":"missing","loc":["body","email"],"msg":"Field required","input":{}}],"request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]},"post":{"tags":["Settings"],"summary":"Set Global Flag Route","operationId":"set_global_flag_route_api_v1_settings_flags_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagSetIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"flag_key":"ENABLE_EMAIL_NOTIFICATIONS","enabled":true,"value":null,"description":"Send email notifications to users","source":"global"},"message":"Flag updated"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/settings/orgs/{organisation_id}":{"get":{"tags":["Settings"],"summary":"List Org Flags Route","operationId":"list_org_flags_route_api_v1_settings_orgs__organisation_id__get","parameters":[{"name":"organisation_id","in":"path","required":true,"schema":{"type":"integer","title":"Organisation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":[{"flag_key":"ENABLE_EMAIL_NOTIFICATIONS","enabled":true,"value":null,"description":"Send email notifications to users","source":"global"}],"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]},"post":{"tags":["Settings"],"summary":"Set Org Flag Route","operationId":"set_org_flag_route_api_v1_settings_orgs__organisation_id__post","parameters":[{"name":"organisation_id","in":"path","required":true,"schema":{"type":"integer","title":"Organisation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagSetIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"flag_key":"ENABLE_EMAIL_NOTIFICATIONS","enabled":true,"value":null,"description":"Send email notifications to users","source":"global"},"message":"Flag updated"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/settings/users/{user_id}":{"get":{"tags":["Settings"],"summary":"List User Flags Route","operationId":"list_user_flags_route_api_v1_settings_users__user_id__get","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":[{"flag_key":"ENABLE_EMAIL_NOTIFICATIONS","enabled":true,"value":null,"description":"Send email notifications to users","source":"global"}],"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]},"post":{"tags":["Settings"],"summary":"Set User Flag Route","operationId":"set_user_flag_route_api_v1_settings_users__user_id__post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlagSetIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"flag_key":"ENABLE_EMAIL_NOTIFICATIONS","enabled":true,"value":null,"description":"Send email notifications to users","source":"global"},"message":"Flag updated"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/settings/resolve/{flag_key}":{"get":{"tags":["Settings"],"summary":"Resolve Flag Route","operationId":"resolve_flag_route_api_v1_settings_resolve__flag_key__get","parameters":[{"name":"flag_key","in":"path","required":true,"schema":{"type":"string","title":"Flag Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"flag_key":"ENABLE_EMAIL_NOTIFICATIONS","enabled":true,"value":null,"description":"Send email notifications to users","source":"global"},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}},"/api/v1/api-filter":{"get":{"tags":["API Filter"],"summary":"Api Filter Route","operationId":"api_filter_route_api_v1_api_filter_get","parameters":[{"name":"type","in":"query","required":true,"schema":{"type":"string","description":"Resource whose filters to fetch (e.g. 'b2c_students')","title":"Type"},"description":"Resource whose filters to fetch (e.g. 'b2c_students')"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{},"example":{"status":"success","data":{"type":"b2c_students","filters":{"simulation":[{"value":10,"label":"Open Pit Simulation"},{"value":20,"label":"Underground Mining"}],"status":[{"value":"active","label":"Active"},{"value":"inactive","label":"Inactive"}],"country":[{"value":"ZA","label":"South Africa"},{"value":"GB","label":"United Kingdom"}]}},"message":"Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"400":{"description":"Bad Request","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Invalid request parameters","errors":{"code":"BAD_REQUEST","request_id":"req-abc123"}}}}},"401":{"description":"Unauthorised – missing or invalid JWT","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Authentication required","errors":{"code":"UNAUTHORIZED","request_id":"req-abc123"}}}}},"403":{"description":"Forbidden – insufficient permissions","content":{"application/json":{"example":{"status":"fail","data":{},"message":"You do not have permission to perform this action","errors":{"code":"FORBIDDEN","request_id":"req-abc123"}}}}},"404":{"description":"Not Found","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Resource not found","errors":{"code":"NOT_FOUND","request_id":"req-abc123"}}}}},"409":{"description":"Conflict – duplicate resource","content":{"application/json":{"example":{"status":"fail","data":{},"message":"A resource with this identifier already exists","errors":{"code":"CONFLICT","request_id":"req-abc123"}}}}},"429":{"description":"Too Many Requests – rate limit exceeded","content":{"application/json":{"example":{"status":"fail","data":{},"message":"Too many requests. Please slow down.","errors":{"code":"RATE_LIMITED","request_id":"req-abc123"}}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"example":{"status":"fail","data":{},"message":"An unexpected error occurred. Please try again later.","errors":{"code":"INTERNAL_ERROR","request_id":"req-abc123"}}}}}},"security":[{"BearerAuth":[]}]}}},"components":{"schemas":{"AccessRequestStatus":{"type":"string","enum":["pending","approved","rejected","cancelled"],"title":"AccessRequestStatus","description":"Lifecycle of a student-initiated simulation access request."},"ActivityAction":{"type":"string","enum":["create","read","update","delete"],"title":"ActivityAction"},"AdminAssignLicenceIn":{"properties":{"organisation_id":{"type":"integer","minimum":1.0,"title":"Organisation Id"},"items":{"items":{"$ref":"#/components/schemas/AssignLicenceItem"},"type":"array","minItems":1,"title":"Items","description":"One entry per simulation to assign"},"notes":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Notes"}},"type":"object","required":["organisation_id","items"],"title":"AdminAssignLicenceIn","description":"Master admin assigns one or many simulations to an organisation.\n\nA single ``items`` list keeps the contract identical for the one-simulation\nand many-simulation cases — the caller just sends a list of length 1..N."},"AllocateIn":{"properties":{"request_id":{"type":"integer","title":"Request Id"},"user_ids":{"items":{"type":"integer"},"type":"array","minItems":1,"title":"User Ids","description":"Student IDs to allocate"}},"type":"object","required":["request_id","user_ids"],"title":"AllocateIn"},"AssignLicenceItem":{"properties":{"simulation_id":{"type":"integer","minimum":1.0,"title":"Simulation Id"},"licence_count":{"type":"integer","minimum":1.0,"title":"Licence Count","description":"Number of licences in the pool"},"expiry_date":{"type":"string","format":"date","title":"Expiry Date","description":"Date the pool expires (inclusive)"}},"type":"object","required":["simulation_id","licence_count","expiry_date"],"title":"AssignLicenceItem","description":"One simulation grant: how many licences and until when.\n\nCross-field rules (expiry-in-future, no duplicate simulations) are enforced\nin the service layer so they surface as the standard domain error envelope."},"AssignSimulationIn":{"properties":{"user_ids":{"items":{"type":"integer"},"type":"array","minItems":1,"title":"User Ids","description":"Student user IDs to assign the simulation to"}},"type":"object","required":["user_ids"],"title":"AssignSimulationIn"},"AssignSimulationsIn":{"properties":{"simulation_ids":{"items":{"type":"integer"},"type":"array","minItems":1,"title":"Simulation Ids"},"validity_days":{"anyOf":[{"type":"integer","maximum":3650.0,"minimum":1.0},{"type":"null"}],"title":"Validity Days","description":"Validity window in days; access expires automatically after it. Mutually exclusive with expires_at. Omit both for lifetime access."},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At","description":"Explicit expiry timestamp (must be in the future). Mutually exclusive with validity_days. Omit both for lifetime access."}},"type":"object","required":["simulation_ids"],"title":"AssignSimulationsIn"},"B2BStudentCreateIn":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"country":{"type":"string","maxLength":64,"minLength":1,"title":"Country"},"contact_no":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Contact No"},"full_name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Full Name"},"request_ids":{"items":{"type":"integer"},"type":"array","title":"Request Ids","description":"Optional licence request IDs to allocate immediately on creation"}},"type":"object","required":["email","country"],"title":"B2BStudentCreateIn"},"B2CStudentCreateIn":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"country":{"type":"string","maxLength":64,"minLength":1,"title":"Country"},"contact_no":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Contact No"},"full_name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Full Name"},"simulation_ids":{"anyOf":[{"items":{"type":"integer"},"type":"array","maxItems":200},{"type":"null"}],"title":"Simulation Ids","description":"Optional simulations to grant on creation. Omit or send [] to skip."}},"type":"object","required":["email","country"],"title":"B2CStudentCreateIn"},"Body_bulk_import_route_api_v1_admin_b2c_students_bulk_import_post":{"properties":{"file":{"type":"string","format":"binary","title":"File"}},"type":"object","required":["file"],"title":"Body_bulk_import_route_api_v1_admin_b2c_students_bulk_import_post"},"Body_bulk_import_route_api_v1_org_students_bulk_import_post":{"properties":{"file":{"type":"string","format":"binary","title":"File"}},"type":"object","required":["file"],"title":"Body_bulk_import_route_api_v1_org_students_bulk_import_post"},"Body_bulk_preview_route_api_v1_admin_b2c_students_bulk_preview_post":{"properties":{"file":{"type":"string","format":"binary","title":"File"}},"type":"object","required":["file"],"title":"Body_bulk_preview_route_api_v1_admin_b2c_students_bulk_preview_post"},"Body_bulk_preview_route_api_v1_org_students_bulk_preview_post":{"properties":{"file":{"type":"string","format":"binary","title":"File"}},"type":"object","required":["file"],"title":"Body_bulk_preview_route_api_v1_org_students_bulk_preview_post"},"ChangePasswordIn":{"properties":{"current_password":{"type":"string","maxLength":128,"minLength":1,"title":"Current Password"},"new_password":{"type":"string","maxLength":128,"minLength":8,"title":"New Password"},"confirm_password":{"type":"string","maxLength":128,"minLength":8,"title":"Confirm Password"}},"type":"object","required":["current_password","new_password","confirm_password"],"title":"ChangePasswordIn"},"CheckEmailIn":{"properties":{"email":{"type":"string","format":"email","title":"Email"}},"type":"object","required":["email"],"title":"CheckEmailIn","description":"Public pre-login probe: does an account usable on this portal exist?"},"CompleteIn":{"properties":{"score":{"anyOf":[{"type":"number","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Score"},"duration_seconds":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Duration Seconds"},"metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metadata"}},"type":"object","title":"CompleteIn"},"CreateAccessRequestIn":{"properties":{"simulation_id":{"type":"integer","minimum":1.0,"title":"Simulation Id"},"note":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Note","description":"Optional message to the reviewer"}},"type":"object","required":["simulation_id"],"title":"CreateAccessRequestIn"},"DeleteB2BStudentsIn":{"properties":{"user_ids":{"items":{"type":"integer"},"type":"array","minItems":1,"title":"User Ids"}},"type":"object","required":["user_ids"],"title":"DeleteB2BStudentsIn"},"DeleteB2CStudentsIn":{"properties":{"user_ids":{"items":{"type":"integer"},"type":"array","minItems":1,"title":"User Ids"}},"type":"object","required":["user_ids"],"title":"DeleteB2CStudentsIn"},"FcmRegisterIn":{"properties":{"token":{"type":"string","maxLength":500,"minLength":4,"title":"Token"},"platform":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Platform"}},"type":"object","required":["token"],"title":"FcmRegisterIn"},"FlagSetIn":{"properties":{"flag_key":{"type":"string","title":"Flag Key"},"enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Enabled"},"value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Value"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","required":["flag_key"],"title":"FlagSetIn"},"ForgotPasswordIn":{"properties":{"email":{"type":"string","format":"email","title":"Email"}},"type":"object","required":["email"],"title":"ForgotPasswordIn"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"LicenceRequestIn":{"properties":{"simulation_id":{"type":"integer","title":"Simulation Id"},"quantity":{"type":"integer","minimum":1.0,"title":"Quantity"},"duration_months":{"type":"integer","minimum":1.0,"title":"Duration Months"},"parent_request_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Parent Request Id"},"notes":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Notes","description":"Optional context for the master admin"}},"type":"object","required":["simulation_id","quantity","duration_months"],"title":"LicenceRequestIn"},"LicenceRequestStatus":{"type":"string","enum":["pending","approved","rejected","expired"],"title":"LicenceRequestStatus"},"LoginIn":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"password":{"type":"string","maxLength":128,"minLength":1,"title":"Password"}},"type":"object","required":["email","password"],"title":"LoginIn"},"LoginOtpRequestIn":{"properties":{"email":{"type":"string","format":"email","title":"Email"}},"type":"object","required":["email"],"title":"LoginOtpRequestIn"},"LoginOtpVerifyIn":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"code":{"type":"string","maxLength":6,"minLength":6,"title":"Code"}},"type":"object","required":["email","code"],"title":"LoginOtpVerifyIn"},"LogoutIn":{"properties":{"refresh_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Refresh Token"}},"type":"object","title":"LogoutIn"},"LogoutSessionsIn":{"properties":{"session_ids":{"items":{"type":"integer"},"type":"array","minItems":1,"title":"Session Ids","description":"IDs from GET /sessions to terminate"}},"type":"object","required":["session_ids"],"title":"LogoutSessionsIn"},"MeUpdateIn":{"properties":{"country":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Country"},"contact_no":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Contact No"},"full_name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Full Name"}},"type":"object","title":"MeUpdateIn"},"ModuleCreateIn":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name"},"slug":{"type":"string","maxLength":255,"minLength":1,"title":"Slug"},"description":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Description"},"icon":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Icon"},"status":{"$ref":"#/components/schemas/SimulationStatus","default":"active"},"display_order":{"type":"integer","minimum":0.0,"title":"Display Order","default":0}},"type":"object","required":["name","slug"],"title":"ModuleCreateIn"},"ModuleUpdateIn":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Name"},"slug":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Slug"},"description":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Description"},"icon":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Icon"},"status":{"anyOf":[{"$ref":"#/components/schemas/SimulationStatus"},{"type":"null"}]},"display_order":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Display Order"}},"type":"object","title":"ModuleUpdateIn"},"OrgAdminPatchIn":{"properties":{"email":{"anyOf":[{"type":"string","format":"email"},{"type":"null"}],"title":"Email"},"full_name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Full Name"},"country":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Country"},"contact_no":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Contact No"},"is_active":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Active"}},"type":"object","title":"OrgAdminPatchIn"},"OrgCreateIn":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name"},"country":{"type":"string","maxLength":64,"minLength":1,"title":"Country"},"org_type":{"anyOf":[{"$ref":"#/components/schemas/OrganisationType"},{"type":"null"}]},"contact_email":{"anyOf":[{"type":"string","format":"email"},{"type":"null"}],"title":"Contact Email"},"contact_phone":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Contact Phone"},"notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Notes"},"admin_email":{"type":"string","format":"email","title":"Admin Email"},"admin_full_name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Admin Full Name"},"admin_country":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Admin Country"},"admin_contact_no":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Admin Contact No"}},"type":"object","required":["name","country","admin_email"],"title":"OrgCreateIn"},"OrgUpdateIn":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Name"},"country":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Country"},"org_type":{"anyOf":[{"$ref":"#/components/schemas/OrganisationType"},{"type":"null"}]},"status":{"anyOf":[{"$ref":"#/components/schemas/OrganisationStatus"},{"type":"null"}]},"contact_email":{"anyOf":[{"type":"string","format":"email"},{"type":"null"}],"title":"Contact Email"},"contact_phone":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Contact Phone"},"notes":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Notes"}},"type":"object","title":"OrgUpdateIn"},"OrganisationStatus":{"type":"string","enum":["active","inactive","suspended"],"title":"OrganisationStatus"},"OrganisationType":{"type":"string","enum":["partner","government","corporate","academic","ngo","other"],"title":"OrganisationType"},"OtpPurpose":{"type":"string","enum":["first_login","login","forgot_password"],"title":"OtpPurpose"},"PerformanceBand":{"type":"string","enum":["need_improvement","average","good","excellent"],"title":"PerformanceBand"},"RefreshIn":{"properties":{"refresh_token":{"type":"string","title":"Refresh Token"}},"type":"object","required":["refresh_token"],"title":"RefreshIn"},"RejectAccessRequestIn":{"properties":{"reason":{"type":"string","maxLength":1000,"minLength":1,"title":"Reason"}},"type":"object","required":["reason"],"title":"RejectAccessRequestIn"},"RejectIn":{"properties":{"reason":{"type":"string","maxLength":1000,"minLength":1,"title":"Reason"}},"type":"object","required":["reason"],"title":"RejectIn"},"ResetPasswordIn":{"properties":{"reset_token":{"type":"string","title":"Reset Token"},"password":{"type":"string","maxLength":128,"minLength":8,"title":"Password"},"confirm_password":{"type":"string","maxLength":128,"minLength":8,"title":"Confirm Password"}},"type":"object","required":["reset_token","password","confirm_password"],"title":"ResetPasswordIn"},"SetPasswordIn":{"properties":{"setup_token":{"type":"string","title":"Setup Token"},"password":{"type":"string","maxLength":128,"minLength":8,"title":"Password"},"confirm_password":{"type":"string","maxLength":128,"minLength":8,"title":"Confirm Password"}},"type":"object","required":["setup_token","password","confirm_password"],"title":"SetPasswordIn"},"SimulationCreateIn":{"properties":{"name":{"type":"string","maxLength":255,"minLength":1,"title":"Name"},"slug":{"type":"string","maxLength":255,"minLength":1,"title":"Slug"},"module_id":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Module Id"},"description":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Description"},"status":{"$ref":"#/components/schemas/SimulationStatus","default":"active"},"passing_score":{"type":"integer","maximum":100.0,"minimum":0.0,"title":"Passing Score","default":50},"duration_minutes":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Duration Minutes"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"},"cover_image_url":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Cover Image Url"},"runner_url":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Runner Url"}},"type":"object","required":["name","slug"],"title":"SimulationCreateIn"},"SimulationStatus":{"type":"string","enum":["active","draft","archived","inactive"],"title":"SimulationStatus"},"SimulationUpdateIn":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Name"},"slug":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Slug"},"module_id":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Module Id"},"description":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Description"},"status":{"anyOf":[{"$ref":"#/components/schemas/SimulationStatus"},{"type":"null"}]},"passing_score":{"anyOf":[{"type":"integer","maximum":100.0,"minimum":0.0},{"type":"null"}],"title":"Passing Score"},"duration_minutes":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Duration Minutes"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"},"cover_image_url":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Cover Image Url"},"runner_url":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Runner Url"}},"type":"object","title":"SimulationUpdateIn"},"StartIn":{"properties":{"simulation_id":{"type":"integer","title":"Simulation Id"},"allocation_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Allocation Id"}},"type":"object","required":["simulation_id"],"title":"StartIn"},"UserType":{"type":"string","enum":["master_admin","org_admin","b2b_student","b2c_student"],"title":"UserType"},"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"},"VerifyOtpIn":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"code":{"type":"string","maxLength":6,"minLength":6,"title":"Code"},"purpose":{"$ref":"#/components/schemas/OtpPurpose"}},"type":"object","required":["email","code","purpose"],"title":"VerifyOtpIn"},"apps__v1__api__b2c_student__schema__RevokeSimulationIn":{"properties":{"simulation_id":{"type":"integer","title":"Simulation Id"},"reason":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Reason"}},"type":"object","required":["simulation_id"],"title":"RevokeSimulationIn"},"apps__v1__api__org_licences__schema__RevokeSimulationIn":{"properties":{"user_ids":{"items":{"type":"integer"},"type":"array","minItems":1,"title":"User Ids","description":"Student user IDs to revoke the simulation from"}},"type":"object","required":["user_ids"],"title":"RevokeSimulationIn"}},"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT access token from SessionMiddleware (`Authorization: Bearer <token>`). Use POST `/auth/master/...` or `/auth/portal/...` (login, refresh, onboarding OTP/password)."}}}}