数据模型
node-protocol.openapi.json 中全部可复用的 schema、安全方案与组件定义。
自动生成的共享组件定义。
{
"parameters": {},
"schemas": {
"NodeConfig": {
"properties": {
"certificates": {
"items": {},
"type": "array"
},
"hash": {
"description": "`sha256:<lowercase hex>`; also the ETag",
"example": "sha256:…",
"type": "string"
},
"inbounds": {
"items": {
"$ref": "#/components/schemas/NodeConfigInbound"
},
"type": "array"
},
"revision": {
"minimum": 0,
"type": "integer"
},
"runtime": {
"$ref": "#/components/schemas/NodeRuntime"
}
},
"required": [
"revision",
"hash",
"runtime",
"inbounds",
"certificates"
],
"type": "object"
},
"NodeConfigInbound": {
"additionalProperties": {},
"description": "Protocol parameters with secrets in place (REALITY private key, SS server key …)",
"properties": {
"id": {
"format": "uuid",
"type": "string"
},
"port": {
"maximum": 65535,
"minimum": 1,
"type": "integer"
},
"protocol": {
"enum": [
"vmess",
"vless",
"trojan",
"shadowsocks",
"hysteria2",
"tuic",
"anytls",
"naive",
"socks",
"http"
],
"type": "string"
},
"security": {
"additionalProperties": {},
"type": "object"
},
"settings": {
"additionalProperties": {},
"type": "object"
},
"transport": {
"additionalProperties": {},
"type": "object"
},
"transport_layer": {
"enum": [
"tcp",
"udp",
"tcp_udp"
],
"type": "string"
}
},
"required": [
"id",
"protocol",
"port",
"transport_layer"
],
"type": "object"
},
"NodeCredentials": {
"description": "Only during a rotation grace window while the node still uses the previous token",
"properties": {
"previous_expires_at": {
"description": "When the token in use stops working",
"example": "2026-10-22T08:00:00.000Z",
"format": "date-time",
"type": "string"
},
"token": {
"description": "The rotated agent token: persist it and use it from now on",
"type": "string"
}
},
"required": [
"token",
"previous_expires_at"
],
"type": [
"object",
"null"
]
},
"NodeEnrollRequest": {
"properties": {
"enrollment_id": {
"description": "Generated by the node and kept across retries: the same token and id within 10 minutes get the same response",
"format": "uuid",
"type": "string"
},
"enrollment_token": {
"example": "enr_…",
"maxLength": 256,
"minLength": 1,
"type": "string"
},
"program": {
"properties": {
"capabilities": {
"properties": {
"features": {
"items": {
"maxLength": 64,
"minLength": 1,
"type": "string"
},
"maxItems": 64,
"type": "array"
},
"protocols": {
"items": {
"maxLength": 32,
"minLength": 1,
"type": "string"
},
"maxItems": 64,
"type": "array"
}
},
"required": [
"protocols",
"features"
],
"type": "object"
},
"commit": {
"maxLength": 64,
"type": [
"string",
"null"
]
},
"name": {
"maxLength": 64,
"minLength": 1,
"type": "string"
},
"os_arch": {
"maxLength": 64,
"type": [
"string",
"null"
]
},
"version": {
"maxLength": 64,
"minLength": 1,
"type": "string"
}
},
"required": [
"name",
"version",
"capabilities"
],
"type": "object"
}
},
"required": [
"enrollment_token",
"enrollment_id",
"program"
],
"type": "object"
},
"NodeEnrollResponse": {
"properties": {
"agent_token": {
"description": "srv_<prefix>_<secret>; persist it before anything else",
"type": "string"
},
"intervals": {
"$ref": "#/components/schemas/NodeIntervals"
},
"next_batch_seq": {
"minimum": 1,
"type": "integer"
},
"server_id": {
"format": "uuid",
"type": "string"
}
},
"required": [
"server_id",
"agent_token",
"intervals",
"next_batch_seq"
],
"type": "object"
},
"NodeHeartbeatRequest": {
"properties": {
"applied": {
"description": "The configuration the node runs; null before the first one is applied",
"properties": {
"hash": {
"maxLength": 128,
"minLength": 1,
"type": "string"
},
"results": {
"items": {
"properties": {
"inbound_id": {
"format": "uuid",
"type": "string"
},
"message": {
"maxLength": 1024,
"type": [
"string",
"null"
]
},
"status": {
"enum": [
"ok",
"bind_failed",
"unsupported",
"error"
],
"type": "string"
}
},
"required": [
"inbound_id",
"status"
],
"type": "object"
},
"maxItems": 1024,
"type": "array"
},
"revision": {
"minimum": 0,
"type": "integer"
}
},
"required": [
"revision",
"hash",
"results"
],
"type": [
"object",
"null"
]
},
"capabilities": {
"properties": {
"features": {
"items": {
"maxLength": 64,
"minLength": 1,
"type": "string"
},
"maxItems": 64,
"type": "array"
},
"protocols": {
"items": {
"maxLength": 32,
"minLength": 1,
"type": "string"
},
"maxItems": 64,
"type": "array"
}
},
"required": [
"protocols",
"features"
],
"type": "object"
},
"last_batch_seq": {
"minimum": 0,
"type": "integer"
},
"network": {
"properties": {
"ipv4": {
"format": "ip",
"type": [
"string",
"null"
]
},
"ipv4_ok": {
"type": "boolean"
},
"ipv6": {
"format": "ip",
"type": [
"string",
"null"
]
},
"ipv6_ok": {
"type": "boolean"
}
},
"required": [
"ipv4_ok",
"ipv6_ok"
],
"type": "object"
},
"program": {
"properties": {
"name": {
"maxLength": 64,
"minLength": 1,
"type": "string"
},
"started_at": {
"example": "2026-10-22T08:00:00Z",
"format": "date-time",
"type": "string"
},
"version": {
"maxLength": 64,
"minLength": 1,
"type": "string"
}
},
"required": [
"name",
"version",
"started_at"
],
"type": "object"
},
"sent_at": {
"description": "Node clock; more than 5 minutes off → clock_skew notice",
"example": "2026-10-22T08:00:00Z",
"format": "date-time",
"type": "string"
},
"system": {
"properties": {
"cpu": {
"maximum": 1,
"minimum": 0,
"type": "number"
},
"disk": {
"maximum": 1,
"minimum": 0,
"type": "number"
},
"load1": {
"maximum": 1000000,
"minimum": 0,
"type": "number"
},
"load15": {
"maximum": 1000000,
"minimum": 0,
"type": "number"
},
"load5": {
"maximum": 1000000,
"minimum": 0,
"type": "number"
},
"mem": {
"maximum": 1,
"minimum": 0,
"type": "number"
},
"online_users": {
"maximum": 1000000000,
"minimum": 0,
"type": "integer"
},
"tcp_conns": {
"maximum": 1000000000,
"minimum": 0,
"type": "integer"
},
"udp_conns": {
"maximum": 1000000000,
"minimum": 0,
"type": "integer"
},
"uptime_s": {
"minimum": 0,
"type": "integer"
}
},
"required": [
"cpu",
"mem",
"disk",
"load1",
"load5",
"load15",
"uptime_s",
"tcp_conns",
"udp_conns",
"online_users"
],
"type": "object"
},
"traffic": {
"properties": {
"interval_s": {
"maximum": 86400,
"minimum": 1,
"type": "integer"
},
"max_rx_bps": {
"description": "Highest 1-second receive speed in the interval, bytes per second",
"example": "31457280",
"pattern": "^(0|[1-9][0-9]{0,13})$",
"type": "string"
},
"max_tx_bps": {
"example": "31457280",
"pattern": "^(0|[1-9][0-9]{0,13})$",
"type": "string"
},
"rx_bytes": {
"example": "31457280",
"pattern": "^(0|[1-9][0-9]{0,13})$",
"type": "string"
},
"tx_bytes": {
"example": "31457280",
"pattern": "^(0|[1-9][0-9]{0,13})$",
"type": "string"
}
},
"required": [
"interval_s",
"rx_bytes",
"tx_bytes",
"max_rx_bps",
"max_tx_bps"
],
"type": "object"
}
},
"required": [
"sent_at",
"program",
"applied",
"system",
"traffic",
"network",
"last_batch_seq"
],
"type": "object"
},
"NodeHeartbeatResponse": {
"properties": {
"credentials": {
"$ref": "#/components/schemas/NodeCredentials"
},
"desired_revision": {
"minimum": 0,
"type": "integer"
},
"intervals": {
"$ref": "#/components/schemas/NodeIntervals"
},
"next_batch_seq": {
"description": "Highest recorded batch_seq + 1 (resume after state loss)",
"minimum": 1,
"type": "integer"
},
"notices": {
"items": {
"$ref": "#/components/schemas/NodeNotice"
},
"type": "array"
},
"server_time": {
"example": "2026-10-22T08:00:00.000Z",
"format": "date-time",
"type": "string"
}
},
"required": [
"server_time",
"desired_revision",
"next_batch_seq",
"intervals",
"notices",
"credentials"
],
"type": "object"
},
"NodeIntervals": {
"description": "Seconds between calls of each kind",
"properties": {
"config_poll": {
"type": "integer"
},
"heartbeat": {
"type": "integer"
},
"online_push": {
"type": "integer"
},
"usage_push": {
"type": "integer"
},
"users_poll": {
"type": "integer"
}
},
"required": [
"config_poll",
"users_poll",
"usage_push",
"online_push",
"heartbeat"
],
"type": "object"
},
"NodeNotice": {
"properties": {
"code": {
"description": "snake_case; ignore codes you do not know",
"example": "clock_skew",
"type": "string"
},
"data": {
"additionalProperties": {},
"type": "object"
},
"message": {
"type": "string"
}
},
"required": [
"code"
],
"type": "object"
},
"NodeOnlineRequest": {
"properties": {
"items": {
"items": {
"properties": {
"ips": {
"items": {
"anyOf": [
{
"format": "ip",
"type": "string"
},
{
"format": "ip",
"type": "string"
}
]
},
"type": "array"
},
"user_id": {
"minimum": 1,
"type": "integer"
}
},
"required": [
"user_id",
"ips"
],
"type": "object"
},
"type": "array"
},
"observed_at": {
"example": "2026-10-22T08:00:00Z",
"format": "date-time",
"type": "string"
}
},
"required": [
"observed_at",
"items"
],
"type": "object"
},
"NodeOnlineResponse": {
"properties": {
"accepted": {
"minimum": 0,
"type": "integer"
},
"notices": {
"items": {
"$ref": "#/components/schemas/NodeNotice"
},
"type": "array"
},
"over_limit_users": {
"items": {
"type": "integer"
},
"type": "array"
},
"rejected": {
"items": {
"properties": {
"index": {
"minimum": 0,
"type": "integer"
},
"reason": {
"enum": [
"too_many_ips",
"unknown_user"
],
"type": "string"
}
},
"required": [
"index",
"reason"
],
"type": "object"
},
"type": "array"
}
},
"required": [
"accepted",
"over_limit_users",
"rejected"
],
"type": "object"
},
"NodeRuntime": {
"additionalProperties": {},
"properties": {
"block_rules": {
"items": {},
"type": "array"
},
"dns": {
"items": {},
"type": "array"
},
"ip_strategy": {
"type": "string"
},
"outbounds": {
"items": {},
"type": "array"
},
"routing_rules": {
"items": {},
"type": "array"
}
},
"required": [
"ip_strategy",
"dns",
"outbounds",
"routing_rules",
"block_rules"
],
"type": "object"
},
"NodeUsageRequest": {
"properties": {
"batch_seq": {
"maximum": 9007199254740990,
"minimum": 1,
"type": "integer"
},
"items": {
"items": {
"properties": {
"down": {
"pattern": "^-?[0-9]{1,40}$",
"type": "string"
},
"inbound_id": {
"format": "uuid",
"type": "string"
},
"up": {
"pattern": "^-?[0-9]{1,40}$",
"type": "string"
},
"user_id": {
"minimum": 1,
"type": "integer"
}
},
"required": [
"inbound_id",
"user_id",
"up",
"down"
],
"type": "object"
},
"type": "array"
},
"window": {
"properties": {
"end": {
"example": "2026-10-22T08:00:00Z",
"format": "date-time",
"type": "string"
},
"start": {
"example": "2026-10-22T08:00:00Z",
"format": "date-time",
"type": "string"
}
},
"required": [
"start",
"end"
],
"type": "object"
}
},
"required": [
"batch_seq",
"window",
"items"
],
"type": "object"
},
"NodeUsageResponse": {
"properties": {
"accepted": {
"minimum": 0,
"type": "integer"
},
"next_batch_seq": {
"minimum": 1,
"type": "integer"
},
"rejected": {
"items": {
"properties": {
"index": {
"minimum": 0,
"type": "integer"
},
"reason": {
"enum": [
"unknown_user",
"inbound_not_on_server",
"negative_value",
"value_too_large",
"window_invalid"
],
"type": "string"
}
},
"required": [
"index",
"reason"
],
"type": "object"
},
"type": "array"
},
"result": {
"enum": [
"accepted",
"duplicate",
"stale"
],
"type": "string"
}
},
"required": [
"result",
"accepted",
"rejected",
"next_batch_seq"
],
"type": "object"
},
"NodeUser": {
"properties": {
"blocked_ips": {
"description": "CIDRs (IPv4 /32, IPv6 /64): drop existing connections, refuse new ones",
"items": {
"type": "string"
},
"type": "array"
},
"device_limit": {
"description": "null: unlimited",
"type": [
"integer",
"null"
]
},
"id": {
"description": "The subscription node_user_id; usage and online reports use it",
"type": "integer"
},
"password": {
"type": [
"string",
"null"
]
},
"speed_limit_mbps": {
"description": "null: unlimited",
"type": [
"integer",
"null"
]
},
"ss2022_keys": {
"additionalProperties": {
"type": "string"
},
"description": "Shadowsocks 2022 user PSK (base64) by method",
"type": [
"object",
"null"
]
},
"uuid": {
"description": "uuid-based protocols; user name of socks / http / naive",
"format": "uuid",
"type": [
"string",
"null"
]
}
},
"required": [
"id",
"uuid",
"password",
"ss2022_keys",
"speed_limit_mbps",
"device_limit",
"blocked_ips"
],
"type": "object"
},
"NodeUsers": {
"description": "An empty `users` list means serve nobody (not the same as 304)",
"properties": {
"access_version": {
"minimum": 0,
"type": "integer"
},
"added": {
"items": {
"$ref": "#/components/schemas/NodeUser"
},
"type": "array"
},
"changed": {
"items": {
"$ref": "#/components/schemas/NodeUser"
},
"type": "array"
},
"full": {
"description": "false: apply added/removed/changed to since_version; replace inbounds completely",
"type": "boolean"
},
"inbounds": {
"items": {
"properties": {
"inbound_id": {
"format": "uuid",
"type": "string"
},
"user_ids": {
"items": {
"type": "integer"
},
"type": "array"
}
},
"required": [
"inbound_id",
"user_ids"
],
"type": "object"
},
"type": "array"
},
"removed": {
"items": {
"type": "integer"
},
"type": "array"
},
"since_version": {
"minimum": 0,
"type": "integer"
},
"users": {
"items": {
"$ref": "#/components/schemas/NodeUser"
},
"type": "array"
}
},
"required": [
"access_version",
"users",
"inbounds",
"full"
],
"type": "object"
},
"Problem": {
"description": "RFC 9457 problem details. Nodes branch on `code`, never on `title` or `detail`.",
"properties": {
"code": {
"description": "Stable `<module>.<reason>` code, see `x-error-codes`",
"type": "string"
},
"detail": {
"type": "string"
},
"errors": {
"description": "Per-field validation errors (422 node.payload_invalid)",
"items": {
"properties": {
"code": {
"type": "string"
},
"message": {
"type": "string"
},
"path": {
"type": "string"
}
},
"required": [
"path",
"code"
],
"type": "object"
},
"type": "array"
},
"request_id": {
"type": "string"
},
"status": {
"type": "integer"
},
"title": {
"type": "string"
},
"type": {
"description": "`urn:error:<code>`",
"type": "string"
}
},
"required": [
"type",
"title",
"status",
"code",
"request_id"
],
"type": "object"
}
},
"securitySchemes": {
"AgentToken": {
"description": "Agent token `srv_<prefix>_<secret>` returned by POST /enroll (or delivered by heartbeat)",
"scheme": "bearer",
"type": "http"
}
}
}