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