-
Notifications
You must be signed in to change notification settings - Fork 1
Trading
The Trade system lets accounts on the same OpenMTG instance propose and complete card trades. When both sides confirm, cards transfer automatically between collections. Trade history is stored separately from your card inventory and can be cleared independently.
Trades must be enabled by an admin before they appear in the UI. See Feature Toggles below.
A trade moves through the following states:
| State | Meaning |
|---|---|
proposed |
Initiator created the trade and added their cards. Counterpart has not yet responded. |
active |
Counterpart added their cards. Both sides can edit or confirm. |
accepted |
Both parties confirmed. Cards have been transferred. |
rejected |
Counterpart declined the trade. |
cancelled |
Initiator cancelled before the counterpart responded. |
Any edit to either side's card list (while active) resets both confirmation flags, requiring both users to confirm again.
- Go to Trades in the sidebar.
- Click New Trade.
- Select the user you want to trade with.
- Use the card picker to select cards from your own collection to offer.
- Submit the proposal. The trade enters
proposedstate.
The counterpart sees a "Your Turn" indicator on the Trades page and a ! badge on the Trades nav link.
- Open the trade from the Trades list.
- Add cards from your collection to your side of the offer.
- Review the initiator's offer on the right panel (read-only).
- Confirm or reject the trade.
- Either party can add or remove cards from their own side while the trade is
active. - Any edit resets both confirmation flags.
- Click Confirm when satisfied with both sides.
- Click Un-submit to retract your confirmation and make further changes.
- Once both parties have confirmed, the transfer executes automatically.
In TradeDetail, each card in the counterpart's offer has a Camera button. Clicking it opens a viewer showing the front and back photos that user uploaded for that card entry, if any.
When both parties confirm:
- The server validates that each card being offered still exists in the source collection in the required quantity.
- For each card transferred:
- The source entry's quantity is decremented. If it reaches zero, the entry is deleted.
- The destination collection is searched for a matching entry (same card, foil flag, condition, and language). If found, quantity is incremented. If not found, a new entry is created.
- The entire operation is atomic. If any validation fails, no cards move.
Trade items store a denormalized snapshot of each card (name, image, price, foil, condition) at the time of the trade. This means trade history remains accurate even if cards are later edited or deleted.
The Trades list page has two sections:
-
Active - trades in
proposedoractivestate that involve you. -
History - completed trades (
accepted,rejected,cancelled).
Status is shown with color badges. A "Your Turn" label appears on any trade that requires your action.
The Trades nav link in the sidebar and mobile menu shows a ! badge when any trade is waiting on you.
An admin can enable or disable Trades from Admin > Settings > Feature Toggles.
When disabled:
- The Trades nav link is hidden for all users.
- Trade pages redirect to
/collection. - The pending count endpoint returns 0.
Trade history is stored in a separate SQLite database, independent of the main PostgreSQL inventory.
| Setting | Default |
|---|---|
| Database location |
TRADES_PATH env var (default ./trades); file is trades.db inside that directory |
Deleting the trades database removes all trade history without affecting any card data in PostgreSQL. See Configuration Reference for the TRADES_PATH variable.
| Method | Path | Description |
|---|---|---|
GET |
/trades/pending-count |
Number of trades awaiting your action (used for the nav badge) |
GET |
/trades |
List active trades and history, up to 50 |
POST |
/trades |
Propose a new trade |
GET |
/trades/{id} |
Trade detail |
PUT |
/trades/{id}/items |
Replace your side's items; resets both confirmation flags |
POST |
/trades/{id}/confirm |
Confirm your side; executes transfer if both sides are confirmed |
POST |
/trades/{id}/unconfirm |
Retract your confirmation |
POST |
/trades/{id}/reject |
Reject (counterpart) or cancel (initiator) the trade |
GET |
/trades/{id}/photos/{entry_id}/{side} |
Serve a card photo to either trade participant |
All endpoints require authentication. The photo endpoint is accessible to both participants in the trade, not just the card owner.