ProVouchers

Rewards and Effects

Every reward type, weighted random rewards, dynamic placeholders, and graceful failure.

Rewards are what a player gets on a successful redeem. Vouchers and codes share the same reward system. Each reward is a string of the form "<type>: <value>".

rewards:
  - "item: DIAMOND 1"
  - "currency: give 250"
  - "message: <green>You redeemed it!"

Two keys hold rewards:

  • rewards: runs every line, every time.
  • random-rewards: picks exactly one weighted set per redeem (see Random rewards).

Reward types

Type (and aliases)Value formatEffect
command (console-command, console)a commandRuns from the console
player-command (p-command)a commandRuns as the player
message (msg, tell)MiniMessagePrivate message to the player
broadcast (announce)MiniMessageMessage to the whole server
titletitle|subtitleTitle and subtitle
actionbar (action-bar)MiniMessageAction bar text
soundkey [volume] [pitch]Plays a sound
item (give-item)<reference> [amount]Gives an item (vanilla or provider)
itemsadder / oraxen / nexo<id> [amount]Provider item shorthand
currency (economy, money, eco)[give|take] <amount>Gives or takes currency
group (rank)<add|remove> <group> [duration]Adds or removes a permission group
permission (perm)<add|deny|remove|set> <node> [value]Sets or clears a permission node
discord<@name|url> <message>Posts a message to a Discord webhook

command and player-command

rewards:
  - "command: give %player% diamond 1"   # from console
  - "player-command: spawn"              # run as the player

command runs from the server console (full permissions). player-command runs as the player, subject to their permissions.

message, broadcast, title, actionbar

rewards:
  - "message: <green>Enjoy your reward!"
  - "broadcast: <gold>%player% <yellow>just redeemed a Legendary voucher!"
  - "title: <gradient:#FFD700:#FF4500>WELCOME</gradient>|<gray>to the server"
  - "actionbar: <yellow>Reward claimed"

title splits on the first | into title and subtitle; the subtitle is optional. All four accept MiniMessage and PlaceholderAPI (see Text).

sound

rewards:
  - "sound: minecraft:entity.player.levelup"
  - "sound: minecraft:ui.toast.challenge_complete 1 1.2"

The value is a namespaced sound key, then optional volume and pitch (both default to 1).

item

rewards:
  - "item: DIAMOND 5"                                # vanilla material [amount]
  - "item: NETHERITE_SWORD"                          # amount defaults to 1
  - "item: itemsadder:ax_wings_pack:phoenix_wings 2" # provider item

The value is an item <reference> [amount]. The reference is either a vanilla material or a provider:id custom item (see Items). Vanilla material names are validated at load; provider items are resolved at redeem time. The reference can also be @<name> for a decorated item from the file's items: map: item: @vip_sword 1.

The amount may be a literal number or a placeholder such as %random:1-3%, which is substituted just before the item is given (so item: GOLD_INGOT %random:1-3% grants 1 to 3 ingots).

The provider keywords are shorthand that fold the provider into the reference:

rewards:
  - "itemsadder: ax_wings_pack:phoenix_wings"   # same as item: itemsadder:...
  - "oraxen: cool_sword 1"
  - "nexo: magic_wand"

If the player's inventory is full, the overflow is dropped at their feet.

currency

rewards:
  - "currency: give 250"
  - "currency: take 100"
  - "currency: 500"              # no verb means give
  - "currency: give %random:100-500%"

currency deposits to or withdraws from the player's balance through the server economy. The verb (give or take) is optional and defaults to give. It works with Vault and any Vault-compatible economy (EssentialsX, CMI, ExcellentEconomy, CoinsEngine, PlayerPoints via its Vault bridge) for that provider's currency, with no extra setup. If no economy is installed, the reward is skipped and logged.

xp

rewards:
  - "xp: 500"               # experience points
  - "xp: 30 levels"         # levels
  - "xp: %random:5-10% levels"

group

rewards:
  - "group: add vip"          # permanent membership
  - "group: add vip 7d"       # temporary, expires in 7 days
  - "group: remove trial"     # remove from a group
  - "rank: add mvp 30d"       # rank is an alias for group

group adds the player to or removes them from a permission group. An optional duration on add (7d, 12h, 90m, 45s) makes the membership temporary and self-expiring. This needs a group-aware, write-capable permission provider (LuckPerms); without one the reward is skipped and logged. Groups are not created by ProVouchers; the group must already exist in your permissions plugin.

permission

rewards:
  - "permission: add essentials.fly"        # set the node to true
  - "permission: deny some.restricted.node" # set the node to false
  - "permission: remove essentials.fly"     # clear a directly-set node
  - "permission: set some.node false"       # set an explicit value
  - "perm: add worldedit.navigation.jumpto" # perm is an alias

permission sets or clears a single permission node on the player. add/deny set the node to true/false, remove clears a node you previously set, and set <node> <true|false> is the explicit form. This also needs a write-capable permission provider (LuckPerms).

Group and permission rewards are written off the main thread (permission writes hit the data store). Pair them with a message: reward if you want to tell the player what they received. Granting a temporary group is the clean way to sell timed ranks, replacing fragile command: lines like lp user %player% parent addtemp ....

discord

rewards:
  - "discord: @announce <gold>%player%</gold> hit the rare reward!"   # content
  - "discord: @rare-drop"                                             # a payload template
  - "discord: https://discord.com/api/webhooks/123/abc %player% redeemed"  # inline URL

discord posts to a Discord webhook. The first token is the target: an @name from the voucher (or code) file's own discord-webhooks: map, or an inline webhook URL. Webhooks are defined per file, alongside the items: map, as either a plain URL (the reward supplies the message, posted as the content) or a { url, payload } block whose payload template is rendered and posted as-is:

vouchers/mystery-crate.yml
discord-webhooks:
  announce: "https://discord.com/api/webhooks/..."   # content-only
  rare-drop:                                          # full payload template
    url: "https://discord.com/api/webhooks/..."
    payload:
      username: "Crate Bot"
      embeds:
        - title: "Rare drop!"
          description: "%player% hit the jackpot, rolling %random:1-1000:roll%."
          color: 16766720

rewards:
  - "discord: @announce %player% opened a crate!"
random-rewards:
  - weight: 1
    rewards:
      - "discord: @rare-drop"

A reward using a payload-template webhook needs no message (discord: @rare-drop); the template is the message. Placeholders (%player%, %arg%, %random%, PlaceholderAPI) are resolved in every string of the template (numbers like color pass through), then it is serialized to JSON, so a resolved value containing quotes is escaped rather than able to corrupt the payload. The @name form is recommended so the secret URL lives in one place. The POST is asynchronous and a failure is logged, never aborting the other rewards. Put a discord reward in a random-rewards set to announce only the rare hits; during a batch open it is skipped, like other notifications, so a stack does not spam the webhook.

Placeholders

Before MiniMessage and PlaceholderAPI run, these placeholders are substituted in every reward value:

PlaceholderBecomes
%player%The redeeming player's name
%arg%The argument from /voucher redeem <code> <arg> (codes with has-argument)
%random:min-max%A random integer in the inclusive range
%random:min-max:name%A named roll: the same name resolves to one shared value per redeem

(%expiry% is also available, but only in a voucher's display name and lore: see Vouchers.)

The curly-brace forms ({player}, {arg}, {random:min-max}) are deprecated but still work; /voucher reload warns when a file uses them.

rewards:
  - "command: give %player% gold_ingot %random:1-3%"
  - "broadcast: <gold>%player% won %random:100-1000% coins!"

Named random: give exactly what you announce

A plain %random:min-max% rolls a fresh value every time it appears. Add a name (%random:min-max:name%) and the first occurrence in a redeem rolls once; every later use of that same name reuses the value. This lets one reward give an amount and another announce the very same amount:

rewards:
  - "currency: give %random:100-500:coins%"
  - "broadcast: <gold>%player% won %random:100-500:coins% coins!"   # same number

Each distinct name has its own value, and unnamed rolls stay independent. The value is cached only for the duration of a single redeem.

%player% and PlaceholderAPI placeholders (%vault_eco_balance%, and so on) both work; see Text and Placeholders for the resolution order.

Random rewards

random-rewards is a list of weighted sets. Exactly one set is chosen per redeem, with probability proportional to its weight over the total. The chosen set runs in addition to the always-run rewards.

rewards:
  - "message: <gray>Opening..."            # always runs
random-rewards:
  - weight: 70
    rewards:
      - "item: GOLD_INGOT %random:1-3%"
  - weight: 25
    rewards:
      - "item: DIAMOND 1"
  - weight: 5
    rewards:
      - "item: NETHERITE_INGOT 1"
      - "broadcast: <gradient:#FF4500:#FFD700>%player% hit the JACKPOT!</gradient>"

Weights do not need to sum to 100; they are normalised. In the example above the chances are 70%, 25%, and 5%.

Graceful failure

Each reward runs independently. If one reward fails (a command that errors, a provider item that is not installed, a missing economy), it is logged against its voucher or code and skipped, and the remaining rewards still run. A typo that can be caught earlier (an unknown reward type, a bad item material, a non-numeric currency amount) is reported by /voucher reload instead, before the voucher is ever used.

On this page