Published

πŸ“‘ API Documentation

πŸ“‘ API Documentation

This document describes all API endpoints available in the Tokyo VPN Speed Monitor system.


Base URLs

After deploying the Google Apps Script projects as Web Apps, you'll have two base URLs:

Main Project:    https://script.google.com/macros/s/{MAIN_DEPLOYMENT_ID}/exec
Trust Project:   https://script.google.com/macros/s/{TRUST_DEPLOYMENT_ID}/exec

Main Project Endpoints

1. Speed Ranking

Get the latest speed ranking for all monitored VPNs.

Endpoint:

GET ?type=ranking

Response:

{
  "lastUpdate": "2026-01-21T10:00:00.000Z",
  "region": "JP",
  "regionName": "ζ—₯ζœ¬οΌˆζ±δΊ¬οΌ‰",
  "updateInterval": "6時間ごと",
  "vpnCount": 15,
  "data": [
    {
      "timestamp": "2026-01-21T10:00:00.000Z",
      "name": "NordVPN",
      "download": 485.2,
      "upload": 312.5,
      "ping": 12.3,
      "stability": 87,
      "reliability": 98,
      "totalScore": 97.8,
      "rank": 1,
      "stabilityScore7d": 94.5
    },
    {
      "timestamp": "2026-01-21T10:00:00.000Z",
      "name": "ExpressVPN",
      "download": 452.1,
      "upload": 298.4,
      "ping": 15.2,
      "stability": 88,
      "reliability": 97,
      "totalScore": 95.2,
      "rank": 2,
      "stabilityScore7d": 92.3
    }
  ]
}

Fields:

FieldTypeDescription
lastUpdateISO DateLast measurement timestamp
regionStringRegion code (JP)
regionNameStringRegion name in Japanese
updateIntervalStringMeasurement frequency
vpnCountNumberNumber of VPNs in ranking
data[].nameStringVPN service name
data[].downloadNumberDownload speed (Mbps)
data[].uploadNumberUpload speed (Mbps)
data[].pingNumberLatency (ms)
data[].stabilityNumberInstant stability score (0-100)
data[].reliabilityNumberConnection reliability (%)
data[].totalScoreNumberOverall score (0-100)
data[].rankNumberCurrent ranking position
data[].stabilityScore7dNumber7-day stability score

2. Stability Scores

Get detailed stability analysis based on 7-day historical data.

Endpoint:

GET ?type=stability

Response:

{
  "region": "JP",
  "regionName": "ζ—₯ζœ¬οΌˆζ±δΊ¬οΌ‰",
  "period": "過去7ζ—₯ι–“",
  "lastUpdate": "2026-01-21T10:00:00.000Z",
  "data": [
    {
      "name": "NordVPN",
      "stabilityScore": 94.5,
      "avgSpeed": 480,
      "speedStdDev": 15.2,
      "avgPing": 12.5,
      "pingStdDev": 2.1,
      "reliability": 98.0,
      "dataPoints": 28
    }
  ]
}

Fields:

FieldTypeDescription
data[].stabilityScoreNumberCalculated stability (0-100)
data[].avgSpeedNumberAverage download speed (Mbps)
data[].speedStdDevNumberSpeed standard deviation
data[].avgPingNumberAverage latency (ms)
data[].pingStdDevNumberLatency standard deviation
data[].reliabilityNumberAverage reliability (%)
data[].dataPointsNumberNumber of measurements

3. Price Data

Get the latest pricing information for all VPNs.

Endpoint:

GET ?action=getPricing

Response:

{
  "success": true,
  "lastUpdate": "2026-01-21T09:00:00.000Z",
  "count": 15,
  "data": [
    {
      "name": "NordVPN",
      "price": 370,
      "currency": "JPY",
      "lastUpdate": "2026-01-21T09:00:00.000Z",
      "isFallback": false,
      "method": "scraperapi"
    },
    {
      "name": "ExpressVPN",
      "price": 524,
      "currency": "JPY",
      "lastUpdate": "2026-01-21T09:00:00.000Z",
      "isFallback": false,
      "method": "direct"
    }
  ]
}

Fields:

FieldTypeDescription
data[].priceNumberMonthly price
data[].currencyStringCurrency code (JPY, USD, EUR)
data[].isFallbackBooleanWhether fallback price was used
data[].methodStringScraping method used

Trust Score Project Endpoints

4. Trust Scores

Get privacy and transparency scores for all VPNs.

Endpoint:

GET ?action=getTrustScores

Response:

{
  "success": true,
  "lastUpdate": "2026-01-01T10:00:00.000Z",
  "count": 15,
  "data": [
    {
      "vpnName": "Mullvad",
      "headquarters": "スウェーデン",
      "scores": {
        "noLogPolicy": 5,
        "thirdPartyAudit": 5,
        "transparencyReport": 4,
        "jurisdiction": 3,
        "dataRetention": 5,
        "openSource": 5,
        "ramOnlyServers": 5,
        "incidentResponse": 5,
        "legalResponse": 5,
        "operatingYears": 5
      },
      "totalScore": 92,
      "grade": "A",
      "lastUpdate": "2026-01-01T10:00:00.000Z"
    }
  ]
}

Score Fields (1-5 scale):

FieldMax PointsDescription
noLogPolicy5No-log policy clarity and verification
thirdPartyAudit5Independent security audits
transparencyReport5Transparency report publication
jurisdiction5Privacy-friendly jurisdiction
dataRetention5Data retention policy
openSource5Open source status
ramOnlyServers5RAM-only server infrastructure
incidentResponse5Security incident handling
legalResponse5Response to legal requests
operatingYears5Track record length

Grade Scale:

GradeScore Range
A85-100
B70-84
C55-69
D40-54
F0-39

5. Integrated Ranking

Get combined ranking with speed, price, and trust scores.

Endpoint:

GET ?action=getIntegrated

Response:

{
  "success": true,
  "lastUpdate": "2026-01-21T10:00:00.000Z",
  "count": 15,
  "weights": {
    "trust": "30%",
    "speed": "30%",
    "price": "20%",
    "stability": "20%"
  },
  "data": [
    {
      "rank": 1,
      "vpnName": "NordVPN",
      "headquarters": "γƒ‘γƒŠγƒž",
      "trustScore": 85,
      "trustGrade": "A",
      "downloadSpeed": 485,
      "uploadSpeed": 312,
      "ping": 12,
      "speedScore": 97.8,
      "stabilityScore": 94.5,
      "price": 370,
      "currency": "JPY",
      "priceScore": 87,
      "integratedScore": 91
    }
  ]
}

6. VPN Detail

Get detailed information for a specific VPN.

Endpoint:

GET ?action=getVPNDetail&vpn={VPN_NAME}

Example:

GET ?action=getVPNDetail&vpn=NordVPN

Response:

{
  "success": true,
  "data": {
    "vpnName": "NordVPN",
    "headquarters": "γƒ‘γƒŠγƒž",
    "scores": {
      "noLogPolicy": 5,
      "thirdPartyAudit": 5,
      "transparencyReport": 4,
      "jurisdiction": 5,
      "dataRetention": 5,
      "openSource": 3,
      "ramOnlyServers": 5,
      "incidentResponse": 4,
      "legalResponse": 5,
      "operatingYears": 4
    },
    "totalScore": 85,
    "grade": "A",
    "jurisdictionInfo": {
      "fiveEyes": false,
      "nineEyes": false,
      "fourteenEyes": false,
      "dataRetention": "γͺし",
      "score": 5
    },
    "lastUpdate": "2026-01-01T10:00:00.000Z"
  }
}

7. Jurisdiction Database

Get the complete jurisdiction database.

Endpoint:

GET ?action=getJurisdiction

Response:

{
  "success": true,
  "count": 12,
  "data": [
    {
      "country": "γƒ‘γƒŠγƒž",
      "fiveEyes": false,
      "nineEyes": false,
      "fourteenEyes": false,
      "dataRetention": "γͺし",
      "score": 5
    },
    {
      "country": "をパγƒͺγ‚«",
      "fiveEyes": true,
      "nineEyes": true,
      "fourteenEyes": true,
      "dataRetention": "γ‚γ‚Š",
      "score": 1
    }
  ]
}

Error Responses

All endpoints return errors in this format:

{
  "success": false,
  "error": "Error message",
  "message": "Human-readable description"
}

Common Errors:

ErrorDescription
No data availableRun measurement/scraping first
VPN not foundInvalid VPN name parameter
Invalid type parameterUnknown endpoint type
Unknown actionInvalid action parameter

Rate Limits

  • Google Apps Script: 20,000 calls/day per user
  • No artificial rate limits imposed
  • Recommended: Cache responses for 5+ minutes

CORS

All endpoints support CORS and can be called from any domain.


Usage Examples

JavaScript (Fetch)

// Get speed ranking
fetch('https://script.google.com/macros/s/YOUR_ID/exec?type=ranking')
  .then(response => response.json())
  .then(data => console.log(data));

// Get trust scores
fetch('https://script.google.com/macros/s/YOUR_TRUST_ID/exec?action=getTrustScores')
  .then(response => response.json())
  .then(data => console.log(data));

Python (Requests)

import requests

# Get speed ranking
response = requests.get('https://script.google.com/macros/s/YOUR_ID/exec?type=ranking')
data = response.json()
print(data)

# Get integrated ranking
response = requests.get('https://script.google.com/macros/s/YOUR_TRUST_ID/exec?action=getIntegrated')
data = response.json()
print(data)

cURL

# Get speed ranking
curl "https://script.google.com/macros/s/YOUR_ID/exec?type=ranking"

# Get trust scores
curl "https://script.google.com/macros/s/YOUR_TRUST_ID/exec?action=getTrustScores"

Webhook Integration

For price change alerts and outage notifications, the system posts to Twitter automatically. To receive notifications via other channels, you can:

  1. Set up a webhook endpoint
  2. Modify twitter-oauth1-post-fixed.gs to call your webhook
  3. Or periodically poll the API endpoints

Data Freshness

Data TypeUpdate Frequency
Speed RankingEvery 6 hours
Stability ScoreCalculated on request (7-day window)
Price DataDaily at 9:00 AM JST
Trust ScoreMonthly on 1st
Integrated RankingCalculated on request

Support

For API issues, please open a GitHub issue at: https://github.com/hmy0210/vpn-stability-ranking/issues