Reference
View as MarkdownMesh API
9 operations. Every call needs a session cookie or an Authorization: Bearer nct_… token unless marked Public. Conventions, errors and scopes
/environments/{environmentId}/meshMesh links, grants and routes of an environment
Needs projects:read. Links are the tailnet link nodes of the environment (service and replication purpose); grants say which service reaches which provider and why (reference, edge, replica); routes list, per consumer, the providers on other servers with the mesh port the consumer dials.
| Parameter | In | Type | Description |
|---|---|---|---|
environmentIdrequired | path | string |
Response 200 · OK · application/json
- EnvGrantView[] | nullrequired
- EnvLinkView[] | nullrequired
- RouteView[] | nullrequired
401Unauthorized403Forbidden404Not Found422Unprocessable Entity500Internal Server Error
Errors are RFC 9457 application/problem+json with a stable code field.
/environments/{environmentId}/mesh/reconcileReconcile the mesh links of an environment now
Needs servers:write. Mode add creates every link, exposure and grant the environment's references and canvas edges need; it adds tailnet devices, so it needs acceptMeshChanges (409 mesh_confirmation_required states the count; 422 with the blocker code, for example mesh_server_required, when the mesh cannot serve a need). Mode repair is what runs every 5 minutes: it only removes grants whose source is gone (10 minutes grace; an edge's grant at once) and never adds a device.
| Parameter | In | Type | Description |
|---|---|---|---|
environmentIdrequired | path | string |
Request body · application/json · required
- acceptMeshChangesbooleanConfirm the tailnet devices mode add creates; the 409 mesh_confirmation_required response states how many
- modeenum: add | repairrequiredadd creates the links the environment needs (devices need acceptMeshChanges); repair only removes grants without a source
Response 200 · OK · application/json
- GrantChange[] | nullrequired
- devicesAddedinteger (int64)required
- modeenum: add | repairrequired
- GrantChange[] | nullrequired
- restagedstring[] | nullrequiredConsumers whose resolved addresses changed; their staged bar shows it
- waitinginteger (int64)requiredGrants kept for their grace period
401Unauthorized403Forbidden404Not Found409Conflictmesh_confirmation_required422Unprocessable Entity500Internal Server Error
Errors are RFC 9457 application/problem+json with a stable code field.
/meshServer mesh of the team
The managed tailnet mesh: coordinator health, the ACL mode and state, the server nodes, the link nodes, the access rules NebulaCtrl derives (read-only) and the tagged device count. Servers join the mesh one by one; replicas and cross-server service links use it.
Response 200 · OK · application/json
- aclManagedWarningstringShown while managed mode is on for Tailscale
- aclMessagestringrequired
- aclModeenum: managed | advisory | offrequired
- aclStateenum: unknown | applied | pending | drift | advisory | errorrequired
- autoJoinbooleanrequiredOnline servers with a current agent join the mesh automatically (each adds one device)
- CoordinatorViewrequired
- DevicesViewrequired
- enabledbooleanrequiredAt least one server joined the mesh (turned on by the first server)
- MeshLinkView[] | nullrequired
- loginServerstringrequired
- managedPushAvailablebooleanrequiredThe credential can write the tailnet policy (Tailscale OAuth with the policy_file scope, or a Headscale API key)
- meshTagstringrequiredThe one tag every mesh node of the team carries; it needs a tagOwners entry on Tailscale
- NodeView[] | nullrequired
- pausedbooleanrequiredMesh changes wait (the platform Headscale is being migrated); established connections keep working
- pausedReasonstringrequired
- providerenum: tailscale | headscale | nonerequired
- RuleView[] | nullrequiredThe access rules NebulaCtrl generates (read-only)
- snippetstringThe rules to add to the tailnet policy (advisory mode)
- warningsstring[] | nullrequired
401Unauthorized403Forbidden404Not Found500Internal Server Error
Errors are RFC 9457 application/problem+json with a stable code field.
/mesh/acl/applyApply the access rules now
Regenerates and applies the policy according to the ACL mode (managed writes it, advisory only verifies it). It normally runs by itself a few seconds after every change.
Response 200 · OK · application/json
- aclManagedWarningstringShown while managed mode is on for Tailscale
- aclMessagestringrequired
- aclModeenum: managed | advisory | offrequired
- aclStateenum: unknown | applied | pending | drift | advisory | errorrequired
- autoJoinbooleanrequiredOnline servers with a current agent join the mesh automatically (each adds one device)
- CoordinatorViewrequired
- DevicesViewrequired
- enabledbooleanrequiredAt least one server joined the mesh (turned on by the first server)
- MeshLinkView[] | nullrequired
- loginServerstringrequired
- managedPushAvailablebooleanrequiredThe credential can write the tailnet policy (Tailscale OAuth with the policy_file scope, or a Headscale API key)
- meshTagstringrequiredThe one tag every mesh node of the team carries; it needs a tagOwners entry on Tailscale
- NodeView[] | nullrequired
- pausedbooleanrequiredMesh changes wait (the platform Headscale is being migrated); established connections keep working
- pausedReasonstringrequired
- providerenum: tailscale | headscale | nonerequired
- RuleView[] | nullrequiredThe access rules NebulaCtrl generates (read-only)
- snippetstringThe rules to add to the tailnet policy (advisory mode)
- warningsstring[] | nullrequired
401Unauthorized403Forbidden404Not Found422Unprocessable Entity500Internal Server Error
Errors are RFC 9457 application/problem+json with a stable code field.
/mesh/acl/checkCompare the generated rules with the stored policy
Read-only drift check: which generated rules are missing from the tailnet policy and which outdated NebulaCtrl rules it still holds. It cannot prove that no broader rule exists; the connectivity test is the ground truth.
Response 200 · OK · application/json
- messagestringrequired
- Rule[] | nullrequiredGenerated rules absent from the stored policy
- readablebooleanrequired
- Rule[] | nullrequiredRules NebulaCtrl owns in the stored policy that are no longer generated
401Unauthorized403Forbidden404Not Found500Internal Server Error
Errors are RFC 9457 application/problem+json with a stable code field.
/mesh/acl/previewPreview the generated access rules
The rules derived from the mesh tables, the policy document (managed Headscale) or the snippet to paste (advisory), and, when the stored policy can be read, what would be added or removed. Nothing is written.
Response 200 · OK · application/json
- ACLDiff
- policystringrequiredWhat NebulaCtrl owns (managed Headscale: the whole policy) or the snippet to paste (HuJSON with comments)
- RuleView[] | nullrequired
401Unauthorized403Forbidden404Not Found500Internal Server Error
Errors are RFC 9457 application/problem+json with a stable code field.
/mesh/links/{linkId}/reprovisionRe-provision a link node
Re-creates a link node with a fresh single-use key (a new device and tailnet IP; the access rules regenerate).
| Parameter | In | Type | Description |
|---|---|---|---|
Idempotency-Key | header | string | Client-chosen key (<=255 chars). A retry with the same key replays the original response for 24 hours. |
linkIdrequired | path | string |
Response 202 · Accepted · application/json
- acceptedbooleanrequired
401Unauthorized403Forbidden404Not Found422Unprocessable Entity500Internal Server Error
Errors are RFC 9457 application/problem+json with a stable code field.
/mesh/settingsChange the mesh settings
Auto-join, the mesh tag and the ACL mode. Switching Tailscale to managed is an opt-in: it needs the OAuth client's policy_file scope, refuses when another team uses the same tailnet (409 mesh_acl_shared_tailnet) and answers 422 mesh_policy_scope_missing when the scope is missing. The token can then rewrite the whole tailnet policy; NebulaCtrl itself replaces only its own rules and keeps comments. Changing the ACL mode or the tag needs the admin scope.
Request body · application/json · required
- aclModeenum: managed | advisory | offmanaged: NebulaCtrl writes the policy (Headscale with an API key; Tailscale only as an opt-in that needs the OAuth scope policy_file and replaces only NebulaCtrl's own rules). advisory: the rules are shown, never written. off: no rules. Needs the admin scope.
- autoJoinbooleanOnline servers with a current agent join the mesh automatically (each adds one device)
- enabledbooleanTurning the mesh off is refused (409 mesh_in_use) while servers still have nodes
- meshTagstringThe tag every mesh node carries (default tag:nebula-mesh); it must be in the integration's allowed tags. Needs the admin scope; fixed while nodes exist.
Response 200 · OK · application/json
- aclManagedWarningstringShown while managed mode is on for Tailscale
- aclMessagestringrequired
- aclModeenum: managed | advisory | offrequired
- aclStateenum: unknown | applied | pending | drift | advisory | errorrequired
- autoJoinbooleanrequiredOnline servers with a current agent join the mesh automatically (each adds one device)
- CoordinatorViewrequired
- DevicesViewrequired
- enabledbooleanrequiredAt least one server joined the mesh (turned on by the first server)
- MeshLinkView[] | nullrequired
- loginServerstringrequired
- managedPushAvailablebooleanrequiredThe credential can write the tailnet policy (Tailscale OAuth with the policy_file scope, or a Headscale API key)
- meshTagstringrequiredThe one tag every mesh node of the team carries; it needs a tagOwners entry on Tailscale
- NodeView[] | nullrequired
- pausedbooleanrequiredMesh changes wait (the platform Headscale is being migrated); established connections keep working
- pausedReasonstringrequired
- providerenum: tailscale | headscale | nonerequired
- RuleView[] | nullrequiredThe access rules NebulaCtrl generates (read-only)
- snippetstringThe rules to add to the tailnet policy (advisory mode)
- warningsstring[] | nullrequired
401Unauthorized403Forbidden404Not Found422Unprocessable Entitymesh_policy_scope_missing500Internal Server Error
Errors are RFC 9457 application/problem+json with a stable code field.
/services/{serviceId}/meshMesh exposures, routes and consumers of a service
Needs projects:read. exposures are the service's ports on its server's mesh node, routes the providers on other servers it reaches (a consumer dials <provider slug>:<mesh port>), consumers the services on other servers that reach it.
| Parameter | In | Type | Description |
|---|---|---|---|
serviceIdrequired | path | string |
Response 200 · OK · application/json
- ConsumerView[] | nullrequiredServices on other servers that reach this one
- ExposureView[] | nullrequired
- RouteView[] | nullrequiredThe providers on other servers this service reaches
401Unauthorized403Forbidden404Not Found422Unprocessable Entity500Internal Server Error
Errors are RFC 9457 application/problem+json with a stable code field.