VPN Gateways API
Site-to-site VPN gateway management.
List VPN gateways
GET /api/v1/vpn-gatewaysconst { data: gateways } = await puchify.vpnGateways.list({ status: "active" })gateways = puchify.vpn_gateways.list(status="active")gateways, err := client.VPNGateways.List(ctx, &puchify.VPNGatewayListParams{
Status: puchify.String("active"),
})puchify vpn list --status activecurl https://api.puchify.com/api/v1/vpn-gateways \
-H "Authorization: Bearer $PUCHIFY_API_KEY"Query parameters:
| Parameter | Type | Description |
|---|---|---|
cursor | string | Pagination cursor |
limit | integer (1-100) | Results per page (default 50) |
status | string | Filter by status (creating, active, deleting, deleted) |
sort | name | created_at | Sort field |
order | asc | desc | Sort direction |
Create a VPN gateway
POST /api/v1/vpn-gatewaysconst { data: gateway } = await puchify.vpnGateways.create({
name: "site-a-vpn",
region: "us-east",
tunnel_type: "ipsec",
remote_network_cidr: "10.0.0.0/16",
remote_peer_ip: "203.0.113.200",
pre_shared_key: "•••••••••••",
})gateway = puchify.vpn_gateways.create(
name="site-a-vpn",
region="us-east",
tunnel_type="ipsec",
remote_network_cidr="10.0.0.0/16",
remote_peer_ip="203.0.113.200",
pre_shared_key="•••••••••••",
)gateway, err := client.VPNGateways.Create(ctx, &puchify.CreateVPNGatewayInput{
Name: "site-a-vpn", Region: "us-east",
TunnelType: puchify.String("ipsec"),
RemoteNetworkCIDR: "10.0.0.0/16",
RemotePeerIP: "203.0.113.200",
PreSharedKey: "•••••••••••",
})puchify vpn create --name site-a-vpn --region us-east \
--tunnel-type ipsec --remote-cidr 10.0.0.0/16 --remote-ip 203.0.113.200curl -X POST https://api.puchify.com/api/v1/vpn-gateways \
-H "Authorization: Bearer $PUCHIFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"site-a-vpn","region":"us-east","tunnel_type":"ipsec","remote_network_cidr":"10.0.0.0/16","remote_peer_ip":"203.0.113.200","pre_shared_key":"•••••••••••"}'Request body:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Gateway name (2-40 chars) |
region | string | yes | Region ID |
tunnel_type | ipsec | wireguard | yes | VPN tunnel protocol |
remote_network_cidr | string | yes | Remote network CIDR block (e.g., 10.0.0.0/16) |
remote_peer_ip | string | yes | Public IP of the remote VPN peer |
pre_shared_key | string | no | PSK for IPsec (auto-generated if omitted) |
local_network_cidr | string | no | Local network CIDR (defaults to the VPC CIDR) |
Get a VPN gateway
GET /api/v1/vpn-gateways/{id}const { data: gateway } = await puchify.vpnGateways.get("vpn_abc123")gateway = puchify.vpn_gateways.get("vpn_abc123")gateway, err := client.VPNGateways.Get(ctx, "vpn_abc123")puchify vpn get vpn_abc123curl https://api.puchify.com/api/v1/vpn-gateways/vpn_abc123 \
-H "Authorization: Bearer $PUCHIFY_API_KEY"Update a VPN gateway
PATCH /api/v1/vpn-gateways/{id}const { data: gateway } = await puchify.vpnGateways.update("vpn_abc123", {
remote_network_cidr: "10.1.0.0/16",
})gateway = puchify.vpn_gateways.update("vpn_abc123", remote_network_cidr="10.1.0.0/16")gateway, err := client.VPNGateways.Update(ctx, "vpn_abc123", &puchify.UpdateVPNGatewayInput{
RemoteNetworkCIDR: puchify.String("10.1.0.0/16"),
})puchify vpn update vpn_abc123 --remote-cidr 10.1.0.0/16curl -X PATCH https://api.puchify.com/api/v1/vpn-gateways/vpn_abc123 \
-H "Authorization: Bearer $PUCHIFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"remote_network_cidr":"10.1.0.0/16"}'Request body:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | no | New gateway name |
remote_network_cidr | string | no | Updated remote CIDR block |
pre_shared_key | string | no | Rotate the pre-shared key |
Delete a VPN gateway
DELETE /api/v1/vpn-gateways/{id}await puchify.vpnGateways.delete("vpn_abc123")puchify.vpn_gateways.delete("vpn_abc123")err := client.VPNGateways.Delete(ctx, "vpn_abc123")puchify vpn delete vpn_abc123curl -X DELETE https://api.puchify.com/api/v1/vpn-gateways/vpn_abc123 \
-H "Authorization: Bearer $PUCHIFY_API_KEY"Get tunnel status
GET /api/v1/vpn-gateways/{id}/statusconst { data: status } = await puchify.vpnGateways.getStatus("vpn_abc123")status = puchify.vpn_gateways.get_status("vpn_abc123")status, err := client.VPNGateways.GetStatus(ctx, "vpn_abc123")puchify vpn status vpn_abc123curl https://api.puchify.com/api/v1/vpn-gateways/vpn_abc123/status \
-H "Authorization: Bearer $PUCHIFY_API_KEY"Returns live tunnel status including up/down state, bytes transferred, and last handshake time.
Polling for readiness
const gateway = await puchify.vpnGateways.waitFor("vpn_abc123", "active", {
timeout: 300_000,
pollInterval: 5_000,
})gateway = puchify.vpn_gateways.wait_for("vpn_abc123", "active", timeout=300)gateway, err := puchify.WaitFor(ctx, client.VPNGateways.Get, "vpn_abc123", "active",
puchify.WithTimeout(5*time.Minute),
)Response shape
{
"data": {
"id": "vpn_abc123",
"name": "site-a-vpn",
"status": "active", // creating | active | deleting | deleted
"region": "us-east",
"tunnel_type": "ipsec",
"local_network_cidr": "172.16.0.0/16",
"remote_network_cidr": "10.0.0.0/16",
"remote_peer_ip": "203.0.113.200",
"local_ip": "203.0.113.150",
"tunnel_status": "up",
"bytes_sent": 104857600,
"bytes_received": 52428800,
"last_handshake": "2026-05-28T10:35:00Z",
"created_at": "2026-05-28T10:30:00Z",
"updated_at": "2026-05-28T10:32:00Z"
},
"meta": {
"persistence": "synced",
"provider": "connected"
}
}Error codes
| Code | Description |
|---|---|
404 | VPN gateway not found |
409 | Conflict — gateway is in a transient state (e.g., provisioning or deleting) |
422 | Invalid CIDR block, peer IP, or tunnel type |