Check a config without a key
const url = 'https://app.tunnelhq.com/api/v1/check/public';const options = { method: 'POST', headers: {'Content-Type': 'application/json'}, body: '{"url":"vless://<uuid>@sg-01.your-vpn.net:443?type=tcp&security=reality&sni=www.microsoft.com&pbk=<public-key>#sg-01"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://app.tunnelhq.com/api/v1/check/public \ --header 'Content-Type: application/json' \ --data '{ "url": "vless://<uuid>@sg-01.your-vpn.net:443?type=tcp&security=reality&sni=www.microsoft.com&pbk=<public-key>#sg-01" }'The free tester: tests one config from Any location, with no key. Limited to 5 requests per IP address per 24 hours, and every request counts, including ones refused for a bad config. Nothing is saved.
The fields are those of Create monitor:
a share link in url (or config), a config file in config, and host, username and
password where the protocol needs them. OpenVPN needs username and password here too.
The test may take 30 seconds. Private, loopback and cloud-metadata addresses are refused.
Request Bodyrequired
Section titled “Request Bodyrequired”object
A share link.
A share link or a config file.
Required unless the share link’s scheme gives it.
The engine for share links. Left out, the checker chooses.
Example
{ "url": "vless://<uuid>@sg-01.your-vpn.net:443?type=tcp&security=reality&sni=www.microsoft.com&pbk=<public-key>#sg-01"}Responses
Section titled “ Responses ”The test ran.
object
An ID for this check. It can’t be looked up.
true when the protocol came from a share link.
When the check started, in ISO 8601 UTC.
When the tunnel came up: its own address if it has one (WireGuard, IKEv2), otherwise the public address traffic left from (share links).
The checker’s own description of the failure. The wording varies.
The kind of failure, such as server_not_connected, internet_stuck, timeout, auth_failed, cert_error, or config_error.
The engine that ran a share-link check: xray or singbox.
Checks this IP address has left in the 24 hours.
Example
{ "test_id": "chk_muh251s09f41c07d2e", "status": "healthy", "protocol": "vless", "config_detected": true, "tested_at": "2026-09-25T14:30:00.000Z", "latency_ms": 162, "connection_time_ms": 410, "handshake_time_ms": 120, "assigned_ip": "198.51.100.20", "error_message": null, "error_category": null, "engine_used": "xray", "remaining_checks": 4}The protocol or engine is missing or unknown.
object
The HTTP status, repeated.
What went wrong.
More detail, on some errors.
Seconds to wait, on the 429 for wrong keys.
Examples
{ "error": true, "code": 400, "message": "Missing 'protocol' field. Supported: vless, vmess, trojan, shadowsocks, hysteria2, tuic, wireguard, amneziawg, openvpn, openconnect, ikev2."}{ "error": true, "code": 400, "message": "Unsupported engine 'fast'. Supported: singbox, xray, auto, both, race."}A configuration field is longer than its limit.
object
The HTTP status, repeated.
What went wrong.
More detail, on some errors.
Seconds to wait, on the 429 for wrong keys.
Example
{ "error": true, "code": 413, "message": "Field 'password' exceeds max length (4096 bytes). Got 5000 bytes."}The config can’t be used, or its host isn’t allowed.
object
The HTTP status, repeated.
What went wrong.
More detail, on some errors.
Seconds to wait, on the 429 for wrong keys.
Examples
{ "error": true, "code": 422, "message": "OpenVPN requires 'username' and 'password' (even if the config has auth-user-pass, credentials must be provided)."}{ "error": true, "code": 422, "message": "Could not determine the target host from that config. The public tester needs a config it can read; sign in and use /api/v1/check for anything more exotic."}{ "error": true, "code": 422, "message": "Host '127.0.0.1' is not allowed on the public check endpoint. Sign in and use /api/v1/check to test loopback or cloud metadata hosts."}{ "error": true, "code": 422, "message": "Host 'sg-01.your-vpn.nett' could not be resolved. Check the address for a typo — the public tester needs a host that resolves publicly."}This IP address has used its 5 checks for the last 24 hours.
object
Seconds.
Example
{ "error": "Rate limit exceeded. Max 5 checks per IP per 24 hours. Sign up for unlimited access.", "remaining": 0, "retry_after": 86400}TunnelHQ’s checker couldn’t be reached.
object
The HTTP status, repeated.
What went wrong.
More detail, on some errors.
Seconds to wait, on the 429 for wrong keys.
Example
{ "error": true, "code": 502, "message": "VPN checker unreachable: timeout of 35000ms exceeded"}No checker is available.
object
The HTTP status, repeated.
What went wrong.
More detail, on some errors.
Seconds to wait, on the 429 for wrong keys.
Example
{ "error": true, "code": 503, "message": "No VPN checker nodes available. Try again shortly."}