toptl
The official Ruby SDK for TOP.TL — post stats, check votes, and manage vote webhooks for your Telegram bot, channel, or group listed on top.tl.
Install
gem install toptl
Or in your Gemfile:
gem "toptl"
Requires Ruby 3.0+. Zero runtime dependencies — transport is net/http from stdlib.
Quickstart
Get an API key at https://top.tl/profile → API Keys. Scope the key to your listing and the operations you need (listing:read, listing:write, votes:read, votes:check).
require "toptl"
client = TopTL::Client.new("toptl_xxx")
# Fetch a listing
listing = client.get_listing("mybot")
puts listing.title, listing.vote_count
# Post stats on a listing you own
client.post_stats(
"mybot",
member_count: 5_000,
group_count: 1_200,
channel_count: 300,
)
# Reward users who voted
check = client.has_voted("mybot", 123456789)
grant_premium(user_id: 123456789) if check.voted
Autoposter
For long-running bot processes, the SDK ships with a background autoposter that calls post_stats on an interval and only hits the API when the stats actually changed:
require "toptl"
client = TopTL::Client.new("toptl_xxx")
poster = TopTL::Autoposter.new(
client,
"mybot",
interval_seconds: 30 * 60, # every 30 min
only_on_change: true, # default
) { { member_count: get_user_count } }
poster.on_post { |result| puts "posted: #{result.success}" }
poster.on_error { |err| warn "autopost failed: #{err.}" }
poster.start
# ...
poster.stop
For cron-style one-shots, skip the autoposter and call client.post_stats(...) directly, or run poster.post_once.
Vote webhooks
Register a URL TOP.TL will POST to whenever someone votes for your listing:
client.set_webhook(
"mybot",
"https://mybot.example.com/toptl-vote",
reward_title: "30-day premium", # shown to the voter
)
# Send a test request to verify your endpoint
result = client.test_webhook("mybot")
puts result.success, result.status_code
The webhook payload contains the voting user (userId, firstName, username), the listing, and a timestamp.
Batch stats
Post stats for up to 25 listings in one request:
client.batch_post_stats([
{ username: "bot1", member_count: 1_200 },
{ username: "bot2", member_count: 5_400 },
])
Error handling
Every API error raises a subclass of TopTL::Error:
begin
client.post_stats("mybot", member_count: 5_000)
rescue TopTL::AuthenticationError
# bad key, or missing scope
rescue TopTL::NotFoundError
# listing does not exist
rescue TopTL::RateLimitError
# back off and retry
rescue TopTL::ValidationError => e
# payload rejected — inspect e.response_body
end
API reference
| Method | Description |
|---|---|
get_listing(username) |
Fetch a listing |
get_votes(username, limit:) |
Recent voters |
has_voted(username, user_id) |
Vote check with timestamp |
post_stats(username, member_count:, group_count:, channel_count:, bot_serves:) |
Update listing counters |
batch_post_stats(items) |
Bulk stats for up to 25 listings |
set_webhook(username, url, reward_title:) |
Register vote webhook |
test_webhook(username) |
Fire a synthetic vote |
get_global_stats |
Site-wide totals |
License
MIT — see LICENSE.