curl --request GET \
--url https://closedvpn.io/auth/threat-prevention-stats \
--header 'Authorization: Bearer <token>'import requests
url = "https://closedvpn.io/auth/threat-prevention-stats"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://closedvpn.io/auth/threat-prevention-stats', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://closedvpn.io/auth/threat-prevention-stats",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://closedvpn.io/auth/threat-prevention-stats"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://closedvpn.io/auth/threat-prevention-stats")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://closedvpn.io/auth/threat-prevention-stats")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"success": true,
"message": "No organization selected",
"data": {
"stats": {
"totalConnections": 15432,
"threatsBlocked": 127,
"riskScore": 8.23,
"protectedUsers": 5
},
"latestEvents": [
{
"user": "john",
"connection": "192.168.1.1 -> 10.0.0.1",
"status": "blocked",
"events": 12,
"lastTime": "2025-06-15T10:30:00"
}
],
"timeSeriesData": [
{
"date": "2025-06-15T10:00:00",
"total": 500,
"prevented": 15
}
],
"preventedByCountry": [
{
"country": "CN",
"count": 45
}
],
"protectionByUser": [
{
"name": "john",
"value": 32
}
]
}
}{
"message": "Unauthorized"
}{
"success": false,
"message": "User not found"
}{
"success": false,
"message": "Server error"
}Threat Prevention Stats
Returns threat prevention dashboard data including total connections, threats blocked, risk score, latest events, and geographic breakdown. Uses the selected organization or org_id query parameter.
curl --request GET \
--url https://closedvpn.io/auth/threat-prevention-stats \
--header 'Authorization: Bearer <token>'import requests
url = "https://closedvpn.io/auth/threat-prevention-stats"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://closedvpn.io/auth/threat-prevention-stats', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://closedvpn.io/auth/threat-prevention-stats",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://closedvpn.io/auth/threat-prevention-stats"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://closedvpn.io/auth/threat-prevention-stats")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://closedvpn.io/auth/threat-prevention-stats")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"success": true,
"message": "No organization selected",
"data": {
"stats": {
"totalConnections": 15432,
"threatsBlocked": 127,
"riskScore": 8.23,
"protectedUsers": 5
},
"latestEvents": [
{
"user": "john",
"connection": "192.168.1.1 -> 10.0.0.1",
"status": "blocked",
"events": 12,
"lastTime": "2025-06-15T10:30:00"
}
],
"timeSeriesData": [
{
"date": "2025-06-15T10:00:00",
"total": 500,
"prevented": 15
}
],
"preventedByCountry": [
{
"country": "CN",
"count": 45
}
],
"protectionByUser": [
{
"name": "john",
"value": 32
}
]
}
}{
"message": "Unauthorized"
}{
"success": false,
"message": "User not found"
}{
"success": false,
"message": "Server error"
}Authorizations
Personal Access Token (PAT) passed in the Authorization header (e.g., Bearer <pat>) for authenticated API requests. PATs are generated via /auth/generate-pat after authenticating through the magic link flow.
Query Parameters
Organization ID (falls back to user's selected organization if not provided)
"60c72b2f5f1b2c001c8e4b1a"
Response
Threat prevention stats retrieved
true
Present only when the returned data is empty, explaining why. One of "No organization selected", "No VPN configuration found for selected org", "VPN configuration not found", "VPN private config not available", or "No log data available".
"No organization selected"
Show child attributes
Show child attributes

