# Proxy API

6 operations under /api/v1. Errors are RFC 9457 problem+json with a stable `code` field. The complete schemas are in https://nebulactrl.com/api/v1/openapi.json.

## GET /servers/{serverId}/proxy

Server-level proxy state: certificates, upstream policy, TCP/UDP ports and tailnet

Authentication: session cookie or `Authorization: Bearer nct_…` token.

Parameters:
- `serverId` (path, string, required)

Response 200: OK (ServerProxy)
  - `agentTooOld` (boolean, required): True when the agent lacks proxy.v2; staging proxy features returns 422 agent_too_old
  - `appliedGeneration` (integer (int64), required)
  - `appliedUpstreamPolicy` (ProxyUpstreamPolicy, required)
  - `capabilities` (string[] | null, required)
  - `certificates` (ServerCertificate[] | null, required)
  - `error` (string, required)
  - `generation` (integer (int64), required)
  - `l4Ports` (ProxyL4Port[] | null, required)
  - `lastDeploy` (ProxyDeployInfo)
  - `ports` (ProxyPorts, required)
  - `staged` (boolean, required): Staged server-level changes await Deploy proxy
  - `status` (string, required): Traefik state reported by the agent: ok, starting, error, or empty
  - `tailnet` (ProxyTailnet, required)
  - `upstreamPolicy` (ProxyUpstreamPolicy, required)
Errors: 401 Unauthorized; 403 Forbidden; 404 Not Found; 422 Unprocessable Entity; 500 Internal Server Error

## POST /servers/{serverId}/proxy/deploy

Deploy the server-level proxy configuration

Sends a `proxy_configure` command with the desired certificates, upstream policy and tailnet. The result updates the applied state asynchronously.

Authentication: session cookie or `Authorization: Bearer nct_…` token.

Parameters:
- `Idempotency-Key` (header, string): Client-chosen key (<=255 chars). A retry with the same key replays the original response for 24 hours.
- `serverId` (path, string, required)

Request body (application/json, required): DeployInputBody
  - `reprovision` (boolean): Delete the managed node and register it again with a new key

Response 202: Accepted (ProxyDeployResult)
  - `commandId` (string, required)
  - `generation` (integer (int64), required)
  - `plan` (ProxyPlan, required)
Errors: 401 Unauthorized; 403 Forbidden; 404 Not Found; 409 Conflict; 422 Unprocessable Entity; 500 Internal Server Error

## POST /servers/{serverId}/proxy/plan

Preview what deploying the proxy would change

Lists the staged differences, whether the proxy container is recreated and warnings (a tailnet node is created, replaced or deleted, a port another process holds, HTTP-01 certificates that cannot validate off port 80). `ports` plans the deploy as if that proxy ports setting were staged too, without staging it (0 = the agent's own port).

Authentication: session cookie or `Authorization: Bearer nct_…` token.

Parameters:
- `serverId` (path, string, required)

Request body (application/json, required): PlanInputBody
  - `ports` (PortsStruct1)
  - `reprovision` (boolean): Delete the managed node and register it again with a new key

Response 200: OK (ProxyPlan)
  - `diff` (ProxyPlanChange[] | null, required)
  - `reasons` (string[] | null, required)
  - `restartRequired` (boolean, required): The proxy container is recreated (about 1 second of dropped connections)
  - `warnings` (string[] | null, required)
Errors: 401 Unauthorized; 403 Forbidden; 404 Not Found; 422 Unprocessable Entity; 500 Internal Server Error

## GET /servers/{serverId}/proxy/routes

The effective route table of the server's proxy (read-only)

Hostnames, upstreams and policies as the proxy receives them. Basic-auth users and hashes are never included.

Authentication: session cookie or `Authorization: Bearer nct_…` token.

Parameters:
- `serverId` (path, string, required)

Response 200: OK (RoutesOutputBody)
  - `items` (ProxyRoute[] | null, required)
Errors: 401 Unauthorized; 403 Forbidden; 404 Not Found; 422 Unprocessable Entity; 500 Internal Server Error

## PATCH /servers/{serverId}/proxy/settings

Stage upstream policy and tailnet settings

Needs `proxy:write`; the loopback and link-local toggles need `admin`; the proxy `ports` can only be changed by the instance administrator (403 `instance_admin_required`; 422 `invalid_proxy_ports`, `proxy_port_clash`, `agent_too_old`). Changes are staged until `POST /servers/{id}/proxy/deploy`, which recreates the proxy container when a port changes. A managed tailnet needs the Tailscale integration (422 `tailnet_not_configured`); host mode needs Tailscale detected on the host (422 `host_tailscale_not_detected`).

Authentication: session cookie or `Authorization: Bearer nct_…` token.

Parameters:
- `serverId` (path, string, required)

Request body (application/json, required): UpdateSettingsInputBody
  - `ports` (PortsStruct)
  - `tailnet` (TailnetStruct)
  - `upstreamPolicy` (UpstreamPolicyStruct)

Response 200: OK (ServerProxy)
  - `agentTooOld` (boolean, required): True when the agent lacks proxy.v2; staging proxy features returns 422 agent_too_old
  - `appliedGeneration` (integer (int64), required)
  - `appliedUpstreamPolicy` (ProxyUpstreamPolicy, required)
  - `capabilities` (string[] | null, required)
  - `certificates` (ServerCertificate[] | null, required)
  - `error` (string, required)
  - `generation` (integer (int64), required)
  - `l4Ports` (ProxyL4Port[] | null, required)
  - `lastDeploy` (ProxyDeployInfo)
  - `ports` (ProxyPorts, required)
  - `staged` (boolean, required): Staged server-level changes await Deploy proxy
  - `status` (string, required): Traefik state reported by the agent: ok, starting, error, or empty
  - `tailnet` (ProxyTailnet, required)
  - `upstreamPolicy` (ProxyUpstreamPolicy, required)
Errors: 401 Unauthorized; 403 Forbidden (`instance_admin_required`); 404 Not Found; 422 Unprocessable Entity (`invalid_proxy_ports`, `tailnet_not_configured`, `host_tailscale_not_detected`); 500 Internal Server Error

## POST /servers/{serverId}/proxy/tailnet/reprovision

Re-provision the managed tailnet node

Deletes the node's state, registers it again with a fresh single-use key and removes the old device from the tailnet. Use it when the device was removed in the Tailscale admin console.

Authentication: session cookie or `Authorization: Bearer nct_…` token.

Parameters:
- `Idempotency-Key` (header, string): Client-chosen key (<=255 chars). A retry with the same key replays the original response for 24 hours.
- `serverId` (path, string, required)

Response 202: Accepted (ProxyDeployResult)
  - `commandId` (string, required)
  - `generation` (integer (int64), required)
  - `plan` (ProxyPlan, required)
Errors: 401 Unauthorized; 403 Forbidden; 404 Not Found; 409 Conflict; 422 Unprocessable Entity; 500 Internal Server Error
