← Use cases

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.
The auction house example: a player bids on Hunter's bow, a second window outbids them a moment later, and the first player sees the new price and an outbid notice.
The auction house example: a player bids on Hunter's bow, a second window outbids them a moment later, and the first player sees the new price and an outbid notice.

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.
Player AYour serverHibiraPlayer BPOST /auction/:id/bid120 goldhouse.bid() checks the bid and holds the goldauction-updateprice 120, A leadsauction-updateauction-update"Bid 126"
Bids go to your server; Hibira tells every player

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 auctions

Step 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 store on 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-main channel and call the same endpoints. For rooms and matchmaking, see multiplayer game rooms and lobbies.