Skip to content

portal.v1

The API the Portal calls. Source: platform/nexus/proto/portal/v1/. Every service is served by nexus over Connect; all but ReleasePublisherService authenticate a user with a Zitadel access token.

portalAuth (the JWT interceptor) only establishes who is calling. Every handler decides on its own whether the caller may proceed; the Gate column below names that check. See Nexus → Authorization and Authz → Model for what each gate means.

File Service Mounted
enrollment.proto PortalSessionService yes
org.proto PortalOrgService yes
gateway.proto PortalGatewayService yes
admin.proto PortalAdminService yes
users.proto PortalUsersService yes
release.proto ReleasePublisherService yes, behind its own key
link.proto PortalLinkService no — see below
common.proto shared messages (Org, Permission, Role, …) —

Gate shorthand used in the tables:

Gate Meaning
device action requireDeviceAccess: the action on the device's org (portal:org), else on the device itself (portal:device), else platform admin. A holding-zone device (no org) is platform-admin only. Refusals are NotFound.
platform admin the * action on portal:system (PLATFORM_ADMIN)
device manage platform admin, or device:manage on portal:system (SUPPORT_ADMIN)
config read / write / apply / confirm device read/write, or a portal:segment grant on one of the device's managed instances — see segment scoping
self acts only on the caller's own subject; no other user's data is reachable

PortalSessionService

RPC Gate Purpose
Me self Caller identity, derived roles (member, plus admin for PLATFORM_ADMIN) and raw permissions. Provisions nothing: a caller with no grant gets an empty permission list and the portal shows its no-organisation screen. Records the visit in portal_sessions.
Enroll self Claim a device with an enrollment code. The code is the credential.
Transfer self Mint a transfer code for a device the caller owns; ownership is enforced downstream.
GetUserPreferences self Every preference of the caller, in one call.
SetUserPreference self Write one preference; an empty value deletes it.

PortalOrgService

RPC Gate Purpose
ListOrganizations filtered Orgs the caller owns (organizations.owner_id) plus orgs they hold a portal:org grant on. A platform admin also gets every other org, labelled admin.
CreateOrganization platform admin Create an empty org owned by system. The admin is not made ORG_OWNER; the first owner is invited from the Team page.
RenameOrganization org write, or platform admin Rename. The slug does not change.
ListMembers org read, or platform admin Holders of a membership role (ORG_OWNER, ORG_MEMBER) on the org. Support grants are not listed.
ListPermissions self, or platform admin ACL tuples of one subject.
ListRoles none The static role catalogue.
AssignPermission / RevokePermission grant authority Write or remove one ACL tuple. See who may grant.
Resolve none Turn ids found inside records (config author, event actor, org) into display names. Never returns an email.
ListOrgAccess org read, or platform admin Who has access to an org, including grants on its individual devices. Platform admins see every holder; everyone else sees membership roles only.
ListPlatformAccess platform admin All portal:system grants, so they can be revoked from the portal.
ListPortalSessions org audit Who used the portal for this org, and when.
ListTemplateOverrides org read, or platform admin Per-org overrides on the service-profile catalogue.
SetTemplateOverride platform admin Write one override.

PortalGatewayService

Fleet and identity

RPC Gate Purpose
ListGateways filtered Devices in the orgs the caller can see. Each DeviceSummary carries caller_actions, what the caller may do on it.
GetGateway device read One device: summary, presentable config, last state (state_data bytes and typed state), published_suffix.
UpdateGateway device write Display name, hostname, model. Empty fields are left unchanged.
GetGatewayState config read Last state report, filtered to the caller's segments for a partner.
GetBlockTrend device read Blocked traffic over time, as reload-corrected increments.
DiscoverEquipment device read Vendor names for the device's ARP table, from the IEEE MA-L listing nexus embeds.

Lifecycle

RPC Gate Purpose
AssignGateway device manage Give a holding-zone device to an org, or move a device between orgs. Sets org_id, status='assigned'.
UnassignGateway platform admin Clear org_id, status='holding'.
ClaimGateway platform admin Fold a holding-zone unit into an existing device: its token and hardware move onto the target and the placeholder is retired.
CreateDevice platform admin Stage a prepared device with no hardware.
CloneDevice platform admin Stage a prepared device seeded with a copy of another's config as a draft.
Reenroll platform admin Move a connected gateway to another environment: pushes a reenroll command carrying the target URLs and a token minted there.

See Device Lifecycle.

Configuration

RPC Gate Purpose
GetGatewayConfig config read Latest presentable config, filtered for a partner.
SaveGatewayConfig config write Store the submitted document as a new draft version. A partner's save is refused if it differs from the stored config outside their segments.
ApplyGatewayConfig config apply Push a version to the device. Re-checks the partner scope against what the version would change now.
ConfirmGatewayConfig config confirm Commit a version inside the confirm window (sends the confirm_config command).
ListConfigVersions / GetConfigVersion device read History. The author is redacted for a caller without audit.
RollbackConfig device write Re-apply an earlier version as a new version.

The apply/confirm pair is the auto-rollback mechanism — see Config Lifecycle.

Partner segments

RPC Gate Purpose
GrantSegmentAccess platform admin Grant a subject PARTNER on one managed instance; the instance must exist on the named device.
RevokeSegmentAccess platform admin Withdraw it. Revoking an absent grant succeeds.
ListSegmentAccess device read Who holds segment grants on this device.

Observability and audit

RPC Gate Purpose
ListDeviceEvents device read + audit Identity and lifecycle changes that are not config versions (hostname, display name, model, org, hardware replacement).
GetGatewayLogs device read + audit Query gateway_logs.
GetGatewayMetrics device read CPU, memory, temperature series.

Operations

RPC Gate Purpose
RestartAgent device device:manage restart_agent command.
RebootDevice device device:manage reboot command.
RunDiagnostic device device:manage ping / traceroute. Returns a command_id; the output arrives over the viewer WebSocket as a command_result with that id.
GetAgentUpdateStatus device read Desired vs reported agent version and the current update phase.
UpdateGatewayAgent device write Record the desired agent version and nudge the device.
SetAgentChannel device write Move the device to another release channel. Does not start an update.

Realtime tickets and console

RPC Gate Purpose
IssueViewerTicket device read Single-use ticket (30 s to redeem, 12 h session ceiling) for one viewer WebSocket.
IssueShellTicket device console Single-use ticket (30 s to redeem, 1 h session ceiling) for one root-console WebSocket. ORG_OWNER, SUPPORT, SUPPORT_ADMIN and platform admins pass; ORG_MEMBER and PARTNER do not. Holding-zone devices are platform-admin only.
ListShellSessions platform admin Console audit trail.

Viewer and shell tickets live in separate tables and are validated by separate RPCs, so one can never be redeemed as the other. See Remote Shell.

Published services and relays

RPC Gate Purpose
IssuePublishedCode device write, or a segment grant covering the service's interface Ask the device to mint an access code for one published service. The code is returned once and never stored by nexus. Requires the device to be online.
RevokePublishedCode as above Revoke one code by id, on the device.
GetRelayLink device read The control plane's half of the gateway's relay path. Relay identity and addresses are filled for platform admins only.
ListRelays platform admin The relay fleet. See Relay fleet.
SetRelayDraining platform admin Drain or undrain a relay.

PortalAdminService

Every RPC requires codes:create on portal:system (target id *), which only the PLATFORM_ADMIN wildcard satisfies.

RPC Purpose
CreateBootstrapToken Mint a named, revocable, multi-use bootstrap token (max_uses 0 = unlimited). Not MAC-locked. The gateway provisioning path.
CreateEnrollmentCodes Batch-create MAC-bound single-use codes (Monsieur Wifi AP claim).
ListEnrollmentCodes / RevokeEnrollmentCode / DeleteEnrollmentCode Manage codes and tokens.
ListDevices / DeleteDevice Every device in every org.
ListOrganizations / DeleteOrganization Every org.
CreateAgentRelease / ListAgentReleases / SetAgentReleaseYanked OTA release catalogue.

PortalUsersService

RPC Gate Purpose
Invite invite authority Create a Zitadel user, or resend the invite if the email exists; returns {user_id, created}. Allowed for a platform admin or a caller holding grant authority somewhere (the org wildcard, or write/transfer on a device). ORG_MEMBER, PARTNER and users with no grant are refused.
Search none Exact-match lookup of one whole email address. Partial input returns no users. The request's method field is ignored.

ReleasePublisherService

RPC Gate Purpose
PublishAgentRelease X-Release-Key header Called by the edge/gateway release pipeline to register a signed build. Refused when NEXUS_RELEASE_PUBLISHER_KEY is unset.

PortalLinkService

Site-to-site links between two gateways: CreateLink, GetLink, ListLinks, DeleteLink, AdvanceLink. Every RPC gates on both devices. The handler (internal/gwconnect/portal_link.go) and its tables (site_links, site_link_ranges) exist, but the service is not mounted in internal/app/app.go and the portal has no client for it, so these RPCs are not reachable.

Wire format notes

  • Connect-JSON. The portal uses JSON by default (VITE_NEXUS_BINARY=true switches to binary). In JSON, int64 values are strings and bytes are base64.
  • Opaque bytes fields carry JSON documents: state_data, config_data, interfaces_from_newer_versions, metrics_json, preference value. The generated client types them as Uint8Array; whatever the portal decodes from them is untyped, so an int64 inside arrives as a string with no compiler warning. Prefer the typed fields where they exist (GetGatewayResponse.state, GetGatewayStateResponse.state, both gateway.v1.StateReportRequest).