Compatibility
Minecraft: Java Edition
Platforms
Tags
Creators
Details
InviteRewards
Track who invited whom on your Discord, and pay out in-game rewards once the invited member verifies rather than merely joins.
The Discord bot is built into the plugin. There is no second process to host and
no external database to set up. One JAR in plugins/, a bot token in
config.yml, then restart.
How it works
- A member joins your Discord through someone's invite. The plugin diffs invite use counts to work out whose invite it was.
- The member presses a button in your verify channel and gets the verified role.
- Only then is the inviter credited. Joining alone earns nothing.
- The inviter links their Minecraft account with
/link, and rewards are handed out as their confirmed invite count crosses each configured threshold.
![]() |
![]() |
![]() |
![]() |
|---|---|---|---|
| Invite tracking | Verification | Threshold rewards | Anti-abuse |
Features
- A join counts for nothing until the invited member verifies, so drive-by joins and bot raids do not pay.
- One Discord account can produce one credit, ever. A database primary key enforces that, not a check that can be raced. Leaving, being re-invited and rejoining all collapse onto the same record.
- Discord accounts younger than a configurable age cannot credit whoever invited them.
- A daily cap per inviter blunts mass-invite bursts.
- If the invited member leaves within the hold window, or is banned at any point, the credit is taken back and rewards above the new count are removed.
- Nobody can invite themselves, and one Minecraft account links to exactly one Discord account.
- Each threshold pays out once. A restart part-way through delivery cannot duplicate a rank or an item.
- Thresholds crossed while a player is offline are queued and delivered on their next join.
- After a restart the plugin tries to attribute joins it missed, by matching the
invite-use delta against members who joined during the downtime. Unambiguous
cases resolve automatically; the rest are logged for
/invitereward attribute.
Commands and permissions
| Command | Description | Permission | Default |
|---|---|---|---|
/link <code> |
Redeem the code issued by /link in Discord |
none | everyone |
/invitereward reload |
Re-read rewards and messages from config.yml |
inviterewards.admin |
op |
/invitereward status <player> |
Show a player's Discord link, confirmed invites and per-threshold state | inviterewards.admin |
op |
/invitereward unlink <player> |
Remove a player's Discord link | inviterewards.admin |
op |
/invitereward attribute <discordId> <inviterId> |
Set the inviter for a member the tracker could not attribute | inviterewards.admin |
op |
In Discord the bot registers one slash command, /link, which issues a
six-character code to type in game.
/invitereward reload reloads rewards and messages only. Changing the token,
guild, channel or role needs a server restart.
Requirements
Paper, or a fork of it. Spigot is not tested.
Minecraft 1.21 through 26.2. The plugin is compiled against the 1.21 API, and also verified to compile against 26.1.2 and 26.2.
Java 21 or newer, which is whatever your Minecraft version already requires (Java 21 on 1.21.x, Java 25 on 26.x).
A Discord bot application that you create yourself. See Setup below.
LuckPerms is optional and only needed for luckperms-group rewards. Without it,
group rewards log a warning and are skipped. Vault plus an economy plugin is
optional in the same way, for money rewards. Command and item rewards have no
dependencies at all.
Setup
The Discord side is where installs go wrong, so do these in order.
- Create an application at https://discord.com/developers/applications and add a Bot to it. Copy the bot token.
- In the Bot tab, enable the Server Members Intent. It is privileged and off by default. Invite tracking does not work without it.
- Invite the bot to your guild with the Manage Server permission, which is what lets it read invites, and with Manage Roles.
- In your guild's role list, drag the bot's own role above the verified role. Discord will not let a bot assign a role positioned above its own.
- Enable Developer Mode in Discord (Settings → Advanced), then right-click to copy the IDs of your guild, your verify channel and your verified role.
- Drop the JAR into
plugins/, start the server once to generateconfig.yml, fill in the token and the three IDs, and restart.
On startup the plugin posts the verification message with its button, and takes a baseline snapshot of your existing invites. Invites that already exist keep working. Joins that happened before you installed the plugin have no baseline and are not attributed retroactively.
Configuration
This is the generated config.yml:
discord:
token: ''
guild-id: ''
# Channel where the verification message with the button is posted.
verify-channel-id: ''
# Role granted once a member verifies.
verified-role-id: ''
verify-message:
title: 'Verification'
body: 'Press the button below to verify and gain access to the server.'
button: 'Verify'
anti-abuse:
# A Discord account younger than this cannot produce a credit for whoever
# invited it. The single most effective filter against throwaway alts.
min-account-age-days: 7
# If an invited member LEAVES within this many days, the credit is revoked.
# A BAN always revokes, regardless of age.
hold-window-days: 7
# Maximum credits one inviter can earn per day. 0 disables the cap.
daily-credit-cap: 10
linking:
# How long a /link code stays valid.
code-expiry-minutes: 10
startup:
# After a restart, try to attribute joins that happened while the server was
# down, by matching the invite-use delta against members who joined in that
# window. Only resolves unambiguous cases; the rest are logged.
recover-missed-joins: true
# Recovery has to load the member list. Skipped above this member count.
recovery-max-guild-size: 10000
# Thresholds are counts of CONFIRMED invites (verified, not revoked).
# Every key is optional - use only the reward types you need.
# commands : run from console, %player% is replaced
# luckperms-group : requires LuckPerms; removed again if the count drops
# money : requires Vault; withdrawn again if the count drops
# items : given on next join if the player is offline; NEVER reclaimed
rewards:
5:
commands:
- 'broadcast &a%player% &7has invited 5 members!'
luckperms-group: 'vip'
money: 1000.0
10:
money: 5000.0
items:
- material: DIAMOND
amount: 8
- material: NETHERITE_INGOT
amount: 1
name: '<gradient:#f0a:#0af>Invite Reward</gradient>'
lore:
- '<gray>Thank you for growing the server.</gray>'
# MiniMessage formatting. https://docs.advntr.dev/minimessage/format.html
messages:
prefix: '<gray>[</gray><aqua>Invites</aqua><gray>]</gray> '
link-usage: '<yellow>Usage: /link <code> - run /link in Discord to get a code.</yellow>'
link-unknown-code: '<red>That code is invalid or has expired.</red>'
link-already-linked: '<red>This Minecraft account is already linked to a Discord account.</red>'
link-discord-taken: '<red>That Discord account is already linked to another Minecraft account.</red>'
link-success: '<green>Linked to Discord as <white><user></white>.</green>'
reward-granted: '<green>Reward unlocked for <white><threshold></white> invites!</green>'
reward-revoked: '<red>An invite was revoked, so your <white><threshold></white>-invite reward was removed.</red>'
items-pending: '<yellow>You had reward items waiting - they are in your inventory now.</yellow>'
inventory-full: '<red>Your inventory was full, so some reward items were dropped at your feet.</red>'
Reward thresholds are arbitrary numbers. Add as many as you like. Each one is paid exactly once.
What happens when a credit is revoked
If a revocation drops someone below a threshold they had already reached, the reward is rolled back as far as it sensibly can be. The LuckPerms group is removed and the Vault money is withdrawn. Items are not taken back, because they may already have been spent or traded away, and hunting them down would be both unreliable and hostile.
If the count later climbs back over that threshold, the group and the money return, but the items and the console commands do not fire again. Otherwise "invite, collect, get them banned, repeat" would print items.
Before you install
The bot only runs while your Minecraft server runs. That is the tradeoff for shipping it as one JAR with nothing to host.
Discord does not backfill invite attribution. It is worked out live, by comparing invite use counts at the moment somebody joins. A normal restart is a minute or two, and the recovery pass on startup resolves most of what it misses.
Servers that sleep when empty, such as Aternos, are a poor fit. The bot is offline whenever the server is, which is most of the time, so most joins will never be attributed. If that describes your host, this plugin will not work well for you.
Troubleshooting
"The bot lacks the Manage Server permission" in the console. Invite tracking is off. Re-invite the bot with Manage Server, or grant it via a role.
Members verify but nobody gets credited. Check the console at startup for the baseline message. If the Server Members Intent is disabled the bot never receives join events. Also check that the inviter is still in the guild, because credits to someone who has left are refused.
"We could not tell who invited you." The join was ambiguous: the vanity URL,
a widget invite, two simultaneous joins, or a join during downtime. Fix it with
/invitereward attribute <discordId> <inviterId>; the credit still requires the
member to be verified.
The verify button does nothing, or role assignment fails. The bot's role must sit above the verified role in your guild's role list.
Rewards not arriving in game. The player must have linked with /link.
Confirm with /invitereward status <player>, which shows the linked Discord ID,
the confirmed invite count, and the state of every threshold.











