Skip to content

Mesh API

9 operations. Every call needs a session cookie or an Authorization: Bearer nct_… token unless marked Public. Conventions, errors and scopes

GET/environments/{environmentId}/mesh

Mesh 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.

ParameterInTypeDescription
environmentIdrequiredpathstring
Response 200 · OK · application/json
EnvironmentMeshView
  • EnvGrantView[] | nullrequired
  • EnvLinkView[] | nullrequired
  • RouteView[] | nullrequired
Errors
  • 401Unauthorized
  • 403Forbidden
  • 404Not Found
  • 422Unprocessable Entity
  • 500Internal Server Error

Errors are RFC 9457 application/problem+json with a stable code field.

POST/environments/{environmentId}/mesh/reconcile

Reconcile 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.

ParameterInTypeDescription
environmentIdrequiredpathstring
Request body · application/json · required
ReconcileInputBody
  • acceptMeshChangesboolean
    Confirm the tailnet devices mode add creates; the 409 mesh_confirmation_required response states how many
  • modeenum: add | repairrequired
    add creates the links the environment needs (devices need acceptMeshChanges); repair only removes grants without a source
Response 200 · OK · application/json
ReconcileView
  • GrantChange[] | nullrequired
  • devicesAddedinteger (int64)required
  • modeenum: add | repairrequired
  • GrantChange[] | nullrequired
  • restagedstring[] | nullrequired
    Consumers whose resolved addresses changed; their staged bar shows it
  • waitinginteger (int64)required
    Grants kept for their grace period
Errors
  • 401Unauthorized
  • 403Forbidden
  • 404Not Found
  • 409Conflictmesh_confirmation_required
  • 422Unprocessable Entity
  • 500Internal Server Error

Errors are RFC 9457 application/problem+json with a stable code field.

GET/mesh

Server 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
View
  • aclManagedWarningstring
    Shown while managed mode is on for Tailscale
  • aclMessagestringrequired
  • aclModeenum: managed | advisory | offrequired
  • aclStateenum: unknown | applied | pending | drift | advisory | errorrequired
  • autoJoinbooleanrequired
    Online servers with a current agent join the mesh automatically (each adds one device)
  • CoordinatorViewrequired
  • DevicesViewrequired
  • enabledbooleanrequired
    At least one server joined the mesh (turned on by the first server)
  • MeshLinkView[] | nullrequired
  • loginServerstringrequired
  • managedPushAvailablebooleanrequired
    The credential can write the tailnet policy (Tailscale OAuth with the policy_file scope, or a Headscale API key)
  • meshTagstringrequired
    The one tag every mesh node of the team carries; it needs a tagOwners entry on Tailscale
  • NodeView[] | nullrequired
  • pausedbooleanrequired
    Mesh changes wait (the platform Headscale is being migrated); established connections keep working
  • pausedReasonstringrequired
  • providerenum: tailscale | headscale | nonerequired
  • RuleView[] | nullrequired
    The access rules NebulaCtrl generates (read-only)
  • snippetstring
    The rules to add to the tailnet policy (advisory mode)
  • warningsstring[] | nullrequired
Errors
  • 401Unauthorized
  • 403Forbidden
  • 404Not Found
  • 500Internal Server Error

Errors are RFC 9457 application/problem+json with a stable code field.

POST/mesh/acl/apply

Apply 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
View
  • aclManagedWarningstring
    Shown while managed mode is on for Tailscale
  • aclMessagestringrequired
  • aclModeenum: managed | advisory | offrequired
  • aclStateenum: unknown | applied | pending | drift | advisory | errorrequired
  • autoJoinbooleanrequired
    Online servers with a current agent join the mesh automatically (each adds one device)
  • CoordinatorViewrequired
  • DevicesViewrequired
  • enabledbooleanrequired
    At least one server joined the mesh (turned on by the first server)
  • MeshLinkView[] | nullrequired
  • loginServerstringrequired
  • managedPushAvailablebooleanrequired
    The credential can write the tailnet policy (Tailscale OAuth with the policy_file scope, or a Headscale API key)
  • meshTagstringrequired
    The one tag every mesh node of the team carries; it needs a tagOwners entry on Tailscale
  • NodeView[] | nullrequired
  • pausedbooleanrequired
    Mesh changes wait (the platform Headscale is being migrated); established connections keep working
  • pausedReasonstringrequired
  • providerenum: tailscale | headscale | nonerequired
  • RuleView[] | nullrequired
    The access rules NebulaCtrl generates (read-only)
  • snippetstring
    The rules to add to the tailnet policy (advisory mode)
  • warningsstring[] | nullrequired
Errors
  • 401Unauthorized
  • 403Forbidden
  • 404Not Found
  • 422Unprocessable Entity
  • 500Internal Server Error

Errors are RFC 9457 application/problem+json with a stable code field.

POST/mesh/acl/check

Compare 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
ACLCheck
  • messagestringrequired
  • Rule[] | nullrequired
    Generated rules absent from the stored policy
  • readablebooleanrequired
  • Rule[] | nullrequired
    Rules NebulaCtrl owns in the stored policy that are no longer generated
Errors
  • 401Unauthorized
  • 403Forbidden
  • 404Not Found
  • 500Internal Server Error

Errors are RFC 9457 application/problem+json with a stable code field.

POST/mesh/acl/preview

Preview 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
ACLPreview
  • ACLDiff
  • policystringrequired
    What NebulaCtrl owns (managed Headscale: the whole policy) or the snippet to paste (HuJSON with comments)
  • RuleView[] | nullrequired
Errors
  • 401Unauthorized
  • 403Forbidden
  • 404Not Found
  • 500Internal Server Error

Errors are RFC 9457 application/problem+json with a stable code field.

PUT/mesh/settings

Change 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
SettingsInputBody1
  • aclModeenum: managed | advisory | off
    managed: 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.
  • autoJoinboolean
    Online servers with a current agent join the mesh automatically (each adds one device)
  • enabledboolean
    Turning the mesh off is refused (409 mesh_in_use) while servers still have nodes
  • meshTagstring
    The 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
View
  • aclManagedWarningstring
    Shown while managed mode is on for Tailscale
  • aclMessagestringrequired
  • aclModeenum: managed | advisory | offrequired
  • aclStateenum: unknown | applied | pending | drift | advisory | errorrequired
  • autoJoinbooleanrequired
    Online servers with a current agent join the mesh automatically (each adds one device)
  • CoordinatorViewrequired
  • DevicesViewrequired
  • enabledbooleanrequired
    At least one server joined the mesh (turned on by the first server)
  • MeshLinkView[] | nullrequired
  • loginServerstringrequired
  • managedPushAvailablebooleanrequired
    The credential can write the tailnet policy (Tailscale OAuth with the policy_file scope, or a Headscale API key)
  • meshTagstringrequired
    The one tag every mesh node of the team carries; it needs a tagOwners entry on Tailscale
  • NodeView[] | nullrequired
  • pausedbooleanrequired
    Mesh changes wait (the platform Headscale is being migrated); established connections keep working
  • pausedReasonstringrequired
  • providerenum: tailscale | headscale | nonerequired
  • RuleView[] | nullrequired
    The access rules NebulaCtrl generates (read-only)
  • snippetstring
    The rules to add to the tailnet policy (advisory mode)
  • warningsstring[] | nullrequired
Errors
  • 401Unauthorized
  • 403Forbidden
  • 404Not Found
  • 422Unprocessable Entitymesh_policy_scope_missing
  • 500Internal Server Error

Errors are RFC 9457 application/problem+json with a stable code field.

GET/services/{serviceId}/mesh

Mesh 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.

ParameterInTypeDescription
serviceIdrequiredpathstring
Response 200 · OK · application/json
ServiceMeshView
  • ConsumerView[] | nullrequired
    Services on other servers that reach this one
  • ExposureView[] | nullrequired
  • RouteView[] | nullrequired
    The providers on other servers this service reaches
Errors
  • 401Unauthorized
  • 403Forbidden
  • 404Not Found
  • 422Unprocessable Entity
  • 500Internal Server Error

Errors are RFC 9457 application/problem+json with a stable code field.