Safe and convenient player-to-player trading: items, money, experience levels and points in a single window with double confirmation.
About
InTrade is a server-side plugin for direct trading between players. Your offer is on the left, your partner's offer is on the right. Each side has 16 item slots plus buttons for the available currencies. No client mods are needed, everything works through a regular inventory menu.
The main goal of the plugin is to keep trades fair. Swapping an item at the last moment is impossible: any change resets both players' readiness and is immediately highlighted for the partner.
Features
- One window for both players: 16 slots per side. Left click adds a stack, right click adds a single item.
- Multiple currencies: money (Vault), whole experience levels, PlayerPoints. Amounts can be entered as
1500,2.5kor1m. - Anti-scam protection: after any change the "Ready" button is locked for 3 seconds, changed items are highlighted for 6 seconds, and a red marker stays where an item was removed. The final countdown after both players confirm lasts 3 seconds, and any change stops it.
- Shulker box and bundle preview: view the contents of your partner's containers before the trade.
- Inventory space check: the trade won't complete if the items have nowhere to go.
- Item recovery: anything that doesn't fit when returned, and the items of a player who dies during a trade, are saved for
/trade claim. - Trade history: a menu showing the items and currencies of every completed trade.
- Stats and leaderboard: trade counter and top list that are not reset when history is cleaned up.
- SQLite or MySQL/MariaDB: works out of the box, and several servers can share one database if needed.
- Per-client language: in
automode every player sees menus and messages in their game language. English and Russian are included, texts use MiniMessage. - Bedrock support: Geyser/Floodgate players enter amounts through a native form.
- Rank-based access: trading and individual currencies can be unlocked from a specific rank via LuckPerms.
- Quick request: Shift + right click on a player.
- PlaceholderAPI and a developer API.
How a trade works
- Run
/trade <player>or Shift + right click a player. They accept with/trade accept. - Add items from your inventory. To take an item back, click it in the trade window.
- Choose a currency and enter an amount.
- Check your partner's offer and click Ready. Once both players confirm, a short countdown starts, after which the trade completes.
Requirements
- Paper 1.21.7 or newer.
- The Java version your Paper build requires (21 minimum).
- Internet access on first launch: Paper downloads the required libraries automatically.
Optional integrations:
| Plugin | Adds |
|---|---|
| Vault + an economy plugin | Money in the trade window |
| PlayerPoints | Trading points |
| Floodgate | Native amount input form for Bedrock players |
| PlaceholderAPI | Stats and player state placeholders |
Items and experience levels work without any dependencies.
Installation
- Put
InTrade-x.x.x.jarinto thepluginsfolder. - Restart the server.
- If needed, edit
plugins/InTrade/config.ymland run/trade reload.
Commands
| Command | Description |
|---|---|
/trade <player> |
Send a request or accept an incoming one from this player |
/trade accept [player] |
Accept a request |
/trade deny [player] |
Deny a request |
/trade toggle |
Enable or disable incoming requests |
/trade claim |
Collect items saved for you |
/trade history [player] |
Your own history; for staff, another player's history |
/trade reload |
Reload configuration and translations |
Alias: /intrade. By default a request lasts 60 seconds, with a 5-second cooldown between requests.
Permissions and rank-based access
| Permission | Default | Access |
|---|---|---|
intrade.player |
everyone | All player permissions |
intrade.use |
everyone | Requests and /trade claim |
intrade.sneak |
everyone | Requests via Shift + right click |
intrade.toggle |
everyone | Toggling incoming requests |
intrade.history |
everyone | Own history |
intrade.currency.money |
everyone | Vault money |
intrade.currency.experience |
everyone | Experience levels |
intrade.currency.playerpoints |
everyone | PlayerPoints |
intrade.admin |
op | All staff permissions |
intrade.history.others |
op | Other players' history |
intrade.reload |
op | Reloading settings |
intrade.bypass.distance |
op | Bypass distance and world restrictions |
intrade.bypass.cooldown |
op | Bypass request cooldown |
intrade.bypass.blocked |
op | Trade blocked items |
Wildcard nodes: intrade.*, intrade.currency.*, intrade.bypass.*.
Trading only from a certain rank. Set in the config:
permissions:
open-to-everyone: false
Run /trade reload and grant access to a group:
/lp group rank3 permission set intrade.player true
Higher ranks get access if you have group inheritance set up. Example: trading is available from rank 3, but money only from rank 5:
/lp group rank3 permission set intrade.currency.money false
/lp group rank5 permission set intrade.currency.money true
config.yml
# InTrade configuration.
# Messages and menu texts are in lang/<language>.yml.
# "auto" shows every player the messages in their game language. English and Russian are included,
# other languages can be added as new files in lang/. Any other value (for example "ru") uses one
# language for everyone.
language: auto
# Used for the console and for game languages without a file in lang/.
default-language: en
permissions:
# true: all players can trade by default.
# false: players need intrade.player (or individual permissions) from a permissions plugin such as LuckPerms.
# Staff permissions are always limited to operators by default.
open-to-everyone: true
requests:
# Time before an unanswered request expires.
expire-seconds: 60
# Minimum time between two requests from the same player.
cooldown-seconds: 5
# Allow sending a request by sneaking and right-clicking a player.
sneak-click: true
# Maximum distance between players. 0 disables the check.
max-distance: 0
# Allow trades only between players in the same world.
same-world: false
safety:
# Time after any change during which the "Ready" button is locked.
change-lock-seconds: 3
# Time a changed or removed item stays highlighted for the partner.
highlight-seconds: 6
# Countdown after both players are ready. Any change stops it.
confirm-seconds: 3
currencies:
# Requires Vault and an economy plugin.
money:
enabled: true
# Whole experience levels.
experience:
enabled: true
# Requires PlayerPoints.
playerpoints:
enabled: true
# Materials that cannot be traded.
blocked-items: []
# - BEDROCK
# - BARRIER
# Worlds where trades cannot be started.
disabled-worlds: []
history:
enabled: true
# Trades older than this are deleted on startup. 0 keeps all trades.
# Trade counts and the top list are not affected.
keep-days: 90
# Changes in this section require a server restart.
storage:
# sqlite: local file plugins/InTrade/trades.db, no setup required.
# mysql: MySQL or MariaDB server, configured below.
type: sqlite
# Unique name of this server. Only needed when several servers use the same MySQL database.
# Items in open trade windows and /trade claim mail are kept per server,
# trade history and trade counts are shared.
server-id: main
mysql:
host: localhost
port: 3306
database: minecraft
user: root
password: ""
# Number of connections. One is used for writing, the rest for reading.
pool-size: 4
# Additional JDBC driver properties.
properties:
useSSL: false
allowPublicKeyRetrieval: true
PlaceholderAPI placeholders
| Placeholder | Value |
|---|---|
%intrade_trades% |
Number of the player's completed trades |
%intrade_trading% |
Whether the player is currently in a trade |
%intrade_accepting% |
Whether the player accepts incoming requests |
%intrade_top_<1-10>_name% |
Name of the player at the given leaderboard position |
%intrade_top_<1-10>_trades% |
Trade count of the player at that position |
History and database
By default history is kept for 90 days, cleanup runs on server startup. history.keep-days: 0 disables deletion. Trade counters and the leaderboard are stored separately and are not reset by cleanup.
SQLite works without setup, the database is located at plugins/InTrade/trades.db. For MySQL or MariaDB set storage.type: mysql, fill in the storage.mysql section and restart the server. Tables with the intrade_ prefix are created automatically.
Server networks. Several servers can use one database with shared history and stats. Each server needs a unique storage.server-id: pending offers and items for /trade claim are bound to a specific server.
Developer API
The api module gives access to stats and trade events. Add it as compileOnly and put InTrade in your plugin's depend or softdepend.
import me.spolzer.intrade.api.InTrade;
InTrade trade = InTrade.get();
trade.tradeCount(player.getUniqueId()).thenAccept(count ->
getLogger().info("Completed trades: " + count));
TradeRequestEventandTradeStartEventare cancellable.TradeCompleteEventcontains both offers.TradeCancelEventprovides the cancellation reason.- Stats are returned as a
CompletableFuture. Switch to the main server thread when working with Bukkit objects.
FAQ
Is a client mod required? No, the plugin is fully server-side.
Can I block certain items from being traded?
Yes, via the blocked-items list in the config. Staff with intrade.bypass.blocked can still trade them.
Can I restrict trading by distance or world?
Yes: max-distance, same-world and disabled-worlds.
What happens if a player leaves or dies during a trade?
The trade is cancelled and items are returned to their owners. Anything that doesn't fit in the inventory is saved for /trade claim.
How do I add my own language?
Create a lang/<code>.yml file based on en.yml or ru.yml.
Is there absolute protection against server crashes? Pending offers are written to the database and restored after a restart. However, player data saving, database writes and third-party economy operations are not combined into a single transaction, so a 100% guarantee cannot be given if the server crashes.
Information
Pinned Versions
- R1.21.7–26.3
Pages
Members
1Owner