Кредити та ліміти
Два окремі ліміти: кредити на місяць, це ваша квота, і виклики на хвилину, які захищають сервіс.
Кредити
- Невелика відповідь з бази даних коштує 1 кредит. Вартість кожного маршруту в таблиці цін.
- Кредити списуються лише за відповідь 2xx. Помилка нічого не коштує.
- Вони оновлюються в перший день вашого періоду, раз на місяць. Невикористане не переноситься.
- Понад квоту ви отримуєте 429
quota_exceeded. API зупиняється, а рахунок не виставляється.
Ліміт на хвилину
Кожен план має ліміт на хвилину. Понад нього ви отримуєте 429 rate_limited із заголовком Retry-After.
Ліміти за планами
| Кредитів на місяць | Викликів на хвилину | Історія | |
|---|---|---|---|
| Start | 5 000 | 30 | 30 дн. |
| Creator | 30 000 | 120 | 90 дн. |
| Pro | 300 000 | 600 | 365 дн. |
| Business | 3 000 000 | 1 800 | усе |
| Enterprise | за договором | за договором | усе |
Заголовки кожної відповіді
| Заголовок | Що означає |
|---|---|
X-RateLimit-Limit | Дозволено викликів на хвилину |
X-RateLimit-Remaining | Залишилося викликів у поточній хвилині |
X-RateLimit-Reset | Секунд до скидання хвилини |
X-Credits-Cost | Скільки кредитів коштував цей виклик |
X-Credits-Limit | Кредити періоду |
X-Credits-Remaining | Залишок кредитів |
X-Credits-Reset | Коли оновлюються кредити (ISO 8601) |
Retry-After | Скільки секунд чекати, лише для 429 і 503 |
Історія
Якщо ви просите більше днів, ніж дозволяє план, відповідь обрізається до ліміту плану, а meta.history_cut: true повідомляє про це.
Як повторити виклик
Прочитайте Retry-After, зачекайте вказаний час і спробуйте знову. Для quota_exceeded не повторюйте: дочекайтеся скидання з X-Credits-Reset.
async function call(url, key) {
for (let attempt = 0; attempt < 3; attempt++) {
const res = await fetch(url, { headers: { Authorization: `Bearer ${key}` } });
const body = await res.json();
if (res.ok) return body;
if (body.error.code === "quota_exceeded") throw new Error(body.error.message);
const wait = Number(res.headers.get("retry-after"));
if (![429, 503].includes(res.status) || !wait) throw new Error(body.error.message);
await new Promise((ok) => setTimeout(ok, wait * 1000));
}
throw new Error("still busy");
} import json, time, urllib.error, urllib.request
def call(url, key):
req = urllib.request.Request(url, headers={"Authorization": f"Bearer {key}"})
for attempt in range(3):
try:
with urllib.request.urlopen(req) as res:
return json.load(res)
except urllib.error.HTTPError as err:
body = json.load(err)
wait = err.headers.get("Retry-After")
if err.code not in (429, 503) or not wait or body["error"]["code"] == "quota_exceeded":
raise
time.sleep(int(wait))
raise RuntimeError("still busy") <?php
function call(string $url, string $key): array {
for ($attempt = 0; $attempt < 3; $attempt++) {
$ch = curl_init($url);
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => true, CURLOPT_HTTPHEADER => ["Authorization: Bearer $key"]]);
$raw = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
curl_close($ch);
$body = json_decode(substr($raw, $size), true);
if ($status < 400) {
return $body;
}
preg_match("/retry-after: (\\d+)/i", substr($raw, 0, $size), $m);
if (!in_array($status, [429, 503]) || empty($m[1]) || $body["error"]["code"] === "quota_exceeded") {
throw new RuntimeException($body["error"]["message"]);
}
sleep((int) $m[1]);
}
throw new RuntimeException("still busy");
}