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.
Built on Strata
ProVouchers does not re-implement scheduling, storage, text rendering, conditions, integrations, or metrics. It uses Strata for all of that. Practically, this means:
- Conditions (permission, region, economy, and so on) are evaluated by Strata, so they share one consistent config shape (see Conditions).
- Integrations (economy, permissions, custom items, placeholders) are provided by Strata's hooks, 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.