milestones
Rewards at TOTAL / MONTHLY / WEEKLY / DAILY / STREAK thresholds, one-time or repeating.
A milestone is a reward that fires when one of a player's vote counters reaches a threshold. They are the long-term chase on top of the per-vote rewards: first vote, 100 votes, a 7-day streak, 30 votes this month.

The milestones menu. Players see every milestone, their progress and what it pays.
Quick example
enabled: true
entries:
- id: first-vote
type: TOTAL
threshold: 1
display-name: "First Vote"
material: PAPER
one-time: true
rewards:
- type: message
target: self
value: "<#5EEEA0>Welcome to the vote club, <#A8D8F0>%player%<#5EEEA0>!"
- type: money
value: 500
lore:
- "<#5EEEA0> • <#E0F0FF>$500 in-game currency"
- id: week-streak
type: STREAK
threshold: 7
display-name: "Week Streak"
material: NETHER_STAR
one-time: true
rewards:
- type: money
value: 2500
lore:
- "<#5EEEA0> • <#E0F0FF>$2,500 in-game currency"
- id: monthly-30
type: MONTHLY
threshold: 30
display-name: "Dedicated Voter"
material: DIAMOND
one-time: false
rewards:
- type: command
value: "give %player% diamond 8"
lore:
- "<#5EEEA0> • <#E0F0FF>8x Diamonds, every month"Reference
| Key | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | Master switch for milestones. |
entries | list | The milestones, in the order they appear in the menu. | |
entries[].id | string | Required, unique. Stored in the database to remember who has claimed what. | |
entries[].type | string | Required. TOTAL, MONTHLY, WEEKLY, DAILY or STREAK. | |
entries[].threshold | int | Required. The counter value the player must reach. | |
entries[].display-name | string | Name shown in the menu and used for %milestone%. MiniMessage. | |
entries[].material | string | Icon in the menu. | |
entries[].one-time | boolean | true | See One-time and repeating. |
entries[].rewards | list | Same syntax as vote-rewards.yml, every type works. | |
entries[].lore | list | Optional lines shown under "Rewards:" in the menu. Leave it out to hide that section. |
Write the lore yourself as a friendly description of the prize.
The menu never lists the raw reward entries.
Do not rename an id on a live server. Claims are remembered by
id, so a renamed milestone looks brand new and pays everyone who is
already past the threshold again on their next vote.
Counter types
| Type | What it counts | Rolls over |
|---|---|---|
TOTAL | All votes the player has ever cast | Never |
MONTHLY | Votes this calendar month | On the 1st |
WEEKLY | Votes this week, Sunday to Saturday | Sunday |
DAILY | Votes today | Midnight |
STREAK | Consecutive days with at least one vote | When the player misses a full day |
All rollovers happen in the general.timezone from config.yml.
One-time and repeating
one-time: truepays once per player, ever. After that it shows as claimed in the menu for good.one-time: falsepays once per period. The claim is cleared when that counter rolls over: aDAILYmilestone can be earned again tomorrow, aMONTHLYone next month, and aSTREAKone the next time the player rebuilds a streak after losing it.
A TOTAL counter never rolls over, so one-time: false on a TOTAL
milestone behaves exactly like one-time: true. There is no "every
100 votes" setting. For that, add one entry per step (100, 200, 300).
When a milestone is checked
Milestones are checked each time a vote is counted for a player who is online, which includes queued offline votes being claimed. A player who reaches several thresholds with one vote gets all of them.
A milestone pays when the counter is at or above the threshold and the player has not claimed it yet. So adding a new 50-vote milestone to a server where players already have 80 votes pays those players on their next vote.
Placeholders
Milestone rewards take every reward placeholder plus these:
| Token | Replaced with |
|---|---|
%milestone% | The milestone's display-name |
%milestone_id% | The milestone's id |
%threshold% | The milestone's threshold |
Resetting a player's milestones
/voteplus reset <player> clears everything VotePlus knows about the
player, including claimed milestones. There is no command that clears
claims on their own.