Errors#

This guide covers all error codes returned by the VPN Signal API and how to handle them in your application.

Error Response Format#

All errors follow a consistent JSON structure:

json
{
  "error": "error_code",
  "message": "Human-readable description of the error",
  "details": {
    "field": "additional context"
  }
}
FieldTypeDescription
errorstringMachine-readable error code
messagestringHuman-readable description
detailsobjectAdditional context (optional)

HTTP Status Codes#

400 Bad Request#

The request was malformed or contained invalid data.

invalid_ip

json
{
  "error": "invalid_ip",
  "message": "The provided IP address is not valid",
  "details": {
    "ip": "not.an.ip",
    "expected": "Valid IPv4 or IPv6 address"
  }
}

Fix: Ensure the IP address is a valid IPv4 (e.g., 192.168.1.1) or IPv6 (e.g., 2001:db8::1) format.


missing_ip

json
{
  "error": "missing_ip",
  "message": "IP address is required",
  "details": {}
}

Fix: Include the ip field in your request body.


invalid_json

json
{
  "error": "invalid_json",
  "message": "Request body must be valid JSON",
  "details": {}
}

Fix: Ensure your request body is valid JSON and the Content-Type header is application/json.


401 Unauthorized#

Authentication failed or API key is missing.

unauthorized

json
{
  "error": "unauthorized",
  "message": "Invalid or missing API key",
  "details": {}
}

Fix: Include a valid API key in the Authorization header:

Authorization: Bearer sk_live_your_key_here

invalid_api_key

json
{
  "error": "invalid_api_key",
  "message": "The API key provided is invalid or has been revoked",
  "details": {}
}

Fix: Check that your API key is correct and hasn't been revoked in the dashboard.


403 Forbidden#

The API key is valid but doesn't have permission for this action.

forbidden

json
{
  "error": "forbidden",
  "message": "API key does not have access to this resource",
  "details": {}
}

Fix: Verify your API key has the correct permissions or upgrade your plan.


429 Too Many Requests#

You've exceeded your rate limit.

rate_limit_exceeded

json
{
  "error": "rate_limit_exceeded",
  "message": "Daily request limit exceeded",
  "details": {
    "limit": 100,
    "reset_at": "2024-01-15T00:00:00Z"
  }
}

Headers included:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1705276800
Retry-After: 3600

Fix: Wait until the reset time or upgrade your plan for higher limits.


500 Internal Server Error#

An unexpected error occurred on our servers.

internal_error

json
{
  "error": "internal_error",
  "message": "An unexpected error occurred",
  "details": {
    "request_id": "req_abc123"
  }
}

Fix: Retry the request. If the error persists, contact support with the request_id.


503 Service Unavailable#

The service is temporarily unavailable.

service_unavailable

json
{
  "error": "service_unavailable",
  "message": "Service temporarily unavailable",
  "details": {
    "retry_after": 30
  }
}

Fix: Wait and retry. The retry_after value indicates seconds to wait.


Error Handling Examples#

JavaScript / TypeScript#

javascript
async function checkIP(ip) {
  try {
    const response = await fetch('https://vpnsignal.io/api/v1/check', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ ip }),
    });

    if (!response.ok) {
      const error = await response.json();

      switch (response.status) {
        case 400:
          throw new Error(`Invalid request: ${error.message}`);
        case 401:
          throw new Error('Invalid API key');
        case 429:
          const retryAfter = response.headers.get('Retry-After');
          throw new Error(`Rate limited. Retry after ${retryAfter}s`);
        default:
          throw new Error(`API error: ${error.message}`);
      }
    }

    return response.json();
  } catch (error) {
    console.error('VPN Signal error:', error);
    throw error;
  }
}

Python#

python
import requests
from requests.exceptions import HTTPError

def check_ip(ip):
    try:
        response = requests.post(
            'https://vpnsignal.io/api/v1/check',
            headers={
                'Authorization': f'Bearer {API_KEY}',
                'Content-Type': 'application/json',
            },
            json={'ip': ip},
        )
        response.raise_for_status()
        return response.json()

    except HTTPError as e:
        error_data = e.response.json()

        if e.response.status_code == 429:
            retry_after = e.response.headers.get('Retry-After', 60)
            raise Exception(f'Rate limited. Retry after {retry_after}s')
        elif e.response.status_code == 401:
            raise Exception('Invalid API key')
        else:
            raise Exception(f"API error: {error_data['message']}")

Retry Logic with Exponential Backoff#

javascript
async function checkIPWithRetry(ip, maxRetries = 3) {
  let lastError;

  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await checkIP(ip);
    } catch (error) {
      lastError = error;

      // Don't retry client errors (4xx)
      if (error.status >= 400 && error.status < 500) {
        throw error;
      }

      // Exponential backoff: 1s, 2s, 4s
      const delay = Math.pow(2, attempt) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }

  throw lastError;
}

Common Issues#

"Invalid API key" but key looks correct#

Tip

Check for extra whitespace or newline characters in your API key. Copy it fresh from the dashboard.

Rate limit hit unexpectedly#

  • Check if multiple services are using the same API key
  • Consider using separate keys for development and production
  • Monitor usage in the dashboard

Intermittent 500 errors#

  • Implement retry logic with exponential backoff
  • Check status.vpnsignal.io for outages
  • Contact support if errors persist

Need Help?#

If you're experiencing issues not covered here:

  1. Check the API Reference for correct usage
  2. Review your usage dashboard for patterns
  3. Contact support with your request_id for specific errors

Next Steps#