tonkeeper

Stars and mentions

Last 30 days, Oct 5 – Nov 3

GitHub stars28
mentions1
01234Oct 5Oct 19Nov 3
UTC days · repositories tonkeeper owns4 repositories

Package downloads

Cumulative recorded downloads · since 2025-10-29

npm83
021426384Oct 5Oct 19Nov 3
Oct 27npm: 1/1 packages observed

Across 1 known packages in repositories tonkeeper owns. Cumulative totals include recorded downloads before the selected range. Missing observations leave gaps; totals may be incomplete.

Top repositories

tonkeeper’s repositories ranked by new stars, as on trending.

Loading

Contributes to

Repositories outside tonkeeper’s account where tonkeeper opened or reviewed pull requests in the past 365 days.

Who noticed tonkeeper

Everyone who starred or forked tonkeeper’s repositories since the archive began in 2011.

Notable accounts

Ordered by the stars their own repositories have received.

Biggest fans

Accounts that starred the most of these repositories.

Breakout weeks

Each repository’s best week of new stars, with the release published around it.

Mentions

1post
Nov 40 posts
  1. I built a TON explorer where every page is a public API call A surprising part of Telegram lives on a blockchain. Collectible @usernames, anonymous +888 phone numbers and gifts are NFTs on The Open Network (TON), and so are .ton domains. They change hands every minute — yet simple questions like "which 4-letter usernames are on auction right now?" or "which .ton domains expired this month?" usually mean clicking through marketplaces one item at a time. apiton.org is my answer to that: an explorer that lists all of it with a status (not listed, for sale, on auction, expired), a price and a history, plus a directory of live TON Sites with screenshots. As of 25 October 2026 it tracks: | Kind | Total | For sale | On auction | |---|---:|---:|---:| | Telegram usernames | 674,469 | 44,460 | 16,871 | | Anonymous +888 numbers | 136,566 | 440 | 84 | | .ton domains | 199,832 | 28,734 | 120 | …plus 28,623 expired .ton domains, 64,596 Telegram gifts and 382 live TON Sites. But the part I want to talk about is how it is built: the website has no database access at all. It is a separate Go program that renders every page from the same public API anyone can call. The Telegram bot @apitonBot works the same way. When the site needs something new, it becomes an API method first. The rule: the site is just another API client apiton.org (Go, html/template) ─┐ @apitonBot (Go) ├──► POST https://app.apiton.org/v2.<Service>/<Method> your script, curl, an AI agent ─┘ │ ├── Postgres catalog: usernames, numbers, domains, gifts, TON Sites └── TON liteservers: live on-chain state Why bother with this discipline on a one-person project? 1. The API can't rot. If a field breaks, my own pages break first, and I see it before anyone else does. 2. Every site feature is an API feature. Expired-domain lists, the sales feed, gift collection floors, TON Site status — all of them are public methods, because the site has no other way to get them. 3. A small blast radius. The site imports no backend package. It can be cached, restarted or rewritten without touching the data layer. Try it: no key, just curl The API speaks Connect, the HTTP-friendly sibling of gRPC: every call is a POST with a JSON body to https://app.apiton.org/v2.<Service>/<Method>. gRPC and gRPC-Web clients generated from the same protos work too. Anonymous calls are allowed — 1 request per second and 10,000 a month per IP. How big is the catalog? curl -s -X POST https://app.apiton.org/v2.Catalog/Summary \ -H 'Content-Type: application/json' -d '{}' { "kinds": [ {"kind": "username", "total": "674469", "by_status": {"auction": "16871", "not_listed": "613138", "sale": "44460"}}, ... ], "live_sites": "382" } These are the numbers from the table above, and the ones on the apiton.org home page. The cheapest .ton domains for sale curl -s -X POST https://app.apiton.org/v2.Catalog/List \ -H 'Content-Type: application/json' \ -d '{"kind":"domain","statuses":["sale"],"sort":"price_asc","limit":2}' { "items": [ { "kind": "domain", "name": "prommeteeev", "nft_address": "UQBt9bwjG5fTpT166sh76zjM0zKQ5rvhr44_vQcE0vPK8SyN", "owner_address": "UQBixgxoacPjMpiqOjr3t7FDnFsYP_Pbxg8VgK2mxckIQspb", "sale_contract": "UQCfowehxX68MXv1HGmVMdrBt2HNQdyxIWI7M41HpKiQYiuA", "status": "sale", "price": 0.468, "price_source": "chain", "expires_at": "2027-10-19T16:45:46Z", "name_len": 11 }, ... ], "total": "28734" } price is in the network's own coin (shown as 💎 on the site), and price_source says whether it came from a sale contract on chain or from a Fragment listing. List filters by kind (username, number, domain, gift), statuses, name_len, digits_only, prefix and an expiry window, and sorts by name, price_asc, price_desc, expires_asc or changed. Two more recipes: # 4-letter usernames on auction curl -s -X POST https://app.apiton.org/v2.Catalog/List \ -H 'Content-Type: application/json' \ -d '{"kind":"username","statuses":["auction"],"name_len":4}' # expired .ton domains, most recently changed first curl -s -X POST https://app.apiton.org/v2.Catalog/List \ -H 'Content-Type: application/json' \ -d '{"kind":"domain","statuses":["expired"],"sort":"changed"}' The full list of fields is in this guide on the apiton blog and in the API reference. What just sold curl -s -X POST https://app.apiton.org/v2.Catalog/Events \ -H 'Content-Type: application/json' \ -d '{"types":["sold"],"limit":3}' Pass a kind and a name instead and you get the history of one item: listed, delisted, re-priced, sold, bids, expiry, renewal. Live state of one item The catalog is refreshed in the background. For the state of a single item right now, the v2.Nft methods read the chain: curl -s -X POST https://app.apiton.org/v2.Nft/Domain \ -H 'Content-Type: application/json' \ -d '{"domain":"apiton.ton"}' { "address": "UQABUZhK7peJbJzDxChcbitG9oJUgxWmk1TqZwU76aMEKALt", "owner_address": "UQAyJ9vVRMGVKg9-6R-KO3alF2ITcccDBAhAi1Qj4HCpVP5Q", "time_expire": "2027-10-08T16:16:31Z", "site": { "kind": "adnl", "status": "live", "title": "apiton — TON explorer: names, gifts and TON Sites", "uptime_30d": 1, "live_since": "2026-10-07T16:18:19.961661Z", "gateway_url": "https://site.apiton.org/apiton.ton/" } } Yes, the explorer is a TON Site itself — more on that below. v2.Nft/Username, Number and Gift work the same way, and v2.Address covers wallets: balance, jettons, NFTs and transactions. Three JSON gotchas The responses are proto3 JSON, which surprises people coming from hand-written REST APIs: - int64 arrives as a string: "total": "28734". Parse it; don't compare it to a number. - Zero values are omitted. An empty list is {}, not {"items": [], "total": "0"}. - Errors use the Connect envelope with a proper HTTP status: curl -s -X POST https://app.apiton.org/v2.Catalog/List \ -H 'Content-Type: application/json' -d '{"kind":"planet"}' # HTTP 400 # {"code":"invalid_argument","message":"unknown kind \"planet\" (username | number | domain | gift)"} Too many requests is resource_exhausted (HTTP 429). unavailable means the TON liteservers are lagging; retry after a second or two. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset. What public liteservers taught me Live reads go to the public TON liteservers. They are free, and they are moody. Between 23 and 25 October, 54–83 % of my liteserver requests were answered with error 651 — "the node is behind". That rate did not change when I tripled my own background load, so it was not me. What made the API usable anyway: 1. A pool with failover. Keep four connections open; a 429 or a 651 is retried on another server, not on the same one. 2. Don't read the newest block. Reads run on a masterchain block about 10 seconds behind the head, which a node that is slightly behind can still serve. If six servers refuse, the answer comes from an older block (at most 45 seconds old). The one exception: before a send, a wallet's own state is read on the newest block only, or the send fails before anything is signed. 3. One chain read per question. A 45-second live cache sits in front of the item methods. Identical concurrent requests share a single chain read that is detached from the caller's context, so a client hanging up doesn't cancel it for everyone else. Errors are never cached. 4. The pool's answer is final. No retry loops stacked on top of it — that is how a bad minute becomes a retry storm. Clients get a clear unavailable instead, and the bot retries once after 1.5 seconds. The other lesson was quieter and more expensive. For months, every sale and auction price read silently returned nothing, because of a typo in the default URL of the archive endpoint those reads went through. "No price" looked like a valid answer, so nothing alerted. The fix was a rule rather than a patch: state and get-method reads go to liteservers only, and the archive is used for old transactions only. .ton domains can't be listed from the chain You'd think the 199,832 domains came from iterating the DNS collection. They can't. The root .ton collection indexes each item by hash(name) rather than a counter, so there is no 0..N to walk. A domain also lapses silently: it is valid for a year after its last renewal (last_fill_up_time), and no transaction marks the moment it expires. So the catalog learns about domains as they show up on chain — transfers, sales, DNS changes — and then re-reads each one on a schedule to compute its expiry. A small trap on the way: get_last_fill_up_time returning 0 means the item was never initialized, not that it expired long ago. TON Sites: a directory of the "other" web A .ton domain can point to a website through its DNS site record — an ADNL address or a TON Storage bag. apiton reads that record for every domain, probes each site over RLDP-HTTP or TON Storage, tells parked pages from live ones, ranks them and takes screenshots with a headless Chrome whose only way out is a .ton-only proxy. The result is apiton.org: 382 live sites today. Sites with clearly illegal content are listed by name with a reason, and never opened or previewed. apiton.org is one of them. apiton.ton is served by a small Go program that speaks ADNL and RLDP-HTTP and reverse-proxies the regular website, GET and HEAD only. Without a TON proxy, you can open it through the gateway: site.apiton.org. The bot and the limits @apitonBot is the second client of the same API. Send it a wallet address, an @username, a +888 number, a name.ton or a gift link and you get a card. You can also watch items and wallets (listed, sold, new bid, incoming transaction), set price alerts, see a wallet's portfolio, and get an API key with /get_api. It answers in Russian for CIS languages and in English for everyone else. With a key (Authorization: Bearer <tg_id>:<secret>) you get your own quota instead of sharing one with your IP: - free — 1 request/s, 10,000 a month; - builder — 10 requests/s, 300,000 a month; - pro — 100 requests/s, 3,000,000 a month. Upgrades are paid in the bot with Telegram Stars or TON. The key, together with a wallet token, also unlocks custodial wallets, sends and jetton/NFT minting. For AI assistants: llms.txt apiton.org is a Markdown map of the site, the API and the bot, written for LLMs. Point an assistant or an agent at it and it can answer "what's the cheapest 5-letter username on sale?" with a real API call instead of a guess. The stack, briefly Go everywhere: connect-go over h2c for the API, Postgres through Bun, Redis for caches and quotas, tongo for TON. The site is server-rendered html/template with no JavaScript framework. React is used only for the bot's Mini App. Try it - Explorer: apiton.org — usernames, +888 numbers, .ton domains, gifts, TON Sites - API reference: docs.apiton.org - Bot: @apitonBot · news: @apiton What would you build on top of it, and which method is missing? Tell me in the comments, or send /feedback to the bot.

    1 comment

Achievements

Awards earned by the repositories tonkeeper owns. Select an award to embed its badge.

No awards yet

Repositories earn awards by reaching the top three in a completed trending day or week.

A repository earns an award for finishing first, second or third in a completed trending day or week, ranked by new stars, new forks or pull request authors. Awards follow a repository through renames and transfers and count toward its current owner. Weeks run Monday to Sunday, UTC.