API Reference#

Complete reference for the VPN Signal API endpoints.

Base URL#

Production: https://vpnsignal.io/api/v1

Check IP#

Check if an IP address is associated with a VPN, Proxy, Tor, or hosting provider.

Endpoint#

POST /check

Headers#

HeaderRequiredDescription
AuthorizationYesBearer token with your API key
Content-TypeYesMust be application/json

Request Body#

json
{
  "ip": "1.1.1.1"
}
FieldTypeRequiredDescription
ipstringYesIPv4 or IPv6 address to check

Response#

json
{
  "ip": "1.1.1.1",
  "is_vpn": false,
  "is_proxy": false,
  "is_tor": false,
  "is_relay": false,
  "is_hosting": true,
  "risk_score": 30,
  "recommendation": "allow",
  "company": {
    "name": "Cloudflare, Inc.",
    "type": "hosting",
    "domain": "cloudflare.com"
  },
  "location": {
    "country": "US",
    "country_name": "United States",
    "city": "San Francisco",
    "region": "California",
    "latitude": 37.7749,
    "longitude": -122.4194
  },
  "asn": {
    "number": 13335,
    "name": "CLOUDFLARENET",
    "route": "1.1.1.0/24"
  }
}

Response Fields#

FieldTypeDescription
ipstringThe IP address that was checked
is_vpnbooleanTrue if IP belongs to a VPN provider
is_proxybooleanTrue if IP is a known proxy server
is_torbooleanTrue if IP is a Tor exit node
is_relaybooleanTrue if IP is an iCloud Private Relay
is_hostingbooleanTrue if IP is from a hosting/datacenter
risk_scoreintegerRisk score from 0-100
recommendationstringallow, verify, or block
companyobjectCompany information (if available)
locationobjectGeographic location data
asnobjectAutonomous System Number data

Note

Some fields like company, location, and asn may be null if the data is not available.

Example Request#

bash
curl -X POST https://vpnsignal.io/api/v1/check \
  -H "Authorization: Bearer sk_live_abc123..." \
  -H "Content-Type: application/json" \
  -d '{"ip": "104.28.231.47"}'

Health Check#

Check if the API is running and healthy.

Endpoint#

GET /health

Headers#

No authentication required.

Response#

json
{
  "status": "healthy"
}

Error Responses#

All errors follow a consistent format:

json
{
  "error": "error_code",
  "message": "Human-readable description",
  "details": {}
}
HTTP CodeError CodeDescription
400invalid_ipThe IP address format is invalid
401unauthorizedMissing or invalid API key
403forbiddenAPI key doesn't have access
429rate_limit_exceededDaily limit exceeded
500internal_errorServer error

See Error Handling for detailed troubleshooting.


SDK Examples#

Node.js#

javascript
class VPNSignal {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.baseUrl = 'https://vpnsignal.io/api/v1';
  }

  async checkIP(ip) {
    const response = await fetch(`${this.baseUrl}/check`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${this.apiKey}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ ip }),
    });

    if (!response.ok) {
      const error = await response.json();
      throw new Error(error.message);
    }

    return response.json();
  }
}

// Usage
const vpn = new VPNSignal('sk_live_abc123...');
const result = await vpn.checkIP('1.1.1.1');

Python#

python
import requests

class VPNSignal:
    def __init__(self, api_key):
        self.api_key = api_key
        self.base_url = 'https://vpnsignal.io/api/v1'

    def check_ip(self, ip):
        response = requests.post(
            f'{self.base_url}/check',
            headers={
                'Authorization': f'Bearer {self.api_key}',
                'Content-Type': 'application/json',
            },
            json={'ip': ip},
        )
        response.raise_for_status()
        return response.json()

# Usage
vpn = VPNSignal('sk_live_abc123...')
result = vpn.check_ip('1.1.1.1')

Rate Limits#

Rate limits are applied per API key:

PlanDaily LimitPer-Second Limit
Free1001
Starter10,00010
Pro100,00050
EnterpriseUnlimited100

Rate limit headers are included in every response:

X-RateLimit-Limit: 10000
X-RateLimit-Remaining: 9523
X-RateLimit-Reset: 1640995200

Next Steps#