PPanel Edge

数据模型

node-protocol.openapi.json 中全部可复用的 schema、安全方案与组件定义。

自动生成的共享组件定义。

OpenAPI

{
  "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"
    }
  }
}