Toncenter
Публичный TON API-gateway. JSON-RPC поверх liteserver-пула: getTransactions, runGetMethod, sendBoc, getAccount. Бесплатный tier с лимитом 1 RPS, платные тарифы для production-нагрузки.
Синонимы: toncenter, toncenter api, ton center
Toncenter (toncenter.com) — публичный API-gateway TON: REST/JSON-RPC поверх пула liteserver’ов. Поддерживается TON Foundation как референс-имплементация публичного TON API.
Основные методы
getTransactions(address, limit, lt, hash)— история транзакций аккаунта.runGetMethod(address, method_name, stack)— вызов get-метода на смарт-контракте (read-only).sendBoc(boc)— отправка подписанного external-message в сеть.getAccount(address)— баланс, code, data, status.
Tier’ы
- Free — 1 RPS, без API-key. Для прототипов и редких запросов.
- Pro — платный, выше rate-limit, отдельный SLA.
Альтернативы
- TONAPI (
tonapi.io) — индексированный API с дружелюбной JSON-схемой и поиском по jetton-операциям. Часто проще для DApp-разработки. - Свой liteserver-pool — для latency-критичной инфраструктуры или приватности.
Аутентификация и rate-limit
Free-tier работает без ключа: https://toncenter.com/api/v2/getAccount?address=... отвечает сразу. Лимит — 1 запрос в секунду на IP; превышение даёт 429 Too Many Requests.
Для production-нагрузки нужен API-key (бесплатная регистрация через @tonapibot для классического tier’а):
const r = await fetch('https://toncenter.com/api/v2/getAccount?address=...', {
headers: { 'X-API-Key': process.env.TONCENTER_KEY },
});
С ключом — 10 RPS на free-pro, выше при платном тарифе. Header X-API-Key важнее query-параметра api_key — некоторые прокси режут query-string.
Пагинация транзакций
Корректный курсор для getTransactions — пара (lt, hash), а не offset. Пример листания всей истории аккаунта:
let cursor = null;
while (true) {
const params = new URLSearchParams({ address: addr, limit: '50' });
if (cursor) { params.set('lt', cursor.lt); params.set('hash', cursor.hash); }
const { result } = await (await fetch(`${API}/getTransactions?${params}`)).json();
if (!result.length) break;
for (const tx of result) handle(tx);
const last = result[result.length - 1];
cursor = { lt: last.transaction_id.lt, hash: last.transaction_id.hash };
}
Использование utime для курсора даёт пропуски: внутри одной секунды может быть много транзакций, и utime >= отсечёт часть.
Типичные ошибки
503 Service Unavailable— liteserver-pool перегружен. Retry с экспоненциальным backoff (start = 500 мс, cap = 8 с) обычно решает.runGetMethodвозвращает stack сnull— контракт не имеет такого method_id или throw’нул внутри. Проверьте код контракта черезgetAccount→data→ ABI.sendBocотдал 200, но транзакция не появляется — внешнее сообщение могло быть отклонено валидатором (низкая комиссия, неверная подпись). Проверяйтеprev_ltаккаунта спустя 15-20 сек: если не изменился — реджект.