校验原理

  1. Key 有效性校验流程
    • 首先调用 Gemini 的 generateContent 接口(如 models/gemini-2.0-flash-lite:generateContent),判断 Key 是否有效(基础有效性)
    • 如果返回 200,说明 Key 有效,标记为 Free,进入下一步
    • 如果返回 400/401/403/429,则判定 Key 无效,将其标记为 Invalid
    • 其它错误则记录为未知或异常状态
  2. Key 是否为付费 Key 原理
    • 对每个通过基础校验的 Key,构造大文本请求体向 cachedContents 接口(如 models/gemini-2.5-flash:cachedContents)发起请求
    • 如果请求成功返回 200(无报错),则认为该 Key 具备付费权限(可访问缓存 API),将其标记为 Paid
    • 如果返回 429(Too Many Requests),则认为该 Key 仅为免费 Key(有速率限制),标记为 Free
    • 其它错误则记录为未知或异常状态

流程图

输入 Key
   │
   ├─> generateContent API 校验
   │      ├─ 200 → 有效 → cachedContents API 校验
   │      │           ├─ 200 → 付费 Key
   │      │           ├─ 429 → 免费 Key
   │      │           └─ 其它 → 异常
   │      └─ 其它 → 无效 Key

接口请求

  • 获取模型列表
curl 'https://generativelanguage.googleapis.com/v1beta/models?key=AIzaSyCuvt31hJeflv7Hxlg9UOBZdlxEbOJ-2JN'
{
  "models": [
    {
      "name": "models/embedding-gecko-001",
      "version": "001",
      "displayName": "Embedding Gecko",
      "description": "Obtain a distributed representation of a text.",
      "inputTokenLimit": 1024,
      "outputTokenLimit": 1,
      "supportedGenerationMethods": [
        "embedText",
        "countTextTokens"
      ]
    },
    {
      "name": "models/gemini-1.5-pro-latest",
      "version": "001",
      "displayName": "Gemini 1.5 Pro Latest",
      "description": "Alias that points to the most recent production (non-experimental) release of Gemini 1.5 Pro, our mid-size multimodal model that supports up to 2 million tokens.",
      "inputTokenLimit": 2000000,
      "outputTokenLimit": 8192,
      "supportedGenerationMethods": [
        "generateContent",
        "countTokens"
      ],
      "temperature": 1,
      "topP": 0.95,
      "topK": 40,
      "maxTemperature": 2
    }
  ],
  "nextPageToken": "Cihtb2RlbHMvaW1hZ2VuLTQuMC1nZW5lcmF0ZS1wcmV2aWV3LTA2LTA2"
}
  • 验证是否有效

# https://ai.google.dev/gemini-api/docs?hl=zh-cn#rest
curl 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-lite:generateContent?key=AIzaSyDh_rYhgs5_hy5g81rI7fcjuuKU4NyMfI1' \
  -H 'Content-Type: application/json' \
  -H 'X-goog-api-key: GEMINI_API_KEY' \
  -X POST \
  -d '{
  "contents": [
    {
      "parts": [
        {
          "text": "Hi"
        }
      ]
    }
  ],
  "generation_config": {
    "thinking_config": {
      "thinking_budget": 0
    }
  }
}'
<?php
$api_key = 'YOUR_GEMINI_KEY';

$body = [
    "model" => "models/gemini-pro",
    "contents" => [
        [
            "role" => "user",
            "parts" => [
                ["text" => "hello"]
            ]
        ]
    ]
];

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=" . $api_key);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Content-Type: application/json"
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($http_code === 200) {
    echo "[INFO] BASIC API VALID - " . substr($api_key, 0, 10) . "... - Passed generate content API test\n";
    echo "Key 有效\n";
} elseif (in_array($http_code, [400, 401, 403, 429])) {
    echo "[WARN] INVALID - " . substr($api_key, 0, 10) . "... - KeyInvalid\n";
    echo "Key 无效\n";
} else {
    echo "[ERROR] ERROR- " . substr($api_key, 0, 10) . "... - HTTP $http_code\n";
    echo "未知错误\n";
}
echo "响应内容:\n$response\n";
?>
# 响应
{
  "candidates": [
    {
      "content": {
        "parts": [
          {
            "text": "Hi there! How can I help you today?\n"
          }
        ],
        "role": "model"
      },
      "finishReason": "STOP",
      "avgLogprobs": -0.015995754437013107
    }
  ],
  "usageMetadata": {
    "promptTokenCount": 1,
    "candidatesTokenCount": 11,
    "totalTokenCount": 12,
    "promptTokensDetails": [
      {
        "modality": "TEXT",
        "tokenCount": 1
      }
    ],
    "candidatesTokensDetails": [
      {
        "modality": "TEXT",
        "tokenCount": 11
      }
    ]
  },
  "modelVersion": "gemini-2.0-flash-lite",
  "responseId": "092haJyTKNWknvgPjZf02AQ"
}
  • 检测是否付费

curl 'https://generativelanguage.googleapis.com/v1beta/cachedContents?key=AIzaSyDh_rYhgs5_hy5g81rI7fcjuuKU4NyMfI1' \
  -H 'Content-Type: application/json' \
  -H 'X-goog-api-key: GEMINI_API_KEY' \
  -X POST \
  -d '{
        "model": "models/gemini-2.5-flash",
        "contents": [
          {
            "parts": [
              {
                "text": "You are an expert at analyzing transcripts."
              }
            ],
            "role": "user"
          }
        ],
        "ttl": "30s"
}'
<?php
// 替换为你的 Gemini API Key
$api_key = 'YOUR_GEMINI_KEY';
$long_text = str_repeat("You are an expert at analyzing transcripts.", 128);
$body = [
    "model" => "models/gemini-2.5-flash",
    "contents" => [
        [
            "role" => "user",
            "parts" => [
                ["text" => $long_text]
            ]
        ]
    ],
    "ttl" => "30s"
];

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:cachedContents?key=" . $api_key);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Content-Type: application/json"
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($http_code === 200) {
    echo "[INFO] PAID KEY DETECTED - " . substr($api_key, 0, 10) . "... - Cache API accessible\n";
} elseif ($http_code === 429) {
    echo "[DEBUG] FREE KEY DETECTED - " . substr($api_key, 0, 10) . "... - Rate limit exceeded for cache API\n";
} else {
    // 其它错误
    echo "[ERROR] CACHE API ERROR - " . substr($api_key, 0, 10) . "... - HTTP $http_code\n";
}
# 1. 付费KEY status code = 200
{
  "name": "cachedContents/vdgt1zr6ceih48e776ewkvui809blrly2bax9lne",
  "model": "models/gemini-2.5-flash",
  "createTime": "2025-08-17T13:52:16.104407Z",
  "updateTime": "2025-08-17T13:52:16.104407Z",
  "expireTime": "2025-08-17T13:52:45.568323278Z",
  "displayName": "",
  "usageMetadata": {
    "totalTokenCount": 1025
  }
}
# 2. 免费KEY,status code = 429
{
  "error": {
    "code": 429,
    "message": "TotalCachedContentStorageTokensPerModelFreeTier limit exceeded for model gemini-2.5-flash: limit=0, requested=1025",
    "status": "RESOURCE_EXHAUSTED"
  }
}
# 3. 响应 status code = 400
{
  "error": {
    "code": 400,
    "message": "Cached content is too small. total_token_count=9, min_total_token_count=1024",
    "status": "INVALID_ARGUMENT"
  }
}

参考资料

  • Gemini API 文档 https://ai.google.dev/gemini-api/docs?hl=zh-cn#rest
  • Gemini-Keychecker https://github.com/Yoo1tic/Gemini-Keychecker