5.5 KiB
Core Private Node Routes
These routes are consumed only by the node agent and require the x-node-auth-key header.
Transport
The node uses two transports to communicate with Core:
- HTTP — registration only (
POST /node/register). - gRPC — all other node-to-core calls: heartbeat, usage reporting, config sync, and stats. Core listens on
GRPC_PORT(default3002). The node connects viaCORE_GRPC_URL. SetCORE_INSECURE=trueon the node to use plaintext instead of TLS.
The HTTP routes for heartbeat, usage, config, and error remain available as a fallback but the node agent uses gRPC by default.
Authentication
POST /node/registeris the only public route in this group.- All other HTTP routes require the
x-node-auth-keyheader. - gRPC calls pass the auth key as the
x-node-auth-keymetadata header (or in theauthKeyrequest field as fallback). - The auth key is issued by Core during registration and persisted on the node side.
Route table
| Method | Route | Input | Output / Notes |
|---|---|---|---|
POST |
/node/register |
RegisterNodeDto |
Returns { authKey, nodeId } |
POST |
/node/heartbeat |
NodeHeartbeatDto |
Returns { ok: true, needSync } |
POST |
/node/usage |
NodeUsageDto |
Returns { ok: true } |
POST |
/node/outbound-usage |
NodeOutboundUsageDto |
Returns { ok: true } |
POST |
/node/session-events |
SessionEventsDto |
Returns { ok: true } |
GET |
/node/config/latest |
none | Returns NodeConfig |
POST |
/node/config/applied |
NodeConfigAppliedDto |
Returns { ok: true } |
POST |
/node/error |
NodeErrorDto |
Returns { ok: true } |
Request payloads
RegisterNodeDto
code: stringname: stringhost: stringip: stringregion: string
NodeHeartbeatDto
ip?: stringrevision?: number
The node sends its current revision in heartbeats. Core uses it to decide whether a sync is needed.
NodeUsageDto
entries: UsageEntryDto[]
UsageEntryDto fields:
userId: numbersubscriptionId?: number | nullnodeProtocolId: numberbytesUp: numberbytesDown: numberrecordedAt: string
NodeOutboundUsageDto
items: OutboundUsageItem[]
OutboundUsageItem fields:
tag: stringbytesUp: numberbytesDown: number
SessionEventsDto
events: SessionEventEntryDto[]
SessionEventEntryDto fields:
userId: numberprotocol: VpnProtocoleventType: SessionEventTypeoccurredAt: stringipAddress?: string
NodeConfigAppliedDto
revision: number
NodeErrorDto
message: stringcode?: stringdetails?: Record<string, unknown>
NodeConfig
The config returned by GET /node/config/latest has this structure:
{
revision: number
clientMap: Record<string, { userId: number; subscriptionId: number | null }>
mtprotoClientMap: Record<string, { userId: number; subscriptionId: number | null }>
services: {
xray?: XrayServiceConfig
mtproto?: MtProtoServiceConfig
}
}
Important notes:
clientMapmaps subscription link UUIDs to the user and subscription — used for xray traffic attribution.mtprotoClientMapmaps MTProto link UUIDs to the user and subscription — used for telemt traffic attribution.services.xraycontains the Xray inbounds, routing, and outbounds for the node.services.mtprotocontains MTProto inbounds fortelemt.- The node stores the current revision and client maps locally after a successful apply.
Route semantics
POST /node/heartbeatupdateslastSeenAtand can request a sync when the node revision is behind.POST /node/usagestores per-minute usage rows and increments subscription traffic counters.POST /node/outbound-usageincrementsnode_outbounds.traffic_bytes_up/down.POST /node/session-eventsstores online/offline events insession_events.POST /node/config/appliedmarks the node sync status assynced.POST /node/errormarks the node aserrorand the sync status asfailed.
gRPC interface (NodeService)
Core exposes a gRPC service that the node agent uses for all real-time communication. The service name is nodeservice.NodeService and is defined in proto/node-service.proto.
Authentication: pass x-node-auth-key as gRPC metadata (or in the authKey field of the request as fallback).
| Method | Request fields | Response fields | Notes |
|---|---|---|---|
Heartbeat |
authKey, revision?, ip? |
ok, needSync |
Equivalent to POST /node/heartbeat |
ReportUsage |
authKey, entries[] |
ok |
Equivalent to POST /node/usage |
ReportOutboundUsage |
authKey, items[] |
ok |
Equivalent to POST /node/outbound-usage |
GetLatestConfig |
authKey |
revision, clientMapJson, mtprotoClientMapJson, servicesJson |
Config fields are JSON-encoded strings |
ConfirmConfigApplied |
authKey, revision |
ok |
Equivalent to POST /node/config/applied |
ReportNodeStats |
authKey, system metrics fields |
ok |
Reports CPU/RAM/disk/network/xray/mtproto snapshot; stored in Redis; drives GET /admin/nodes/:id/runtime-status and stats history |
ReportNodeStats fields: uptimeSeconds, cpuPercent, cpuCores, ramUsed, ramTotal, diskUsed, diskTotal, netRxPerSec, netTxPerSec, netRxTotal, netTxTotal, xrayRunning, xrayUptimeSeconds?, mtprotoJson.
The node sends ReportNodeStats on every heartbeat cycle. GET /admin/nodes/:id/runtime-status returns the latest stored snapshot without polling the node; ?fromNode=true forces a live HTTP fetch instead.