WireGuard VPN API Documentation

Developer reference for the FastAPI service in /data/wgvpn. Last verified on 2026-08-12.

Public base URLhttps://wgvpnapi.tdimpact.app:5530
Local container URLhttp://127.0.0.1:5533
AuthAuthorization: Bearer <API_TOKEN>
TransportAll API operations are currently GET requests.

Overview

This API manages WireGuard peers through server-side scripts under /data/wgvpn/scripts. Server WireGuard configs live in /etc/wireguard, and generated client configs live in /data/wgvpn/clients.

Every request must include a bearer token. JSON responses use application/json, except /get_cert?download=true, which returns application/octet-stream.

Mutating operations use GET for compatibility with the current integration. Treat /create, /revoke, /block, and /unblock as write operations even though the HTTP method is GET.

Parameter Rules

ParameterUsed byRequiredValidationMeaning
network_wg /create, /revoke, /block, /unblock, /get_users, /get_cert Yes ^\d{1,5}$ Numeric suffix for the WireGuard interface. 0 maps to wg0 and /etc/wireguard/wg0.conf.
client_name /create, /revoke, /block, /unblock, /get_cert Yes ^[A-Za-z0-9_.-]{1,64}$ Stable client identifier. It is used in the server config marker ### Client <client_name> and the generated client filename.
client_ip_v4 /create Yes IPv4 address without CIDR, for example 10.100.0.65. The client tunnel address. It must belong to the IPv4 CIDR configured in the target network's Address line. The server stores the peer route as <client_ip_v4>/32.
download /get_cert No Boolean query value. Defaults to false. When true, returns the raw client config file instead of JSON.

Error Responses

Most domain errors return top-level JSON with success=false. Authentication and FastAPI validation errors use the standard FastAPI detail shape.

HTTPErrorWhen it happensShape
401Auth header missing or invalidNo bearer token header or malformed header.{"detail":"Missing or invalid Authorization header"}
403Invalid tokenBearer token does not match the configured API token.{"detail":"Invalid token"}
404network_not_foundRequested /etc/wireguard/wgX.conf or params file does not exist.{"success":false,"error":"network_not_found",...}
404client_not_foundThe requested client marker does not exist in the network config.{"success":false,"error":"client_not_found",...}
404certificate_not_foundThe generated client config file does not exist in /data/wgvpn/clients.{"success":false,"error":"certificate_not_found",...}
409client_name_existsCreate requested a name that already exists in config or as a client config file.{"success":false,"error":"client_name_exists",...}
409client_ip_existsCreate requested an IP already used as current AllowedIPs or saved OriginalAllowedIPs.{"success":false,"error":"client_ip_exists",...}
409client_state_invalidUnblock cannot restore the peer because saved state is missing or malformed.{"success":false,"error":"client_state_invalid",...}
409network_cidr_not_foundCreate cannot find an IPv4 CIDR in the target network config's Address line.{"success":false,"error":"network_cidr_not_found",...}
422client_ip_outside_networkCreate requested a valid IPv4 address, but it is outside the target WireGuard network CIDR.{"success":false,"error":"client_ip_outside_network",...}
422client_ip_reservedCreate requested the server address, network address, or broadcast address.{"success":false,"error":"client_ip_reserved",...}
422Validation errorA required query parameter is missing or fails the format rules.{"detail":[...]}
500Internal errorUnexpected SSH, script, or runtime failure.{"detail":"..."}

Endpoints

GET/get_networks

Lists WireGuard network config files found in /etc/wireguard/*.conf.

Request Parameters

NameRequiredValidationDescription
No query parameters.

Request Example

curl -H "Authorization: Bearer <API_TOKEN>" \
  "https://wgvpnapi.tdimpact.app:5530/get_networks"

Success Response

{
  "success": true,
  "networks": [
    {"name": "wg0", "address": "10.100.0.1/24", "listenPort": "50042"}
  ]
}
GET/get_users

Lists clients for one WireGuard network. Current AllowedIPs is intentionally not returned; use status, blocked, and original_allowed_ips.

Request Parameters

NameRequiredValidationDescription
network_wgYes^\d{1,5}$Network suffix. Example: 0 maps to wg0.

Request Example

curl -H "Authorization: Bearer <API_TOKEN>" \
  "https://wgvpnapi.tdimpact.app:5530/get_users?network_wg=0"

Success Response

{
  "success": true,
  "network": "wg0",
  "users": [
    {
      "name": "test_luchkin65",
      "status": "active",
      "original_allowed_ips": "10.100.0.65/32",
      "blocked": false
    }
  ]
}
GET/create

Creates a client config file and appends a peer block to the server WireGuard config.

Checks Before Create

  • The network config /etc/wireguard/wgX.conf must exist.
  • The params file /etc/wireguard/paramsX must exist.
  • The client name must not already exist in the server config.
  • The generated client file must not already exist.
  • The requested IP must belong to the IPv4 CIDR from the target network's Address line, for example 10.100.0.1/20.
  • The requested IP must not equal the server interface address, the network address, or the broadcast address.
  • The requested IP must not already be used as current AllowedIPs or saved OriginalAllowedIPs.

Request Parameters

NameRequiredValidationDescription
network_wgYes^\d{1,5}$Network suffix. Example: 0 maps to wg0.
client_nameYes^[A-Za-z0-9_.-]{1,64}$Unique client name. Used in the peer marker and generated filename.
client_ip_v4YesIPv4 address without CIDRClient tunnel IPv4 address. Must be inside the target network CIDR. The server stores the peer route as /32.

Request Example

curl -H "Authorization: Bearer <API_TOKEN>" \
  "https://wgvpnapi.tdimpact.app:5530/create?network_wg=0&client_name=new_client&client_ip_v4=10.100.0.80"

Success Response

{
  "success": true,
  "status": "created",
  "network": "wg0",
  "user": "new_client",
  "client_ip_v4": "10.100.0.80",
  "output": ["SUCCESS"]
}
GET/revoke

Removes the client peer block from the server config and deletes the generated client config file.

Request Parameters

NameRequiredValidationDescription
network_wgYes^\d{1,5}$Network suffix. Example: 0 maps to wg0.
client_nameYes^[A-Za-z0-9_.-]{1,64}$Existing client name to remove.

Checks Before Revoke

  • The network config must exist.
  • The client marker ### Client <client_name> must exist exactly.

Request Example

curl -H "Authorization: Bearer <API_TOKEN>" \
  "https://wgvpnapi.tdimpact.app:5530/revoke?network_wg=0&client_name=old_client"

Success Response

{
  "success": true,
  "status": "revoked",
  "network": "wg0",
  "user": "old_client",
  "output": ["SUCCESS"]
}
GET/block

Blocks a client without deleting it. The peer remains in the server config, keys stay intact, and AllowedIPs is set to 0.0.0.0/32.

Request Parameters

NameRequiredValidationDescription
network_wgYes^\d{1,5}$Network suffix. Example: 0 maps to wg0.
client_nameYes^[A-Za-z0-9_.-]{1,64}$Existing client name to block.

Checks Before Block

  • The network config must exist.
  • The client marker must exist exactly.

Request Example

curl -H "Authorization: Bearer <API_TOKEN>" \
  "https://wgvpnapi.tdimpact.app:5530/block?network_wg=0&client_name=client1"

Success Response

{
  "success": true,
  "status": "blocked",
  "network": "wg0",
  "user": "client1",
  "original_allowed_ips": "10.100.0.80/32",
  "output": ["SUCCESS", "Status=blocked", "OriginalAllowedIPs=10.100.0.80/32"]
}

Blocking an already blocked client is idempotent and returns success if saved original state exists.

GET/unblock

Restores a blocked client using the saved OriginalAllowedIPs. No allowed_ips input parameter is accepted or needed.

Request Parameters

NameRequiredValidationDescription
network_wgYes^\d{1,5}$Network suffix. Example: 0 maps to wg0.
client_nameYes^[A-Za-z0-9_.-]{1,64}$Existing client name to unblock.

Checks Before Unblock

  • The network config must exist.
  • The client marker must exist exactly.
  • The peer block must contain OriginalAllowedIPs and an AllowedIPs line.

Request Example

curl -H "Authorization: Bearer <API_TOKEN>" \
  "https://wgvpnapi.tdimpact.app:5530/unblock?network_wg=0&client_name=client1"

Success Response

{
  "success": true,
  "status": "unblocked",
  "network": "wg0",
  "user": "client1",
  "allowed_ips": "10.100.0.80/32",
  "output": ["SUCCESS", "Status=active", "AllowedIPs=10.100.0.80/32"]
}

Unblocking an already active client is idempotent if OriginalAllowedIPs exists.

GET/get_cert

Returns the generated client WireGuard config. By default the config is JSON-escaped in the content field.

Request Parameters

NameRequiredValidationDescription
network_wgYes^\d{1,5}$Network suffix. Example: 0 maps to wg0.
client_nameYes^[A-Za-z0-9_.-]{1,64}$Existing client name whose config file should be returned.
downloadNoBoolean, defaults to falseWhen true, returns the raw file as application/octet-stream.

Request Example

curl -H "Authorization: Bearer <API_TOKEN>" \
  "https://wgvpnapi.tdimpact.app:5530/get_cert?network_wg=0&client_name=client1"

JSON Response

{
  "success": true,
  "network": "wg0",
  "user": "client1",
  "filename": "wg0-client1.conf",
  "content": "[Interface]\nPrivateKey = ..."
}

File Download

curl -H "Authorization: Bearer <API_TOKEN>" \
  "https://wgvpnapi.tdimpact.app:5530/get_cert?network_wg=0&client_name=client1&download=true" \
  -o wg0-client1.conf
The JSON and download forms contain the client's private key. Do not log or expose these responses.

Client State Model

Each managed peer block uses comments to store API-visible state:

### Client client1
### Status active
### OriginalAllowedIPs 10.100.0.80/32
[Peer]
PublicKey = ...
PresharedKey = ...
AllowedIPs = 10.100.0.80/32
PersistentKeepalive = 5

Blocking changes only the status metadata and the technical AllowedIPs value:

### Status blocked
### OriginalAllowedIPs 10.100.0.80/32
AllowedIPs = 0.0.0.0/32

Unblocking restores AllowedIPs from OriginalAllowedIPs. The API intentionally does not accept an allowed_ips input for unblock.

Network masks such as /24 or /20 are read from the existing WireGuard server config. Client peer entries still use /32 routes; the mask is used to validate whether a new client IP belongs to the selected network during /create.

Verified Cases

The following cases were tested against the live service on http://127.0.0.1:5533. A disposable test client was created, blocked, unblocked, revoked, and verified absent afterward.

CaseExpected HTTPResultNotes
Missing auth401PassedStandard FastAPI detail string.
Invalid auth403PassedStandard FastAPI detail string.
List networks200PassedReturned wg0, wg10, wg5.
List users200PassedReturned users without current allowed_ips.
Missing network for get users404Passednetwork_not_found.
Invalid or missing query params422PassedFastAPI validation errors.
Get certificate JSON200PassedResponse contained expected metadata and config content.
Get certificate download200PassedReturned application/octet-stream.
Missing certificate404Passedcertificate_not_found.
Revoke missing client404Passedclient_not_found; no false success.
Create missing network404Passednetwork_not_found.
Create duplicate name409Passedclient_name_exists.
Create duplicate IP409Passedclient_ip_exists.
Create valid temporary client200PassedClient config and peer were created.
Block missing client/network404PassedStructured top-level JSON errors.
Block valid client200PassedState changed to blocked and original IP was preserved.
Block already blocked200PassedIdempotent success.
Unblock missing client/network404PassedStructured top-level JSON errors.
Unblock valid client200PassedOriginal IP restored from config metadata.
Unblock already active200PassedIdempotent success when original state exists.
Revoke valid temporary client200PassedPeer and client config removed.
Revoke already removed404Passedclient_not_found.
Certificate after revoke404Passedcertificate_not_found.

Test coverage is summarized above for quick developer review.

Operational Notes and Limitations