{"openapi":"3.1.0","info":{"title":"TaiwanFRP","description":"Add your description here","version":"0.1.0"},"paths":{"/api/v1/auth/discord/login":{"get":{"tags":["Auth"],"summary":"Discord Login","description":"生成 Discord OAuth2 登入 URL 並重定向用戶, 同時產生並存儲 CSRF state 防止 CSRF 攻擊","operationId":"discord_login_api_v1_auth_discord_login_get","responses":{"307":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/auth/discord/callback":{"get":{"tags":["Auth"],"summary":"Discord Callback","description":"處理 Discord OAuth2 回調, 驗證 state 並交換 access token","operationId":"discord_callback_api_v1_auth_discord_callback_get","parameters":[{"name":"code","in":"query","required":true,"schema":{"type":"string","title":"Code"}},{"name":"state","in":"query","required":true,"schema":{"type":"string","title":"State"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"Bad Request","content":{"application/json":{"examples":{"invalid_oauth_state":{"summary":"Invalid or missing OAuth state","value":{"detail":"Invalid OAuth state"}},"missing_authorization_code":{"summary":"Missing authorization code","value":{"detail":"Missing authorization code"}},"failed_token_exchange":{"summary":"Failed token exchange","value":{"detail":"Failed to exchange code for token"}},"no_access_token":{"summary":"No access token","value":{"detail":"No access token received"}},"failed_user_info_fetch":{"summary":"Failed user info fetch","value":{"detail":"Failed to fetch user info"}}},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/auth/logout":{"post":{"tags":["Auth"],"summary":"Logout","description":"處理用戶登出, 刪除 session cookie 和 Redis 中的 session","operationId":"logout_api_v1_auth_logout_post","responses":{"204":{"description":"Successful Response"}}}},"/api/v1/users/me":{"get":{"tags":["Users"],"summary":"Read Current User","description":"獲取當前用戶信息的路由, 需要驗證","operationId":"read_current_user_api_v1_users_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurrentUser"}}}},"401":{"description":"Not authenticated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"cookie_missing":{"summary":"Cookie missing","value":{"detail":"Not authenticated"}},"session_invalid":{"summary":"Session expired or invalid","value":{"detail":"Session expired or invalid"}}}}}},"403":{"description":"Account cannot be used","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"account_suspended":{"summary":"Account not active","value":{"detail":"Account is suspended"}},"account_deleted":{"summary":"Account has been deleted","value":{"detail":"Account is deleted"}},"account_banned":{"summary":"Account is banned","value":{"detail":"Account is banned"}}}}}}}}},"/api/v1/users/{discord_id}/activate":{"post":{"tags":["Users"],"summary":"Activate User","description":"啟用帳號","operationId":"activate_user_api_v1_users__discord_id__activate_post","parameters":[{"name":"discord_id","in":"path","required":true,"schema":{"type":"string","title":"Discord Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/users/me/become-node-provider":{"post":{"tags":["Users"],"summary":"Become Node Provider","description":"使用者自助取得節點提供者資格 (node_provider 身分組), 使其獲得 node.create 權限","operationId":"become_node_provider_api_v1_users_me_become_node_provider_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurrentUser"}}}},"401":{"description":"Not authenticated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"cookie_missing":{"summary":"Cookie missing","value":{"detail":"Not authenticated"}},"session_invalid":{"summary":"Session expired or invalid","value":{"detail":"Session expired or invalid"}}}}}},"404":{"description":"User not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"user_not_found":{"summary":"User not found","value":{"detail":"User not found"}}}}}},"409":{"description":"User is already a node provider","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"already_node_provider":{"summary":"Already a node provider","value":{"detail":"User is already a node provider"}}}}}}}}},"/status":{"get":{"tags":["system"],"summary":"Health Check","description":"健康檢查端點，檢查資料庫和 Redis 連線狀態","operationId":"health_check_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthCheckResponseModel"}}}}}}},"/api/v1/nodes":{"get":{"tags":["Nodes"],"summary":"Get Nodes","description":"獲取節點列表的路由, 根據使用者權限返回對應可見的節點列表\n- 未登入、一般使用者: 僅能看到 ACTIVE 且 is_public=True 的節點\n- 節點擁有者: 能看到自己擁有的所有節點\n- 管理員: 能看到所有節點","operationId":"get_nodes_api_v1_nodes_get","parameters":[{"name":"owner","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Owner"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NodeResponse"},"title":"Response Get Nodes Api V1 Nodes Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Nodes"],"summary":"Create Node","description":"建立新的 FRP 節點, 預設狀態為 DRAFT","operationId":"create_node_api_v1_nodes_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeCreateRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeResponse"}}}},"400":{"description":"Invalid port range","content":{"application/json":{"example":{"detail":"port_start must be less than or equal to port_end"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict","content":{"application/json":{"example":{"detail":"Node with the same name or host already exists"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/nodes/{node_id}":{"get":{"tags":["Nodes"],"summary":"Get Node","description":"獲取單個節點的路由, 根據使用者權限返回對應可見的節點資訊\n- 未登入、一般使用者: 僅能看到 ACTIVE 且 is_public=True 的節點\n- 節點擁有者: 能看到自己擁有的所有節點\n- 管理員: 能看到所有節點\n若無權查看則返回 404 Not Found","operationId":"get_node_api_v1_nodes__node_id__get","parameters":[{"name":"node_id","in":"path","required":true,"schema":{"type":"integer","maximum":2147483647,"minimum":1,"description":"Node ID","title":"Node Id"},"description":"Node ID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeResponse"}}}},"404":{"description":"Node not found","content":{"application/json":{"example":{"detail":"Node not found"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Nodes"],"summary":"Update Node","description":"更新節點資訊的路由, 只有節點擁有者或管理員可以更新節點資訊","operationId":"update_node_api_v1_nodes__node_id__patch","parameters":[{"name":"node_id","in":"path","required":true,"schema":{"type":"integer","maximum":2147483647,"minimum":1,"description":"Node ID","title":"Node Id"},"description":"Node ID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeUpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeResponse"}}}},"404":{"description":"Node not found","content":{"application/json":{"example":{"detail":"Node not found"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"400":{"description":"Invalid update request","content":{"application/json":{"examples":{"invalid_port":{"summary":"Invalid port range","value":{"detail":"port_start must be less than or equal to port_end"}},"invalid_status_draft":{"summary":"Cannot manually change status (Draft)","value":{"detail":"Cannot manually change status while node is in draft state"}},"invalid_status_reviewing":{"summary":"Cannot manually change status (Reviewing)","value":{"detail":"Cannot manually change status while node is in reviewing state"}}},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"No authorized","content":{"application/json":{"example":{"detail":"Not authorized to update this node"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict","content":{"application/json":{"example":{"detail":"Node with the same name or host already exists"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Nodes"],"summary":"Delete Node","description":"刪除節點的路由, 只有節點擁有者或管理員可以刪除節點","operationId":"delete_node_api_v1_nodes__node_id__delete","parameters":[{"name":"node_id","in":"path","required":true,"schema":{"type":"integer","maximum":2147483647,"minimum":1,"description":"Node ID","title":"Node Id"},"description":"Node ID"}],"responses":{"204":{"description":"Successful Response"},"404":{"description":"Node not found","content":{"application/json":{"example":{"detail":"Node not found"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"No authorized","content":{"application/json":{"example":{"detail":"Not authorized to delete this node"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/tunnels":{"get":{"tags":["Tunnels"],"summary":"Get Tunnels","description":"列出當前使用者建立的所有隧道","operationId":"get_tunnels_api_v1_tunnels_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/TunnelResponse"},"type":"array","title":"Response Get Tunnels Api V1 Tunnels Get"}}}}}},"post":{"tags":["Tunnels"],"summary":"Create Tunnel","description":"建立新的 FRP 隧道","operationId":"create_tunnel_api_v1_tunnels_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TunnelCreateRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TunnelCreateResponse"}}}},"404":{"description":"Node not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Node not found"}}}},"400":{"description":"Invalid request data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"Node is not available":{"summary":"Node is not available","value":{"detail":"Node is not available"}},"Remote port is missing for TCP and UDP protocols":{"summary":"Remote port is missing for TCP and UDP protocols","value":{"detail":"remote_port is required for TCP and UDP protocols"}},"Remote port is out of range":{"summary":"Remote port is out of range","value":{"detail":"remote_port must be between <number> and <number>"}},"Remote port is already in use":{"summary":"Remote port is already in use","value":{"detail":"remote_port is already in use on this node"}}}}}},"403":{"description":"Port has been reached the maximum limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"You have reached your maximum tunnel limit <number>"}}}},"409":{"description":"Conflict with existing tunnel","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"A tunnel with the same configuration already exists"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/tunnels/{tunnel_id}":{"get":{"tags":["Tunnels"],"summary":"Get Tunnel","description":"取得指定的隧道資訊","operationId":"get_tunnel_api_v1_tunnels__tunnel_id__get","parameters":[{"name":"tunnel_id","in":"path","required":true,"schema":{"type":"string","minLength":36,"maxLength":36,"description":"隧道的 UUID","title":"Tunnel Id"},"description":"隧道的 UUID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TunnelResponse"}}}},"404":{"description":"Tunnel not found","content":{"application/json":{"example":{"detail":"Tunnel not found"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Tunnels"],"summary":"Update Tunnel","description":"更新指定的隧道資訊","operationId":"update_tunnel_api_v1_tunnels__tunnel_id__patch","parameters":[{"name":"tunnel_id","in":"path","required":true,"schema":{"type":"string","minLength":36,"maxLength":36,"description":"隧道的 UUID","title":"Tunnel Id"},"description":"隧道的 UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TunnelUpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TunnelResponse"}}}},"404":{"description":"Node not found","content":{"application/json":{"example":{"detail":"Node not found"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"400":{"description":"Invalid request data","content":{"application/json":{"examples":{"Node is not available":{"summary":"Node is not available","value":{"detail":"Node is not available"}},"Remote port is missing for TCP and UDP protocols":{"summary":"Remote port is missing for TCP and UDP protocols","value":{"detail":"remote_port is required for TCP and UDP protocols"}},"Remote port is out of range":{"summary":"Remote port is out of range","value":{"detail":"remote_port must be between <number> and <number>"}}},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict with existing tunnel","content":{"application/json":{"examples":{"Remote port has been used":{"summary":"Remote port is already in use","value":{"detail":"remote_port is already in use on this node"}},"Conflict with existing tunnel":{"summary":"Tunnel with the same name already exists","value":{"detail":"Tunnel with the same name already exists"}}},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Tunnels"],"summary":"Delete Tunnel","description":"刪除指定的隧道","operationId":"delete_tunnel_api_v1_tunnels__tunnel_id__delete","parameters":[{"name":"tunnel_id","in":"path","required":true,"schema":{"type":"string","minLength":36,"maxLength":36,"description":"隧道的 UUID","title":"Tunnel Id"},"description":"隧道的 UUID"}],"responses":{"204":{"description":"Successful Response"},"404":{"description":"Tunnel not found","content":{"application/json":{"example":{"detail":"Tunnel not found"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/tunnels/{tunnel_id}/reset-token":{"post":{"tags":["Tunnels"],"summary":"Regenerate Agent Token","description":"重新生成指定隧道的 Agent Token","operationId":"regenerate_agent_token_api_v1_tunnels__tunnel_id__reset_token_post","parameters":[{"name":"tunnel_id","in":"path","required":true,"schema":{"type":"string","minLength":36,"maxLength":36,"description":"隧道的 UUID","title":"Tunnel Id"},"description":"隧道的 UUID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TunnelCreateResponse"}}}},"404":{"description":"Tunnel not found","content":{"application/json":{"example":{"detail":"Tunnel not found"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict with existing token","content":{"application/json":{"example":{"detail":"Failed to regenerate agent token due to a conflict"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/permissions":{"get":{"tags":["Permissions"],"summary":"Get Permissions","description":"取得當前使用者擁有的權限節點列表","operationId":"get_permissions_api_v1_permissions_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/PermissionResponse"},"type":"array","title":"Response Get Permissions Api V1 Permissions Get"}}}}}}},"/api/v1/roles":{"get":{"tags":["Roles"],"summary":"Get Roles","description":"取得所有身份組的列表, 需要 role.read.all 權限\n包含身份組擁有的的權限節點","operationId":"get_roles_api_v1_roles_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/RoleResponse"},"type":"array","title":"Response Get Roles Api V1 Roles Get"}}}}}},"post":{"tags":["Roles"],"summary":"Create Role","description":"建立新的身份組, 需要 role.create 權限\n- 如果 permissions 傳入空陣列, 則身份組不會擁有任何權限節點","operationId":"create_role_api_v1_roles_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoleCreateRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoleResponse"}}}},"400":{"description":"Permissions not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Some permissions not found"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Role with the same name already exists"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/roles/{role_id}":{"get":{"tags":["Roles"],"summary":"Get Role","description":"取得單一身份組的詳細資訊, 需要 role.read.all 權限\n包含身份組擁有的的權限節點","operationId":"get_role_api_v1_roles__role_id__get","parameters":[{"name":"role_id","in":"path","required":true,"schema":{"type":"integer","maximum":2147483647,"minimum":1,"description":"身份組 ID","title":"Role Id"},"description":"身份組 ID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoleResponse"}}}},"404":{"description":"Role not found","content":{"application/json":{"example":{"detail":"Role not found"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Roles"],"summary":"Update Role","description":"更新身份組資訊, 需要 role.update 權限\n- 系統預設身份組 (admin, user, node_provider) 不允許改名\n- 如果 permissions 傳入空陣列, 則身份組不會擁有任何權限節點","operationId":"update_role_api_v1_roles__role_id__patch","parameters":[{"name":"role_id","in":"path","required":true,"schema":{"type":"integer","maximum":2147483647,"minimum":1,"description":"身份組 ID","title":"Role Id"},"description":"身份組 ID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoleUpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoleResponse"}}}},"404":{"description":"Role not found","content":{"application/json":{"example":{"detail":"Role not found"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"400":{"description":"Permissions not found","content":{"application/json":{"example":{"detail":"Some permissions not found"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden","content":{"application/json":{"example":{"detail":"Cannot update system default roles"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict","content":{"application/json":{"example":{"detail":"Role with the same name already exists"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Roles"],"summary":"Delete Role","description":"刪除身份組, 需要 role.delete 權限\n- 系統預設身份組 (admin, user, node_provider) 無法被刪除","operationId":"delete_role_api_v1_roles__role_id__delete","parameters":[{"name":"role_id","in":"path","required":true,"schema":{"type":"integer","maximum":2147483647,"minimum":1,"description":"身份組 ID","title":"Role Id"},"description":"身份組 ID"}],"responses":{"204":{"description":"Successful Response"},"404":{"description":"Role not found","content":{"application/json":{"example":{"detail":"Role not found"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/api-keys":{"get":{"tags":["API-Keys"],"summary":"Get Api Keys","description":"列出當前使用者建立的所有 API Key","operationId":"get_api_keys_api_v1_api_keys_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/ApiKeyResponse"},"type":"array","title":"Response Get Api Keys Api V1 Api Keys Get"}}}}}},"post":{"tags":["API-Keys"],"summary":"Create Api Key","description":"建立新的 API Key","operationId":"create_api_key_api_v1_api_keys_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreateRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreateResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"invalid_permission_ids":{"summary":"Invalid permission IDs","value":{"detail":"One or more permission IDs are invalid"}},"api_key_limit_exceeded":{"summary":"API Key limit exceeded","value":{"detail":"You have reached the maximum limit of <number> API Keys"}}}}}},"403":{"description":"Cannot assign permission you don't have","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Cannot assign permission '<permission_name>' you don't have"}}}},"409":{"description":"API Key generation collision","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"API Key generation collision, please try again"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/api-keys/{api_key_id}":{"get":{"tags":["API-Keys"],"summary":"Get Api Key","description":"取得指定的 API Key 資訊","operationId":"get_api_key_api_v1_api_keys__api_key_id__get","parameters":[{"name":"api_key_id","in":"path","required":true,"schema":{"type":"string","minLength":36,"maxLength":36,"description":"API Key 的 UUID","title":"Api Key Id"},"description":"API Key 的 UUID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["API-Keys"],"summary":"Delete Api Key","description":"刪除指定的 API Key","operationId":"delete_api_key_api_v1_api_keys__api_key_id__delete","parameters":[{"name":"api_key_id","in":"path","required":true,"schema":{"type":"string","minLength":36,"maxLength":36,"description":"API Key 的 UUID","title":"Api Key Id"},"description":"API Key 的 UUID"}],"responses":{"204":{"description":"Successful Response"},"404":{"description":"API Key not found","content":{"application/json":{"example":{"detail":"API Key not found"},"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"ApiKeyCreateRequest":{"properties":{"description":{"type":"string","maxLength":255,"minLength":1,"title":"Description","description":"API Key 的用途描述"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At","description":"API Key 的過期時間, 若為 None 則表示不過期"},"permission_ids":{"items":{"type":"integer"},"type":"array","title":"Permission Ids","description":"API Key 的權限 ID 列表 (可選)"}},"type":"object","required":["description"],"title":"ApiKeyCreateRequest"},"ApiKeyCreateResponse":{"properties":{"id":{"type":"string","title":"Id","description":"API Key 的唯一識別 ID"},"description":{"type":"string","title":"Description","description":"API Key 的用途描述"},"api_key":{"type":"string","title":"Api Key","description":"新建立的 API Key"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At","description":"API Key 的過期時間, 若為 None 則表示不過期"},"permission_ids":{"items":{"type":"integer"},"type":"array","title":"Permission Ids","description":"API Key 的權限 ID 列表 (可選)"}},"type":"object","required":["id","description","api_key"],"title":"ApiKeyCreateResponse"},"ApiKeyResponse":{"properties":{"id":{"type":"string","title":"Id","description":"API Key 的唯一識別 ID"},"description":{"type":"string","title":"Description","description":"API Key 的用途描述"},"prefix":{"type":"string","title":"Prefix","description":"API Key 的前綴, 例如 twf_live_12345678"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At","description":"API Key 的過期時間, 若為 None 則表示不過期"},"permission_ids":{"items":{"type":"integer"},"type":"array","title":"Permission Ids","description":"API Key 的權限 ID 列表 (可選)"}},"type":"object","required":["id","description","prefix"],"title":"ApiKeyResponse"},"CurrentUser":{"properties":{"internal_user_id":{"type":"string","title":"Internal User Id"},"internal_account_status":{"type":"string","title":"Internal Account Status"},"discord_id":{"type":"string","title":"Discord Id"},"username":{"type":"string","title":"Username"},"avatar":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Avatar"},"mfa_enabled":{"type":"boolean","title":"Mfa Enabled"},"locale":{"type":"string","title":"Locale"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"verified":{"type":"boolean","title":"Verified"},"roles":{"items":{"type":"string"},"type":"array","title":"Roles","description":"使用者擁有的身份組名稱"},"permissions":{"items":{"type":"string"},"type":"array","title":"Permissions","description":"使用者擁有的所有權限節點"},"limits":{"$ref":"#/components/schemas/UserLimits","description":"使用者擁有的資源上限"}},"type":"object","required":["internal_user_id","internal_account_status","discord_id","username","avatar","mfa_enabled","locale","email","verified"],"title":"CurrentUser"},"ErrorResponse":{"properties":{"detail":{"anyOf":[{"type":"string"},{"additionalProperties":true,"type":"object"}],"title":"Detail","description":"錯誤詳細資訊"}},"type":"object","required":["detail"],"title":"ErrorResponse"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HealthCheckResponseModel":{"properties":{"api":{"type":"string","title":"Api"},"version":{"type":"string","title":"Version"},"database":{"type":"string","title":"Database"},"redis":{"type":"string","title":"Redis"}},"type":"object","required":["api","version","database","redis"],"title":"HealthCheckResponseModel"},"NodeCreateRequest":{"properties":{"name":{"type":"string","maxLength":50,"minLength":2,"title":"Name"},"description":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Description"},"host":{"type":"string","maxLength":100,"title":"Host"},"port_start":{"type":"integer","maximum":65535.0,"minimum":1.0,"title":"Port Start"},"port_end":{"type":"integer","maximum":65535.0,"minimum":1.0,"title":"Port End"},"is_public":{"type":"boolean","title":"Is Public","default":true}},"type":"object","required":["name","host","port_start","port_end"],"title":"NodeCreateRequest"},"NodeResponse":{"properties":{"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"host":{"type":"string","title":"Host"},"port_start":{"type":"integer","title":"Port Start"},"port_end":{"type":"integer","title":"Port End"},"status":{"$ref":"#/components/schemas/NodeStatus"},"is_public":{"type":"boolean","title":"Is Public"},"owner_id":{"type":"string","title":"Owner Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","name","description","host","port_start","port_end","status","is_public","owner_id","created_at","updated_at"],"title":"NodeResponse"},"NodeStatus":{"type":"string","enum":["active","draft","reviewing","maintenance","disabled"],"title":"NodeStatus"},"NodeUpdateRequest":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":50,"minLength":2},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Description"},"host":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Host"},"port_start":{"anyOf":[{"type":"integer","maximum":65535.0,"minimum":1.0},{"type":"null"}],"title":"Port Start"},"port_end":{"anyOf":[{"type":"integer","maximum":65535.0,"minimum":1.0},{"type":"null"}],"title":"Port End"},"status":{"anyOf":[{"$ref":"#/components/schemas/NodeStatus"},{"type":"null"}]},"is_public":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Public"}},"type":"object","required":["status","is_public"],"title":"NodeUpdateRequest"},"PermissionResponse":{"properties":{"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","name","description","created_at","updated_at"],"title":"PermissionResponse"},"RoleCreateRequest":{"properties":{"name":{"type":"string","maxLength":50,"minLength":1,"title":"Name","description":"身份組名稱"},"description":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Description","description":"身份組描述"},"max_tunnels":{"type":"integer","minimum":0.0,"title":"Max Tunnels","description":"最大允許的隧道數量"},"max_bandwidth":{"type":"integer","minimum":0.0,"title":"Max Bandwidth","description":"最大允許的頻寬 (Mbps)"},"permissions":{"items":{"type":"integer"},"type":"array","title":"Permissions","description":"身份組擁有的權限節點 ID 列表, 傳入空陣列表示身份組不會擁有任何權限節點"}},"type":"object","required":["name","max_tunnels","max_bandwidth"],"title":"RoleCreateRequest"},"RoleResponse":{"properties":{"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"max_tunnels":{"type":"integer","title":"Max Tunnels"},"max_bandwidth":{"type":"integer","title":"Max Bandwidth"},"permissions":{"items":{"$ref":"#/components/schemas/PermissionResponse"},"type":"array","title":"Permissions","default":[]},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","name","description","max_tunnels","max_bandwidth","created_at","updated_at"],"title":"RoleResponse"},"RoleUpdateRequest":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":50,"minLength":1},{"type":"null"}],"title":"Name","description":"身份組名稱"},"description":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Description","description":"身份組描述"},"max_tunnels":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Max Tunnels","description":"最大允許的隧道數量"},"max_bandwidth":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Max Bandwidth","description":"最大允許的頻寬 (Mbps)"},"permissions":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Permissions","description":"身份組擁有的權限節點 ID 列表, 傳入空陣列表示身份組不會擁有任何權限節點"}},"type":"object","title":"RoleUpdateRequest"},"TunnelCreateRequest":{"properties":{"name":{"type":"string","maxLength":50,"minLength":1,"title":"Name"},"description":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Description"},"node_id":{"type":"integer","maximum":2147483647.0,"minimum":1.0,"title":"Node Id"},"protocol":{"$ref":"#/components/schemas/TunnelProtocol","description":"The protocol for the tunnel (TCP or UDP)"},"local_ip":{"type":"string","maxLength":50,"title":"Local Ip","default":"127.0.0.1"},"local_port":{"type":"integer","maximum":65535.0,"minimum":1.0,"title":"Local Port"},"remote_port":{"anyOf":[{"type":"integer","maximum":65535.0,"minimum":1.0},{"type":"null"}],"title":"Remote Port"},"is_kcp_enabled":{"type":"boolean","title":"Is Kcp Enabled","default":true},"is_proxy_protocol_v2_enabled":{"type":"boolean","title":"Is Proxy Protocol V2 Enabled","default":false}},"type":"object","required":["name","node_id","protocol","local_port"],"title":"TunnelCreateRequest"},"TunnelCreateResponse":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"node_id":{"type":"integer","title":"Node Id"},"protocol":{"$ref":"#/components/schemas/TunnelProtocol"},"local_ip":{"type":"string","title":"Local Ip"},"local_port":{"type":"integer","title":"Local Port"},"remote_port":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Remote Port"},"is_kcp_enabled":{"type":"boolean","title":"Is Kcp Enabled"},"is_proxy_protocol_v2_enabled":{"type":"boolean","title":"Is Proxy Protocol V2 Enabled"},"is_enabled":{"type":"boolean","title":"Is Enabled"},"status":{"$ref":"#/components/schemas/TunnelStatus"},"token_prefix":{"type":"string","title":"Token Prefix"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"agent_token":{"type":"string","title":"Agent Token","description":"用於驗證 Agent 的身份, 由後端生成, 僅顯示一次"}},"type":"object","required":["id","name","description","node_id","protocol","local_ip","local_port","remote_port","is_kcp_enabled","is_proxy_protocol_v2_enabled","is_enabled","status","token_prefix","created_at","updated_at","agent_token"],"title":"TunnelCreateResponse"},"TunnelProtocol":{"type":"string","enum":["tcp","udp","http","https","tcpmux","stcp","sudp"],"title":"TunnelProtocol"},"TunnelResponse":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"node_id":{"type":"integer","title":"Node Id"},"protocol":{"$ref":"#/components/schemas/TunnelProtocol"},"local_ip":{"type":"string","title":"Local Ip"},"local_port":{"type":"integer","title":"Local Port"},"remote_port":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Remote Port"},"is_kcp_enabled":{"type":"boolean","title":"Is Kcp Enabled"},"is_proxy_protocol_v2_enabled":{"type":"boolean","title":"Is Proxy Protocol V2 Enabled"},"is_enabled":{"type":"boolean","title":"Is Enabled"},"status":{"$ref":"#/components/schemas/TunnelStatus"},"token_prefix":{"type":"string","title":"Token Prefix"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","name","description","node_id","protocol","local_ip","local_port","remote_port","is_kcp_enabled","is_proxy_protocol_v2_enabled","is_enabled","status","token_prefix","created_at","updated_at"],"title":"TunnelResponse"},"TunnelStatus":{"type":"string","enum":["active","disabled"],"title":"TunnelStatus"},"TunnelUpdateRequest":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":50,"minLength":1},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Description"},"node_id":{"anyOf":[{"type":"integer","maximum":2147483647.0,"minimum":1.0},{"type":"null"}],"title":"Node Id"},"protocol":{"anyOf":[{"$ref":"#/components/schemas/TunnelProtocol"},{"type":"null"}],"description":"The protocol for the tunnel (TCP or UDP)"},"local_ip":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}],"title":"Local Ip"},"local_port":{"anyOf":[{"type":"integer","maximum":65535.0,"minimum":1.0},{"type":"null"}],"title":"Local Port"},"remote_port":{"anyOf":[{"type":"integer","maximum":65535.0,"minimum":1.0},{"type":"null"}],"title":"Remote Port"},"is_kcp_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Kcp Enabled"},"is_proxy_protocol_v2_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Proxy Protocol V2 Enabled"},"is_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Enabled"}},"type":"object","title":"TunnelUpdateRequest"},"UserLimits":{"properties":{"max_tunnels":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Tunnels","description":"最大隧道數量限制, 0 代表無限制","default":0},"max_bandwidth":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Bandwidth","description":"最大頻寬限制, 0 代表無限制","default":0}},"type":"object","title":"UserLimits"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}