tonapi.io и rate-лимиты: как убрать ошибку 429
tonapi.io отдаёт HTTP 429 при превышении rate-лимита. Разбираем, как убрать ошибку 429, почему «228» — это мем, и как получить свой ключ через MCP TONNode.
tonapi 429: полдевятого вечера, прод горит, а в логах — стена красного
Ваш бот на TON только что попал в подборку, пользователи повалили, и приложение вдруг начало отдавать пустые балансы. Открываете логи — там сотни строк:
HTTP 429 Too Many Requests
Знакомо? Вы ходите в tonapi.io за балансами и историей транзакций, всё работало на десяти пользователях, а на тысяче анонимный доступ упёрся в потолок. Это классика: пока трафик небольшой, публичный API кажется бесплатным и бесконечным. Как только нагрузка растёт — он превращается в бутылочное горлышко, и вы ловите tonapi 429 пачками. Это не баг вашего кода и не «нода легла» — это rate limit публичного API, и лечится он предсказуемо.
Разберём, почему возникает 429, почему пресловутая «228» тут ни при чём, какие фиксы реально помогают, и как уйти с общего анонимного пула на персональный лимит для чтения TON — через MCP-сервер TONNode.
Почему tonapi.io возвращает 429 Too Many Requests
tonapi.io — публичный HTTP-API к данным TON. Как у любого публичного сервиса, у него есть tonapi rate limit — ограничение частоты запросов, чтобы один клиент не съел всю ёмкость.
Когда вы ходите без ключа, вы делите общий анонимный пул со всеми остальными анонимами планеты. Практически это лимит порядка ~1 запроса в секунду. Для одного скрипта это терпимо. Но как только у вас параллельный воркер, который для каждого кошелька дёргает баланс, потом джеттон-баланс, потом историю, — вы мгновенно вылетаете за секундный лимит. Особенно больно при холодном старте, когда нужно проиндексировать сразу много адресов.
Сервер отвечает так:
HTTP/1.1 429 Too Many Requests
Retry-After: 1
Важно понимать: 429 — это стандартный код HTTP из спецификации, а не проприетарный код tonapi. Его отдаёт кто угодно при превышении частоты — GitHub, Stripe, Cloudflare, любой rate-limited сервис. Тот же самый механизм у toncenter и у большинства RPC-провайдеров. Значит, и лечится он стандартными приёмами, о которых ниже.
«Ошибка 228» — это не код API, а мем комьюнити (реальный код — 429)
Если вы гуглили проблему на русскоязычных форумах, вам наверняка попадалась «ошибка 228». Расставим точки над i, потому что это реально сбивает новичков с толку.
«228» — не официальный код ошибки ни tonapi, ни toncenter. Это мем-число, давно живущее в TON-комьюнити и всплывающее в чатах и шутках. Никакого HTTP-статуса 228 в ответ на превышение лимита вам не прилетит — такого статус-кода в HTTP попросту нет.
Реальный код, который вы увидите в логах и заголовках ответа, — именно 429. Когда кто-то в чате пишет «поймал 228 от тонапи», по факту он поймал 429 (или обычный таймаут), а «228» использует как фигуру речи. Ищите в своих логах 429, а не «228» — так вы найдёте настоящую причину. Проверяется в одну строку:
curl -s -o /dev/null -w "%{http_code}\n" https://tonapi.io/v2/blockchain/masterchain-head
# под нагрузкой без ключа увидите: 429
Быстрые фиксы: ретраи, бэкофф, кэш и свой ключ
Раз 429 — стандартная история, у неё есть стандартный набор лечений. Идём от простого к главному.
1. Экспоненциальный бэкофф с уважением к Retry-After
Не долбите эндпоинт в тугой цикл после первого же отказа — вы только усугубите ситуацию. При 429 сервер часто отдаёт заголовок Retry-After — сколько секунд подождать. Уважайте его, а если его нет — растите паузу экспоненциально.
async function fetchWithBackoff(url, opts = {}, maxRetries = 5) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const res = await fetch(url, opts);
if (res.status !== 429) return res;
// Уважаем Retry-After, иначе растим паузу экспоненциально
const retryAfter = Number(res.headers.get('retry-after'));
const waitMs = Number.isFinite(retryAfter) && retryAfter > 0
? retryAfter * 1000
: Math.min(1000 * 2 ** attempt, 30_000); // 1s, 2s, 4s… потолок 30s
await new Promise(r => setTimeout(r, waitMs));
}
throw new Error('429 не ушёл: превышено число ретраев');
}
2. Ограничьте число одновременных запросов
Часто 429 прилетает не от общего объёма, а от того, что вы запускаете 50 запросов «веером» через Promise.all. Поставьте семафор с лимитом параллелизма (1–4) — и всплески сгладятся, не пробивая секундный лимит.
3. Кэшируйте неизменные данные
Метаданные жетона (имя, символ, decimals), результат конвертации адреса, старые транзакции — это данные, которые не меняются. Положите их в локальный кэш с разумным TTL и не спрашивайте API повторно. Один только кэш decimals жетонов убирает заметную долю обращений.
4. Главный фикс — свой ключ вместо анонима
Первые три пункта — обезболивающее. Настоящее лечение — уйти с анонимного пула на собственный ключ. Персональный ключ поднимает ваш лимит на порядки по сравнению с ~1 req/s на аноним; вы перестаёте конкурировать со всем интернетом, и 429 просто уходит из штатной работы. Частный случай для соседнего провайдера разобран в фиксе 429 у toncenter — логика идентична.
Что делать, когда лимитов tonapi всё равно не хватает
Допустим, вы всё сделали правильно: бэкофф, кэш, очередь. Но приложение растёт, и даже с ключом вы упираетесь либо в тариф, либо в саму модель «HTTP-прослойка поверх ноды». Тут обычно рассматривают два пути.
Путь «свои лайтсерверы». Возникает соблазн «просто взять публичный лайтсервер из глобального конфига TON и ходить напрямую по ADNL». Честная оговорка: это не серебряная пуля. Публичные лайтсерверы из глобального конфига тоже общие и лимитированные — под нагрузкой они регулярно отвечают not ready или отваливаются по ADNL-таймауту, и глубокой истории транзакций не хранят. Отдельная типовая боль — именно not ready, разбор в как чинить «liteserver not ready». То есть просто «уйти на публичный конфиг» проблему лимитов не решает, а иногда усугубляет.
Путь «сменить провайдера/интерфейс». Проблема не в конкретном tonapi.io, а в том, что вы сидите на общем ресурсе. Обзор альтернатив HTTP-API собран в альтернативах tonapi в 2026. А если вы строите ИИ-агента, есть смысл не оборачивать REST руками, а подключить TON как набор инструментов через MCP — тогда чтение блокчейна становится вызовом инструмента, а не сырым HTTP-запросом, который надо ретраить.
TONNode MCP: персональный лимит вместо общего анонимного пула
TONNode (сайт tonnode.io) — это hosted MCP-сервер для TON. MCP (Model Context Protocol) — стандарт, по которому ИИ-агенты (Claude, Cursor, ChatGPT/Codex и любой MCP-клиент) вызывают внешние инструменты. Вместо того чтобы учить агента дёргать https://tonapi.io/v2/... и обрабатывать 429, вы даёте ему набор именованных инструментов для чтения TON.
Ключевой момент: пакет @tonnode/mcp работает по нативному ADNL-протоколу TON, без HTTP-прослоек. Он open source (MIT), лежит на npm и GitHub (tonnode/mcp). Это не ещё один REST-враппер поверх tonapi, а прямой разговор с сетью.
Типовые запросы, ради которых вы ходили в tonapi, покрываются инструментами чтения один-в-один:
- get_balance — баланс GRAM на адресе.
- get_jetton_balance — баланс USDT или любого жетона; джеттон-кошелёк вычисляется он-чейн, вам не нужно самому выводить его адрес. Как это заменяет связку из нескольких запросов — в заметке баланс USDT на TON одним вызовом.
- get_account_state — статус аккаунта, флаги, последняя транзакция.
- get_transactions — история транзакций.
- run_get_method — любой read-only get-метод контракта.
- get_masterchain_info — голова мастерчейна (актуальный блок).
- get_jetton_info — метаданные жетона: имя, символ, эмиссия и decimals (у USDT — 6, у большинства жетонов — 9; без них вы неправильно пересчитаете raw-единицы).
- parse_address — офлайн-конвертация и проверка адресов EQ/UQ/raw, вообще без обращения к сети.
Небольшая заметка про нейминг: GRAM — это переименованный в июне 2026 Toncoin. Сеть по-прежнему называется TON, поменялось только имя монеты. Балансы
get_balance— в GRAM.
Пример промпта, который агент выполнит через инструменты, а не через ручной HTTP:
Проверь баланс GRAM и баланс USDT на адресе
UQBvW8Z5huBkMJYdnfAEM5JqTNkuWX3diqYENkWsIL0XF_wm
и покажи последние 5 транзакций этого кошелька.
Агент сам вызовет get_balance, затем get_jetton_balance (вычислив джеттон-кошелёк он-чейн), затем get_transactions — без единого написанного вами HTTP-запроса, без Retry-After и без ручного бэкоффа в вашем коде.
Как подключить за минуту: локально для разработки или hosted-ключ под прод
Есть два способа, и оба честные. Важно не путать их: локальный npx без ключа удобен для разработки, но работает на публичном конфиге TON; персональный лимит, который снимает боль 429 под нагрузкой, даёт именно hosted-ключ.
Вариант A — локально, бесплатно, без ключа (для разработки)
Полный набор инструментов чтения поднимается одной командой через npx — регистрация и карта не нужны. Добавьте в конфиг MCP-клиента:
{
"mcpServers": {
"ton": {
"command": "npx",
"args": ["-y", "@tonnode/mcp"]
}
}
}
Идеальный старт для локальной разработки и проверки: полный набор чтения, ноль конфигурации, open source под капотом. Но честная оговорка: этот режим ходит по публичному конфигу TON, то есть подвержен тем же общим ограничениям, что и любые публичные лайтсерверы (not ready, ADNL-таймауты под нагрузкой). Для прод-трафика это не замена персональному лимиту — за ним идите в вариант B.
Вариант B — hosted-эндпоинт со своим ключом (для прода)
Когда нужна гарантированная пропускная способность и персональный лимит под нагрузкой прода, подключаете hosted-эндпоинт со своим Bearer-ключом:
{
"mcpServers": {
"ton": {
"type": "http",
"url": "https://mcp.tonnode.io/mcp",
"headers": { "Authorization": "Bearer tn_live_…" }
}
}
}
Тарифы
На всех тарифах доступны все 16 инструментов TONNode — платите вы только за пропускную способность:
- Hobby — бесплатно навсегда, 60 запросов/мин. Ключ выдаётся сразу после входа, без карты.
- Pro — $29/мес, 300 запросов/мин.
- Scale — $199/мес, 1200 запросов/мин.
Разница с анонимным tonapi очевидна: там вы делите ~1 req/s со всем интернетом, здесь у вас персональный потолок — уже на бесплатном hosted-ключе Hobby это 60 запросов в минуту только для вас, без плясок с бэкоффом и без случайных 429. Это уже не тот же самый бесплатный путь, что локальный npx без ключа: у hosted-ключа Hobby свой лимит, а не общий публичный пул.
Итог
429 от tonapi.io — это не баг и не мифическая «228», а честный сигнал: вы сидите на общем анонимном пуле и упёрлись в его потолок. Ретраи с бэкоффом, уважение к Retry-After, ограничение числа одновременных запросов и кэш снимают острую боль. Но по-настоящему проблема уходит только когда у вас появляется собственная ёмкость — а если вы строите на ИИ-агентах, ещё и удобнее делать это через MCP, где чтение TON идёт по нативному протоколу, а не через HTTP-прослойку.
Возьмите бесплатный hosted-ключ Hobby (60 req/min, без карты) и перестаньте ловить 429 → tonnode.io/dashboard?plan=hobby
Нужен запас под прод-нагрузку — сравните тарифы Pro и Scale: tonnode.io/pricing.
Дайте вашему агенту доступ к TON
16 MCP-инструментов: чтение, некастодиальные свапы, кроссчейн и кошельки. Бесплатный тариф — 60 запр/мин, карта не нужна.