Skip to main content
T TON Adoption
← Glossary
NODE/03 · Term

Toncenter

Public TON API gateway. JSON-RPC over a liteserver pool: getTransactions, runGetMethod, sendBoc, getAccount. Free tier with 1 RPS, paid tiers for production load.

Aliases: toncenter api, ton center

Toncenter (toncenter.com) is a public TON API gateway: REST/JSON-RPC over a pool of liteservers. Maintained by TON Foundation as the reference implementation of a public TON API.

Core methods

  • getTransactions(address, limit, lt, hash) — account transaction history.
  • runGetMethod(address, method_name, stack) — read-only call to a contract’s get-method.
  • sendBoc(boc) — broadcast a signed external message.
  • getAccount(address) — balance, code, data, status.

Tiers

  • Free — 1 RPS, no API key. For prototypes and occasional calls.
  • Pro — paid, higher rate limit, separate SLA.

Alternatives

  • TONAPI (tonapi.io) — indexed API with friendly JSON schemas and operation-level search. Often easier for DApp development.
  • Your own liteserver pool — for latency-critical infrastructure or for privacy.

Authentication and rate limits

Free tier works without a key: https://toncenter.com/api/v2/getAccount?address=... responds immediately. Limit — 1 request per second per IP; exceeding it returns 429 Too Many Requests.

For production load you need an API key (free signup via @tonapibot for the classic tier):

const r = await fetch('https://toncenter.com/api/v2/getAccount?address=...', {
  headers: { 'X-API-Key': process.env.TONCENTER_KEY },
});

With a key — 10 RPS on free-pro, higher on paid tiers. The X-API-Key header is more reliable than the api_key query parameter — some proxies strip query strings.

Paginating transactions

The correct cursor for getTransactions is a (lt, hash) pair, not an offset. Example walking an account’s full history:

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 };
}

Using utime as a cursor causes gaps: many transactions can share the same second, and utime >= will drop some.

Common errors

  • 503 Service Unavailable — liteserver pool is overloaded. Retry with exponential backoff (start = 500 ms, cap = 8 s) usually fixes it.
  • runGetMethod returns stack with null — the contract has no such method_id, or threw inside. Inspect the contract code via getAccountdata → ABI.
  • sendBoc returned 200 but no transaction appears — the external message may have been rejected by the validator (low fee, bad signature). Check the account’s prev_lt after 15-20 sec: if it didn’t change — your message was rejected.

Related terms