/vote: every vote site in one place
When each vote site opens again for a player, votes cast, how far the next reward is, a reminder in chat and a party bar that shows only when it matters. New in 0.3.
On this page 7 parts
/vote: every vote site in one place
New in 0.3. /vote used to print a list of links. Now it answers what a player actually wants to know: where can I vote right now, how many votes have I got, and how far is the next reward. Everything below is a setting in votes.toml (and in the editor's Settings and Votes screens); nothing is tied to one server or to one vote site.
What a player sees
#» Vote for this server:
» vote now | Czech-Craft - https://czech-craft.eu/server/you/vote/
» in 1h 12m | Minecraft-list.cz - https://...
» in ~23h 5m | minecraft-mp.com - https://...
Every site on one page: https://example.com/vote
You can vote on 1 of 7 sites right now.
Your votes: 3 today, 41 in all, 4 days running.
Streak reward at 7 days in a row: 3 days to go.
This month: 11 votes - 4 more for a prize place (the top 3). /vote top
Vote party: 12 of 25 - 13 to go.
Every address is a link a player can click. A time with a ~ is an estimate; one without comes from the vote site itself.
Telling the sites apart: votes.lists
#One line per site, parts separated by |:
service=Czech-Craft.eu | name=Czech-Craft | link=https://czech-craft.eu/server/you/vote/ | every=2h | check=https://czech-craft.eu/api/server/you/player/{player}/next_vote/ | path=next_vote | tz=Europe/Prague
service=Minecraft-MP.com | name=minecraft-mp.com | link=https://minecraft-mp.com/server/123/vote/ | every=24h
service(required) is the name the site sends with its vote, exactly as invotes.services.nameandlinkare what players read and click.everyis how long that site makes a player wait.checkandpathare optional: an https address the site answers when can this player vote next on, and where the time sits in its JSON answer (next_vote,[0].nextPossibleVote,data.next).{player},{year}and{month}are filled in. A time can be seconds or milliseconds since 1970, an ISO time, or2026-10-24 13:34:51in the zonetz(default:votes.time-zone).{key:name}inchecktakes a key from the filelists.keysin the votes data folder. Two lines per key:name=the-keyandname.host=api.example.com. A key is sent only to the host written beside it: it is filled in only into an https address whose host is exactly that one (never into the host part itself), otherwise it is not used and the log says so. Keys are never written in the settings, so the editor, the API and the assistant never see them, and whoever can change the settings cannot send a key to a server of their own.
Where the time comes from. If the site answers, that answer is used. If it does not have such an address, is down, is slow (votes.lists-timeout, default 4 seconds) or answers something unreadable, Keystone estimates: the last vote this server received from that site plus every (or, without every, the interval votes.site-cooldown counts votes with). A site that failed is left alone for 45 seconds, so a dead site does not slow every player's /vote. No time is written in the code.
What leaves the server, and where it may go. Only when you write check: the player's name, in the address you wrote, to the site you named, when that player types /vote (answers are remembered for up to a minute; nothing is sent for the chat reminder). Leave check out and nothing is sent anywhere. Only https is used, and only to public addresses: a name that resolves to this machine, a private network, a link-local address (including the cloud metadata address), carrier-grade NAT or a unique-local IPv6 address is refused before anything is sent, so the settings cannot be used to reach what only this machine can. Redirects are not followed, an answer is read to 64 KiB at most, and what a site answered is never shown to anyone: the editor and the API only get the time (or that it was estimated).
With votes.lists empty, /vote prints the lines of votes.sites as before.
The page
#votes.page is one link to a page with every site on it, such as your website's vote page. /vote prints it under the sites.
Votes, streaks and the month
#- Today / in all / streak come from the same table the vote rules read, so the number a player sees is the number the rules use.
- Streak reward: the nearest
votes.streaksline above the player's streak and how many days are left. - The month: the player's place and votes, and with
votes.top.rewardshow many more votes reach the last prize place./vote topshows the board.
A reminder in chat
#votes.remind.chat (on by default): to a player who can vote somewhere, "You can vote on 5 of 7 sites right now", at most every votes.remind.chat-every (default 3 hours), the first one votes.remind.chat-after-join (default 3 minutes) after joining. It is checked every five minutes and uses only what the server already knows, so it sends no request to any site. A player switches it off with /vote remind chat off (and on with /vote remind chat on). /vote remind on is the other reminder, a private Discord message.
The party bar
#The boss bar that counts the last votes to the party goal used to stay on screen the whole time. Now it shows for votes.party.bar-for (default 20 seconds) after a vote moves it, and goes. 0s keeps the old behaviour: on while the count is within votes.party.bar-from of the goal.
In the editor and the API
#The Votes screen lists the sites and, for a player you look up, when each opens for them. GET /v1/votes/lists (scope players.read) returns the same, with ?player= for one player.
Every vote, to your own vote page (votes.report.*, off until set): report.url is an https address that is POSTed JSON - {"type":"vote","server","player","list","at"} for each accepted vote, and {"type":"lists","server","lists":[…]} every report.every (5 minutes, only when they changed) with the vote lists and their waits - for a full vote page on your website or a bot. report.key goes as a Bearer token, report.server names this server in the reports (a world key such as mc; empty sends none). Addresses inside the network are refused unless the owner sets report.allow-local; only the owner may set any of it.
Texts are in the language files: votes.where.*, votes.list.* and votes.remind.chat*; change them in the editor's Languages screen.
Did this page help?
Opens the feedback panel with this page attached. It lands in the same queue as everything else.