Core Concepts
Vouchers vs codes, where everything is configured, and how a redemption flows.
A quick mental model so the rest of the documentation clicks into place.
Vouchers and codes
ProVouchers has two delivery methods that share everything else:
| Voucher | Code | |
|---|---|---|
| What it is | A physical item players hold | A word players type |
| How it is redeemed | Right-click the item | /voucher redeem <code> |
| Defined in | vouchers/<id>.yml | codes/<id>.yml |
| Use limit | Per item (each item redeems once) | Per player and/or global counter |
| Rewards, conditions, effects | Same system | Same system |
If you understand one, you understand the other. The fields that differ are listed on the Voucher Reference and Code Reference pages; everything shared (rewards, conditions, text) has its own page and applies to both.
Where everything lives
plugins/ProVouchers/
├── config.yml # storage backend, anti-dupe, metrics (see Config Reference)
├── data.db # created only when the storage backend is sqlite
├── vouchers/ # one voucher per .yml file
│ ├── crate_key.yml
│ └── rank_token.yml
└── codes/ # one code per .yml file
└── launch_gift.yml- Server-wide settings (which database, anti-dupe behaviour, metrics) live in
config.yml. - Each voucher and code is its own file. The file name without
.ymlis the defaultid/code, but you can override it with theid:orcode:key inside the file. - After editing any file, run
/voucher reload. There is no need to restart.
Anatomy of a voucher file
id: crate_key # identity (defaults to the file name)
display-name: "<gold>Key" # how the item is named (MiniMessage)
item: { material: TRIPWIRE_HOOK, glow: true } # what the item looks like
lore: [ "<gray>Right-click" ] # item description lines (MiniMessage)
cooldown: 0 # per-player seconds between redeems
expiry: "" # when the item stops working
conditions: [ ... ] # who may redeem it, and where (see Conditions)
rewards: [ ... ] # what they get (see Rewards)
random-rewards: [ ... ] # weighted "pick one" rewardsOnly item is strictly required (and even then material defaults to PAPER).
Everything else has a sensible default.
How a redemption flows
When a player right-clicks a voucher (or runs /voucher redeem), ProVouchers runs
these steps in order and stops at the first failure:
- Is it a real voucher/code? Unknown or removed ids are rejected.
- Is it redeemable?
unredeemable: truevouchers are display-only. - Owner check (vouchers only):
owner-onlyvouchers reject other players. - Expiry check: expired vouchers and codes are rejected.
- Game mode gate: creative and spectator are blocked by default.
- Cooldown check: per-player, per-voucher.
- Conditions: every condition must pass; the first failure shows its message.
- Anti-dupe / use limits (checked off the main thread): a duplicate voucher item or an exhausted code is rejected.
- Rewards run: always-run rewards plus one weighted random set, each reward executed independently.
Steps 1 to 7 are instant and on the player's thread. Step 8 touches the database, so it runs asynchronously, then control returns to the player to grant rewards. This keeps the server (and Folia regions) responsive.
One self-contained plugin
Everything ProVouchers needs (scheduling, storage, text rendering, conditions, integrations, metrics) ships inside the plugin. Practically, this means:
- Conditions (permission, region, economy, and so on) share one consistent config shape (see Conditions).
- Integrations (economy, permissions, custom items, placeholders) are detected automatically, so installing a supported plugin "just works" without ProVouchers-specific setup (see Integrations).
- Text is rendered with MiniMessage and PlaceholderAPI in one place (see Text and Placeholders).
That is the whole model. The rest of the docs are reference pages for each piece.