PublicVPNList API v1

Read the current prebuilt snapshot of technically checked public OpenVPN endpoints. API responses never build the catalog or run a VPN check in the request.

Important: PublicVPNList does not operate these third-party servers. A successful technical check does not guarantee privacy, identity, operator trust, logging practices or future availability.

Quick start

Use the versioned /api/v1/ paths. Respect 429, apply backoff, cache the ETag, and check both expires_at and each record’s last_checked_at.

EndpointPurpose
GET /api/v1/serversFilter, sort and paginate server records
GET /api/v1/servers/{public_id}One record by stable public ID
GET /api/v1/countriesAvailable countries and counts
GET /api/v1/protocolsPublished protocols and transports
GET /api/v1/statsSnapshot counters
GET /api/v1/datasetVersion, lifecycle and export links
GET /api/v1/healthLightweight snapshot health
curl -H 'Accept: application/json' \
  'https://publicvpnlist.com/api/v1/servers?country=JP&transport=udp&min_speed=20&sort=speed&order=desc&per_page=50'
Result will appear here.

Filters and pagination

ParameterAccepted value
countryTwo-letter ISO code, for example US
protocolopenvpn
transporttcp or udp
port1–65535
fresh_withinAge in seconds, 1–259200
min_speed, max_latency, min_uptimeNumeric technical filters; unknown uptime is null
statusonline means online at the last technical check
sortspeed, latency, uptime, last_checked, score, first_seen
orderasc or desc
page, per_pageDefault 1 / 50; maximum page size 200
fieldsComma-separated public fields
formatjson

Examples

PHP

$url = 'https://publicvpnlist.com/api/v1/servers?country=US&per_page=10';
$data = json_decode(file_get_contents($url), true);

Python

import requests
r = requests.get('https://publicvpnlist.com/api/v1/servers', params={'country': 'US'}, timeout=15)
r.raise_for_status()
print(r.json()['data'])

JavaScript

const response = await fetch('https://publicvpnlist.com/api/v1/stats');
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const payload = await response.json();

Record fields

FieldsMeaning
idStable public endpoint ID; never a Bitrix element ID.
country_code, country_name, cityPublished location metadata. Unknown or unverified city is null.
hostname, ip, protocol, transport, portPublic connection endpoint metadata allowed by the catalog policy.
speed_mbps, latency_msRepresentative measurements from the PublicVPNList checker region, not a client-side guarantee.
uptime_percent_7d, uptime_hours, sessionsnull until a matching trustworthy measurement window exists; values are never invented.
technical_quality_score, score_labelReachability/performance/freshness signal. It is not a privacy, identity or trust assessment.
last_checked_at, first_seen_at, config_updated_atUTC ISO 8601 timestamps; unknown config-update time is null.
freshness_status, availability_statusSnapshot-relative freshness and state at the last technical check.
source_name, source_urlUpstream attribution.
server_page_url, config_download_urlPublic detail/download location where permitted. Config URL remains null to preserve the existing live-check and one-time-token flow.
risk_flags, config_sha256Non-secret caution flags and a content hash where available; no configuration content is returned.

HTTP behavior

  • Free API limit: 60 requests per minute per short-lived keyed IP hash; health has a separate 12/minute limit.
  • 400 invalid parameter, 404 unknown endpoint/record, 405 method, 429 rate limit, 500 safe internal error.
  • Use ETag or Last-Modified; unchanged GET/HEAD requests return 304.
  • CORS allows public GET/HEAD without credentials. Duplicate query parameters are rejected.
  • Technical quality score is not a privacy, identity or trust assessment.

See the exact machine-readable contract in OpenAPI JSON and stable files on the exports page.

Changelog and migration policy

v1.0 — July 28, 2026: stable public IDs, strict filters, pagination, conditional caching, rate-limit headers and snapshot exports.

The earlier multiprotocol preview remains temporarily available on its old specialist routes and with ?legacy=1 for list routes. New integrations should use the documented dataset response; legacy compatibility may be retired only after a published migration window.

Breaking changes require a new versioned path. Additive fields may appear in v1; integrations should ignore unknown fields. A deprecated major version will be documented before removal.

Acceptable use: cache results, avoid scraping HTML, do not use the service to conceal abuse, and report unwanted or incorrect endpoint listings through contact/takedown.