{"openapi":"3.1.0","info":{"title":"VeriCash API","version":"0.1.0"},"paths":{"/api/auth/register":{"post":{"tags":["auth"],"summary":"Register","operationId":"register_api_auth_register_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserCreate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/login":{"post":{"tags":["auth"],"summary":"Login","description":"Standard OAuth2 password flow (application/x-www-form-urlencoded).","operationId":"login_api_auth_login_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_login_api_auth_login_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/me":{"get":{"tags":["auth"],"summary":"Me","operationId":"me_api_auth_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserOut"}}}}},"security":[{"OAuth2PasswordBearer":[]}]},"put":{"tags":["auth"],"summary":"Update Me","operationId":"update_me_api_auth_me_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/auth/me/password":{"put":{"tags":["auth"],"summary":"Change Password","operationId":"change_password_api_auth_me_password_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasswordChange"}}},"required":true},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/auth/forgot-password":{"post":{"tags":["auth"],"summary":"Forgot Password","description":"Generate a 6-digit reset code.\n\nIn a production system this would be emailed. For this demo the code is\nreturned directly in the response so the developer can test without an\nSMTP server.","operationId":"forgot_password_api_auth_forgot_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForgotPasswordRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/reset-password":{"post":{"tags":["auth"],"summary":"Reset Password","operationId":"reset_password_api_auth_reset_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordRequest"}}},"required":true},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/users":{"get":{"tags":["auth"],"summary":"List Users","operationId":"list_users_api_auth_users_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/UserOut"},"type":"array","title":"Response List Users Api Auth Users Get"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/auth/users/{user_id}":{"put":{"tags":["auth"],"summary":"Update User","operationId":"update_user_api_auth_users__user_id__put","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserAdminUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["auth"],"summary":"Delete User","operationId":"delete_user_api_auth_users__user_id__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/scan":{"post":{"tags":["scan"],"summary":"Scan Note","description":"Scan a banknote image. Works for guests (result not saved) and logged-in users.","operationId":"scan_note_api_scan_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_scan_note_api_scan_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/scan/batch":{"post":{"tags":["scan"],"summary":"Scan Batch","description":"Scan multiple banknote images in one request (max 10).","operationId":"scan_batch_api_scan_batch_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_scan_batch_api_scan_batch_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/ScanResult"},"type":"array","title":"Response Scan Batch Api Scan Batch Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/scan/history":{"get":{"tags":["scan"],"summary":"History","description":"Return scan history.\n\n- Admin  : all scans (bureau-wide audit log).\n- Viewer : all scans (read-only oversight role).\n- Inspector : own scans only (operational record).","operationId":"history_api_scan_history_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScanResult"},"title":"Response History Api Scan History Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["scan"],"summary":"Clear History","description":"Clear scan history.\n\n- Inspector: deletes only their own scans.\n- Admin: deletes ALL scans (bureau-wide).\n- Viewer: forbidden.","operationId":"clear_history_api_scan_history_delete","security":[{"OAuth2PasswordBearer":[]}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/scan/stats":{"get":{"tags":["scan"],"summary":"Scan Stats","description":"Aggregate stats for the dashboard charts.","operationId":"scan_stats_api_scan_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/scan/export":{"get":{"tags":["scan"],"summary":"Export Csv","description":"Export scan history as CSV.","operationId":"export_csv_api_scan_export_get","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"token","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/members":{"get":{"tags":["members"],"summary":"List Members","operationId":"list_members_api_members_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/TeamMemberOut"},"type":"array","title":"Response List Members Api Members Get"}}}}}},"post":{"tags":["members"],"summary":"Create Member","operationId":"create_member_api_members_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamMemberIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamMemberOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/members/{mid}":{"put":{"tags":["members"],"summary":"Update Member","operationId":"update_member_api_members__mid__put","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"mid","in":"path","required":true,"schema":{"type":"integer","title":"Mid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamMemberIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamMemberOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["members"],"summary":"Delete Member","operationId":"delete_member_api_members__mid__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"mid","in":"path","required":true,"schema":{"type":"integer","title":"Mid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/currencies":{"get":{"tags":["currencies"],"summary":"List Currencies","operationId":"list_currencies_api_currencies_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/CurrencyConfigOut"},"type":"array","title":"Response List Currencies Api Currencies Get"}}}}}},"post":{"tags":["currencies"],"summary":"Upsert Currency","operationId":"upsert_currency_api_currencies_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurrencyConfigIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurrencyConfigOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"OAuth2PasswordBearer":[]}]}},"/api/currencies/{code}":{"delete":{"tags":["currencies"],"summary":"Delete Currency","operationId":"delete_currency_api_currencies__code__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string","title":"Code"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/settings":{"get":{"tags":["settings"],"summary":"List Settings","operationId":"list_settings_api_settings_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/SettingItem"},"type":"array","title":"Response List Settings Api Settings Get"}}}}}}},"/api/settings/{key}":{"get":{"tags":["settings"],"summary":"Get Setting","operationId":"get_setting_api_settings__key__get","parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","title":"Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingItem"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["settings"],"summary":"Upsert Setting","operationId":"upsert_setting_api_settings__key__put","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","title":"Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingValueIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingItem"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["settings"],"summary":"Delete Setting","operationId":"delete_setting_api_settings__key__delete","security":[{"OAuth2PasswordBearer":[]}],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","title":"Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/":{"get":{"summary":"Root","operationId":"root__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health":{"get":{"summary":"Health","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"Body_login_api_auth_login_post":{"properties":{"grant_type":{"anyOf":[{"type":"string","pattern":"password"},{"type":"null"}],"title":"Grant Type"},"username":{"type":"string","title":"Username"},"password":{"type":"string","title":"Password"},"scope":{"type":"string","title":"Scope","default":""},"client_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Id"},"client_secret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Secret"}},"type":"object","required":["username","password"],"title":"Body_login_api_auth_login_post"},"Body_scan_batch_api_scan_batch_post":{"properties":{"images":{"items":{"type":"string","format":"binary"},"type":"array","title":"Images"},"hint_currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hint Currency"}},"type":"object","required":["images"],"title":"Body_scan_batch_api_scan_batch_post"},"Body_scan_note_api_scan_post":{"properties":{"image":{"type":"string","format":"binary","title":"Image"},"hint_currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hint Currency"}},"type":"object","required":["image"],"title":"Body_scan_note_api_scan_post"},"CurrencyConfigIn":{"properties":{"code":{"type":"string","title":"Code"},"name":{"type":"string","title":"Name"},"enabled":{"type":"boolean","title":"Enabled","default":true},"denominations":{"items":{"type":"string"},"type":"array","title":"Denominations","default":[]}},"type":"object","required":["code","name"],"title":"CurrencyConfigIn"},"CurrencyConfigOut":{"properties":{"code":{"type":"string","title":"Code"},"name":{"type":"string","title":"Name"},"enabled":{"type":"boolean","title":"Enabled","default":true},"denominations":{"items":{"type":"string"},"type":"array","title":"Denominations","default":[]},"id":{"type":"integer","title":"Id"},"accuracy":{"type":"number","title":"Accuracy","default":0.0}},"type":"object","required":["code","name","id"],"title":"CurrencyConfigOut"},"ForgotPasswordRequest":{"properties":{"email":{"type":"string","format":"email","title":"Email"}},"type":"object","required":["email"],"title":"ForgotPasswordRequest"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"PasswordChange":{"properties":{"current_password":{"type":"string","title":"Current Password"},"new_password":{"type":"string","maxLength":128,"minLength":6,"title":"New Password"}},"type":"object","required":["current_password","new_password"],"title":"PasswordChange"},"ResetPasswordRequest":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"code":{"type":"string","title":"Code"},"new_password":{"type":"string","maxLength":128,"minLength":6,"title":"New Password"}},"type":"object","required":["email","code","new_password"],"title":"ResetPasswordRequest"},"ScanResult":{"properties":{"id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Id"},"currency":{"type":"string","title":"Currency"},"denomination":{"type":"string","title":"Denomination"},"authenticity_score":{"type":"number","title":"Authenticity Score"},"verdict":{"type":"string","title":"Verdict"},"confidence":{"type":"number","title":"Confidence"},"demonetized":{"type":"boolean","title":"Demonetized","default":false},"breakdown":{"type":"object","title":"Breakdown"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"}},"type":"object","required":["currency","denomination","authenticity_score","verdict","confidence","breakdown"],"title":"ScanResult"},"SettingItem":{"properties":{"key":{"type":"string","title":"Key"},"value":{"title":"Value"}},"type":"object","required":["key","value"],"title":"SettingItem","description":"Setting value can be any JSON type (number, string, boolean, list, dict)."},"SettingValueIn":{"properties":{"value":{"title":"Value"}},"type":"object","required":["value"],"title":"SettingValueIn"},"TeamMemberIn":{"properties":{"name":{"type":"string","title":"Name"},"role":{"type":"string","title":"Role"},"github":{"type":"string","title":"Github","default":""},"photo_url":{"type":"string","title":"Photo Url","default":""},"contribution":{"type":"string","title":"Contribution","default":""},"order_index":{"type":"integer","title":"Order Index","default":0}},"type":"object","required":["name","role"],"title":"TeamMemberIn"},"TeamMemberOut":{"properties":{"name":{"type":"string","title":"Name"},"role":{"type":"string","title":"Role"},"github":{"type":"string","title":"Github","default":""},"photo_url":{"type":"string","title":"Photo Url","default":""},"contribution":{"type":"string","title":"Contribution","default":""},"order_index":{"type":"integer","title":"Order Index","default":0},"id":{"type":"integer","title":"Id"}},"type":"object","required":["name","role","id"],"title":"TeamMemberOut"},"TokenOut":{"properties":{"access_token":{"type":"string","title":"Access Token"},"token_type":{"type":"string","title":"Token Type","default":"bearer"},"user":{"$ref":"#/components/schemas/UserOut"}},"type":"object","required":["access_token","user"],"title":"TokenOut"},"UserAdminUpdate":{"properties":{"full_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Full Name"},"role":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Role"},"password":{"anyOf":[{"type":"string","maxLength":128,"minLength":6},{"type":"null"}],"title":"Password"}},"type":"object","title":"UserAdminUpdate"},"UserCreate":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"full_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Full Name"},"password":{"type":"string","maxLength":128,"minLength":6,"title":"Password"}},"type":"object","required":["email","password"],"title":"UserCreate"},"UserOut":{"properties":{"id":{"type":"integer","title":"Id"},"email":{"type":"string","format":"email","title":"Email"},"full_name":{"type":"string","title":"Full Name"},"role":{"type":"string","title":"Role"}},"type":"object","required":["id","email","full_name","role"],"title":"UserOut"},"UserUpdate":{"properties":{"full_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Full Name"}},"type":"object","title":"UserUpdate"},"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"}},"securitySchemes":{"OAuth2PasswordBearer":{"type":"oauth2","flows":{"password":{"scopes":{},"tokenUrl":"/api/auth/login"}}}}}}