diff --git a/database/model/model.go b/database/model/model.go
index 99566d9d..4636798d 100644
--- a/database/model/model.go
+++ b/database/model/model.go
@@ -55,6 +55,7 @@ type Inbound struct {
ExpiryTime int64 `json:"expiryTime" form:"expiryTime"` // Expiration timestamp
TrafficReset string `json:"trafficReset" form:"trafficReset" gorm:"default:never;index:idx_enable_traffic_reset,priority:2"` // Traffic reset schedule
LastTrafficResetTime int64 `json:"lastTrafficResetTime" form:"lastTrafficResetTime" gorm:"default:0"` // Last traffic reset timestamp
+ TrafficMultiplier float64 `json:"trafficMultiplier" form:"trafficMultiplier" gorm:"default:1"` // Multiplier for inbound/client traffic accounting
ClientStats []xray.ClientTraffic `gorm:"foreignKey:InboundId;references:Id" json:"clientStats" form:"clientStats"` // Client traffic statistics
// Xray configuration fields
diff --git a/frontend/public/openapi.json b/frontend/public/openapi.json
index fedcded9..ed7101f9 100644
--- a/frontend/public/openapi.json
+++ b/frontend/public/openapi.json
@@ -312,6 +312,7 @@
"remark": "VLESS-443",
"enable": true,
"expiryTime": 0,
+ "trafficMultiplier": 1,
"listen": "",
"port": 443,
"protocol": "vless",
@@ -500,6 +501,7 @@
"protocol": "vless",
"expiryTime": 0,
"total": 0,
+ "trafficMultiplier": 1,
"settings": {
"clients": [
{
diff --git a/frontend/src/models/dbinbound.ts b/frontend/src/models/dbinbound.ts
index 391838c2..e0e6008f 100644
--- a/frontend/src/models/dbinbound.ts
+++ b/frontend/src/models/dbinbound.ts
@@ -31,6 +31,7 @@ export type DBInboundInit = Partial<{
expiryTime: number;
trafficReset: string;
lastTrafficResetTime: number;
+ trafficMultiplier: number;
listen: string;
port: number;
protocol: string;
@@ -73,6 +74,7 @@ export class DBInbound {
expiryTime: number;
trafficReset: string;
lastTrafficResetTime: number;
+ trafficMultiplier: number;
listen: string;
port: number;
@@ -99,6 +101,7 @@ export class DBInbound {
this.expiryTime = 0;
this.trafficReset = "never";
this.lastTrafficResetTime = 0;
+ this.trafficMultiplier = 1;
this.listen = "";
this.port = 0;
diff --git a/frontend/src/pages/api-docs/endpoints.ts b/frontend/src/pages/api-docs/endpoints.ts
index 6fc4e5a5..628dcd23 100644
--- a/frontend/src/pages/api-docs/endpoints.ts
+++ b/frontend/src/pages/api-docs/endpoints.ts
@@ -108,7 +108,7 @@ export const sections: readonly Section[] = [
path: '/panel/api/inbounds/list',
summary: 'List every inbound owned by the authenticated user, including each inbound’s clientStats traffic counters. settings, streamSettings, and sniffing are returned as nested JSON objects (no escaped strings); legacy callers that send them back as JSON-encoded strings are still accepted on write.',
response:
- '{\n "success": true,\n "obj": [\n {\n "id": 1,\n "userId": 1,\n "up": 0,\n "down": 0,\n "total": 0,\n "remark": "VLESS-443",\n "enable": true,\n "expiryTime": 0,\n "listen": "",\n "port": 443,\n "protocol": "vless",\n "settings": {\n "clients": [],\n "decryption": "none"\n },\n "streamSettings": {\n "network": "tcp",\n "security": "reality",\n "realitySettings": { "show": false, "dest": "..." }\n },\n "tag": "inbound-443",\n "sniffing": {\n "enabled": true,\n "destOverride": ["http", "tls"]\n },\n "clientStats": []\n }\n ]\n}',
+ '{\n "success": true,\n "obj": [\n {\n "id": 1,\n "userId": 1,\n "up": 0,\n "down": 0,\n "total": 0,\n "remark": "VLESS-443",\n "enable": true,\n "expiryTime": 0,\n "trafficMultiplier": 1,\n "listen": "",\n "port": 443,\n "protocol": "vless",\n "settings": {\n "clients": [],\n "decryption": "none"\n },\n "streamSettings": {\n "network": "tcp",\n "security": "reality",\n "realitySettings": { "show": false, "dest": "..." }\n },\n "tag": "inbound-443",\n "sniffing": {\n "enabled": true,\n "destOverride": ["http", "tls"]\n },\n "clientStats": []\n }\n ]\n}',
},
{
method: 'GET',
@@ -137,7 +137,7 @@ export const sections: readonly Section[] = [
path: '/panel/api/inbounds/add',
summary: 'Create a new inbound. Send the full inbound payload (protocol, port, settings, streamSettings, sniffing, remark, expiryTime, total, enable). settings, streamSettings, and sniffing may be sent as nested JSON objects (preferred) or as JSON-encoded strings (legacy).',
body:
- '{\n "enable": true,\n "remark": "VLESS-443",\n "listen": "",\n "port": 443,\n "protocol": "vless",\n "expiryTime": 0,\n "total": 0,\n "settings": {\n "clients": [{ "id": "...", "email": "user1" }],\n "decryption": "none",\n "fallbacks": []\n },\n "streamSettings": {\n "network": "tcp",\n "security": "reality",\n "realitySettings": { "show": false, "dest": "..." }\n },\n "sniffing": {\n "enabled": true,\n "destOverride": ["http", "tls"]\n }\n}',
+ '{\n "enable": true,\n "remark": "VLESS-443",\n "listen": "",\n "port": 443,\n "protocol": "vless",\n "expiryTime": 0,\n "total": 0,\n "trafficMultiplier": 1,\n "settings": {\n "clients": [{ "id": "...", "email": "user1" }],\n "decryption": "none",\n "fallbacks": []\n },\n "streamSettings": {\n "network": "tcp",\n "security": "reality",\n "realitySettings": { "show": false, "dest": "..." }\n },\n "sniffing": {\n "enabled": true,\n "destOverride": ["http", "tls"]\n }\n}',
errorResponse:
'{\n "success": false,\n "msg": "Port 443 is already in use"\n}',
},
diff --git a/frontend/src/pages/inbounds/InboundFormModal.tsx b/frontend/src/pages/inbounds/InboundFormModal.tsx
index dd1c43c4..8ee46e70 100644
--- a/frontend/src/pages/inbounds/InboundFormModal.tsx
+++ b/frontend/src/pages/inbounds/InboundFormModal.tsx
@@ -940,6 +940,7 @@ export default function InboundFormModal({
expiryTime: form.expiryTime,
trafficReset: form.trafficReset,
lastTrafficResetTime: form.lastTrafficResetTime || 0,
+ trafficMultiplier: form.trafficMultiplier || 1,
listen: ib.listen,
port: ib.port,
protocol: ib.protocol,
@@ -1052,6 +1053,18 @@ export default function InboundFormModal({
}}
/>
+
+ {
+ const next = Number(v);
+ form.trafficMultiplier = next > 0 ? next : 1;
+ refresh();
+ }}
+ />
+