Skip to content

Webhooks

Webhooks allow WireGuard Portal to notify external services about events such as user creation, device changes, or configuration updates. This enables integration with other systems and automation workflows.

When webhooks are configured and a specified event occurs, WireGuard Portal sends an HTTP POST request to the configured webhook URL. The payload contains event-specific data in JSON format.

Configuration

All available configuration options for webhooks can be found in the configuration overview.

A basic webhook configuration looks like this:

webhook:
  url: https://your-service.example.com/webhook

Security

Webhooks can be secured by using a shared secret. This secret is included in the Authorization header of the webhook request, allowing your service to verify the authenticity of the request. You can set the shared secret in the webhook configuration:

webhook:
  url: https://your-service.example.com/webhook
  secret: "Basic dXNlcm5hbWU6cGFzc3dvcmQ="

You should also make sure that your webhook endpoint is secured with HTTPS to prevent eavesdropping and tampering.

Available Events

WireGuard Portal supports various events that can trigger webhooks. The following events are available:

  • create: Triggered when a new entity is created.
  • update: Triggered when an existing entity is updated.
  • delete: Triggered when an entity is deleted.
  • connect: Triggered when a user connects to the VPN.
  • disconnect: Triggered when a user disconnects from the VPN.

The following entity models are supported for webhook events:

  • user: WireGuard Portal users support creation, update, or deletion events.
  • peer: Peers support creation, update, or deletion events. Via the peer_metric entity, you can also receive connection status updates.
  • peer_metric: Peer metrics support connection status updates, such as when a peer connects or disconnects.
  • interface: WireGuard interfaces support creation, update, or deletion events.

Payload Structure

All webhook events send a JSON payload containing relevant data. The structure of the payload depends on the event type and entity involved. A common shell structure for webhook payloads is as follows:

{
  "event": "create", // The event type, e.g. "create", "update", "delete", "connect", "disconnect"
  "entity": "user",  // The entity type, e.g. "user", "peer", "peer_metric", "interface"
  "identifier": "the-user-identifier", // Unique identifier of the entity, e.g. user ID or peer ID
  "payload": {
    // The payload of the event, e.g. a Peer model.
    // Detailed model descriptions are provided below.
  }
}

Payload Models

All payload models are encoded as JSON objects. Fields with empty values might be omitted in the payload.

User Payload (entity: user)

JSON Field Type Description
CreatedBy string Creator identifier
UpdatedBy string Last updater identifier
CreatedAt time.Time Time of creation
UpdatedAt time.Time Time of last update
Identifier string Unique user identifier
Email string User email
Source string Authentication source
ProviderName string Name of auth provider
IsAdmin bool Whether user has admin privileges
Firstname string User's first name (optional)
Lastname string User's last name (optional)
Phone string Contact phone number (optional)
Department string User's department (optional)
Notes string Additional notes (optional)
Disabled *time.Time When user was disabled
DisabledReason string Reason for deactivation
Locked *time.Time When user account was locked
LockedReason string Reason for being locked

Peer Payload (entity: peer)

JSON Field Type Description
CreatedBy string Creator identifier
UpdatedBy string Last updater identifier
CreatedAt time.Time Creation timestamp
UpdatedAt time.Time Last update timestamp
Endpoint string Peer endpoint address
EndpointPublicKey string Public key of peer endpoint
AllowedIPsStr string Allowed IPs
ExtraAllowedIPsStr string Extra allowed IPs
PresharedKey string Pre-shared key for encryption
PersistentKeepalive int Keepalive interval in seconds
DisplayName string Display name of the peer
Identifier string Unique identifier
UserIdentifier string Associated user ID (optional)
InterfaceIdentifier string Interface this peer is attached to
Disabled *time.Time When the peer was disabled
DisabledReason string Reason for being disabled
ExpiresAt *time.Time Expiration date
Notes string Notes for this peer
AutomaticallyCreated bool Whether peer was auto-generated
PrivateKey string Peer private key
PublicKey string Peer public key
InterfaceType string Type of the peer interface
Addresses []string IP addresses
CheckAliveAddress string Address used for alive checks
DnsStr string DNS servers
DnsSearchStr string DNS search domains
Mtu int MTU (Maximum Transmission Unit)
FirewallMark uint32 Firewall mark (optional)
RoutingTable string Custom routing table (optional)
PreUp string Command before bringing up interface
PostUp string Command after bringing up interface
PreDown string Command before bringing down interface
PostDown string Command after bringing down interface

Interface Payload (entity: interface)

JSON Field Type Description
CreatedBy string Creator identifier
UpdatedBy string Last updater identifier
CreatedAt time.Time Creation timestamp
UpdatedAt time.Time Last update timestamp
Identifier string Unique identifier
PrivateKey string Private key for the interface
PublicKey string Public key for the interface
ListenPort int Listening port
Addresses []string IP addresses
DnsStr string DNS servers
DnsSearchStr string DNS search domains
Mtu int MTU (Maximum Transmission Unit)
FirewallMark uint32 Firewall mark
RoutingTable string Custom routing table
PreUp string Command before bringing up interface
PostUp string Command after bringing up interface
PreDown string Command before bringing down interface
PostDown string Command after bringing down interface
SaveConfig bool Whether to save config to file
DisplayName string Human-readable name
Type string Type of interface
DriverType string Driver used
Disabled *time.Time When the interface was disabled
DisabledReason string Reason for being disabled
PeerDefNetworkStr string Default peer network configuration
PeerDefDnsStr string Default peer DNS servers
PeerDefDnsSearchStr string Default peer DNS search domains
PeerDefEndpoint string Default peer endpoint
PeerDefAllowedIPsStr string Default peer allowed IPs
PeerDefMtu int Default peer MTU
PeerDefPersistentKeepalive int Default keepalive value
PeerDefFirewallMark uint32 Default firewall mark for peers
PeerDefRoutingTable string Default routing table for peers
PeerDefPreUp string Default peer pre-up command
PeerDefPostUp string Default peer post-up command
PeerDefPreDown string Default peer pre-down command
PeerDefPostDown string Default peer post-down command

Peer Metrics Payload (entity: peer_metric)

JSON Field Type Description
Status PeerStatus Current status of the peer
Peer Peer Peer data

PeerStatus sub-structure:

JSON Field Type Description
UpdatedAt time.Time Time of last status update
IsConnected bool Is peer currently connected
IsPingable bool Can peer be pinged
LastPing *time.Time Time of last successful ping
BytesReceived uint64 Bytes received from peer
BytesTransmitted uint64 Bytes sent to peer
Endpoint string Last known endpoint
LastHandshake *time.Time Last successful handshake
LastSessionStart *time.Time Time the last session began

Example Payloads

The following payload is an example of a webhook event when a peer connects to the VPN:

{
  "event": "connect",
  "entity": "peer_metric",
  "identifier": "Fb5TaziAs1WrPBjC/MFbWsIelVXvi0hDKZ3YQM9wmU8=",
  "payload": {
    "Status": {
      "UpdatedAt": "2025-06-27T22:20:08.734900034+02:00",
      "IsConnected": true,
      "IsPingable": false,
      "BytesReceived": 212,
      "BytesTransmitted": 2884,
      "Endpoint": "10.55.66.77:58756",
      "LastHandshake": "2025-06-27T22:19:46.580842776+02:00",
      "LastSessionStart": "2025-06-27T22:19:46.580842776+02:00"
    },
    "Peer": {
      "CreatedBy": "admin@wgportal.local",
      "UpdatedBy": "admin@wgportal.local",
      "CreatedAt": "2025-06-26T21:43:49.251839574+02:00",
      "UpdatedAt": "2025-06-27T22:18:39.67763985+02:00",
      "Endpoint": "10.55.66.1:51820",
      "EndpointPublicKey": "eiVibpi3C2PUPcx2kwA5s09OgHx7AEaKMd33k0LQ5mM=",
      "AllowedIPsStr": "10.11.12.0/24,fdfd:d3ad:c0de:1234::/64",
      "ExtraAllowedIPsStr": "",
      "PresharedKey": "p9DDeLUSLOdQcjS8ZsBAiqUzwDIUvTyzavRZFuzhvyE=",
      "PersistentKeepalive": 16,
      "DisplayName": "Peer Fb5TaziA",
      "Identifier": "Fb5TaziAs1WrPBjC/MFbWsIelVXvi0hDKZ3YQM9wmU8=",
      "UserIdentifier": "admin@wgportal.local",
      "InterfaceIdentifier": "wgTesting",
      "AutomaticallyCreated": false,
      "PrivateKey": "QBFNBe+7J49ergH0ze2TGUJMFrL/2bOL50Z2cgluYW8=",
      "PublicKey": "Fb5TaziAs1WrPBjC/MFbWsIelVXvi0hDKZ3YQM9wmU8=",
      "InterfaceType": "client",
      "Addresses": [
        "10.11.12.10/32",
        "fdfd:d3ad:c0de:1234::a/128"
      ],
      "CheckAliveAddress": "",
      "DnsStr": "",
      "DnsSearchStr": "",
      "Mtu": 1420
    }
  }
}

Here is another example of a webhook event when a peer is updated:

{
  "event": "update",
  "entity": "peer",
  "identifier": "Fb5TaziAs1WrPBjC/MFbWsIelVXvi0hDKZ3YQM9wmU8=",
  "payload": {
    "CreatedBy": "admin@wgportal.local",
    "UpdatedBy": "admin@wgportal.local",
    "CreatedAt": "2025-06-26T21:43:49.251839574+02:00",
    "UpdatedAt": "2025-06-27T22:18:39.67763985+02:00",
    "Endpoint": "10.55.66.1:51820",
    "EndpointPublicKey": "eiVibpi3C2PUPcx2kwA5s09OgHx7AEaKMd33k0LQ5mM=",
    "AllowedIPsStr": "10.11.12.0/24,fdfd:d3ad:c0de:1234::/64",
    "ExtraAllowedIPsStr": "",
    "PresharedKey": "p9DDeLUSLOdQcjS8ZsBAiqUzwDIUvTyzavRZFuzhvyE=",
    "PersistentKeepalive": 16,
    "DisplayName": "Peer Fb5TaziA",
    "Identifier": "Fb5TaziAs1WrPBjC/MFbWsIelVXvi0hDKZ3YQM9wmU8=",
    "UserIdentifier": "admin@wgportal.local",
    "InterfaceIdentifier": "wgTesting",
    "AutomaticallyCreated": false,
    "PrivateKey": "QBFNBe+7J49ergH0ze2TGUJMFrL/2bOL50Z2cgluYW8=",
    "PublicKey": "Fb5TaziAs1WrPBjC/MFbWsIelVXvi0hDKZ3YQM9wmU8=",
    "InterfaceType": "client",
    "Addresses": [
      "10.11.12.10/32",
      "fdfd:d3ad:c0de:1234::a/128"
    ],
    "CheckAliveAddress": "",
    "DnsStr": "",
    "DnsSearchStr": "",
    "Mtu": 1420
  }
}