Game auction houses and player markets
Live listings, bids and countdowns in every client, a last-seconds extension against sniping, buy now and sale prices, with your server deciding every bid and your game keeping the coins and items.
An auction house, trading post or player market keeps a game's economy moving, and it only feels fair when everyone sees the same thing at the same time: the new price the moment someone bids, the same countdown on every screen, and a sale that cannot be stolen in the last second. The open-source @hibira-io/auction package gives you that on Hibira, with your own server deciding every bid.
What your players get
- Listings that appear, change price and disappear in every open client, without refreshing.
- Countdowns that agree with the server's clock, and a bid in the last seconds that adds time instead of sniping.
- "You were outbid" the moment it happens, buy now, and the recent sale prices of each item.

Built with
- One public or private channel per house (
auction-main), carrying one event,auction-update, with the whole listing and a version number. - The HTTP API (
trigger) from your server, so each change is published once however many players watch it. - @hibira-io/auction: the server part checks bids, extends late auctions and settles them; the client part keeps the newest copy of each listing and catches up after a reconnect.
Step 1: create the house on your server
Your game keeps the items and the coins. The house asks you to hold a bidder's coins, to give them back when someone bids higher, and to move the item and the coins when an auction closes:
import Pusher from 'pusher';
import { createAuctionHouse } from '@hibira-io/auction/server';
const hibira = new Pusher({ appId, key, secret, host: 'ws.hibira.io', useTLS: true });
const house = createAuctionHouse({
pusher: hibira,
name: 'main',
extendWithin: 30000, // a bid in the last 30 s adds time
reserve: async ({ userId, amount }) => {
if (!(await wallet.hold(userId, amount))) throw new Error('not enough gold');
},
release: async ({ userId, amount }) => wallet.unhold(userId, amount),
settle: async ({ listing }) => game.deliver(listing), // idempotent by listing.id
});
house.start(); // closes and settles ended auctionsStep 2: four endpoints
Take the player from your own session, never from the request body:
app.get('/auction', async (req, res) => res.json(await house.snapshot()));
app.post('/auction/:id/bid', requireLogin, async (req, res) => {
try {
res.json(await house.bid({ listingId: req.params.id, bidderId: req.user.id, bidder: { name: req.user.name }, amount: req.body.amount }));
} catch (err) {
res.status(err.status ?? 500).json({ error: err.code });
}
});
// The same for house.buyout() and house.list()Step 3: show the house in the game
import { AuctionHouse } from '@hibira-io/auction';
const house = AuctionHouse.open(pusher, 'main', {
load: () => fetch('/auction').then((r) => r.json()),
});
house.on('change', ({ listings }) => render(listings));
setInterval(() => listings.forEach((l) => showTimeLeft(l, house.timeLeft(l))), 250);
bidButton.onclick = () => fetch(`/auction/${l.id}/bid`, { method: 'POST', body: JSON.stringify({ amount: l.minBid }) });house.prices(type) returns the recent sale prices of an item type for a price chart. After a reconnect the house loads the snapshot again, so nothing is missed.
Try it
The auction house example is a complete Next.js game market: NPC traders, a bag, buy now, outbid notices and sale prices, in seven languages. Open it in two windows and bid in one.
Tips
- Every change is one message, however many players watch. Split a large house by category or region (
name: 'weapons') so each client loads only what it shows. - With several game servers, give the house a
storeon your database; saves are compare-and-set, so two servers cannot both accept the same bid. - It moves your game's own coins and items, not real money.
- Clients on Unity, Godot or any Pusher SDK can follow the same
auction-mainchannel and call the same endpoints. For rooms and matchmaking, see multiplayer game rooms and lobbies.