Sealed bid auctions
Everything the create page does, as three calls, with the rules that decide what a bid means.
Try one
Run these in order against the live network. The auction closes about a minute after you open it, so you can watch a real one through from an empty board to a result.
1. Open the auction
The rules travel with it: the currency and its decimals, an optional reserve and an optional maximum. Rules that cannot be satisfied, like a maximum below the reserve, are refused here rather than at the close on an auction already running.
const auction = await peal.createAuction({
title: 'Signed tour poster',
description: 'One of a kind, ships worldwide.',
imageUrl: 'https://images.example.com/poster.jpg',
closesIn: 3600, // or closesAt: '2026-09-12T18:00:00Z'
currency: 'USD', // decimals come with the code
reserveMinor: 10_00, // nothing below this can win
maximumMinor: 500_00, // nothing above this can win
tag: 'my-shop',
});
// auction.bid_url is a hosted page bidders can open right away.
2. Place a sealed bid
The amount goes into a fixed width record and is encrypted here with batched threshold encryption, so what reaches the network is 320 bytes of ciphertext whether the bid is five dollars or five hundred thousand. Run it more than once to add bidders: none of them can see the others.
await peal.bid(auction.id, {
amountMinor: 125_00, // 125.00 in a 2 decimal currency
name: 'ana', // shown on the board, never trusted
});
3. Read the board
Null until it closes, so "not open yet" can never be read as "no bids". Afterwards: every readable bid ranked, the queue the rules allow to win, and anything discarded with the reason why.
const { winner, queue, bids, discarded } = await peal.results(auction.id);
// bids every readable bid, ranked, whether or not it can win
// queue only the ones inside the reserve and the maximum
// winner queue[0], or null if nothing qualified
The rules, and why each one is there
The rounds API gives you submissions sealed with batched threshold encryption (BTE) that open together when a threshold of the committee produces its shares. An auction is that plus the rules that decide what a bid means, and those rules are the reason this lives in the API rather than being left to every caller to get subtly wrong.
- Amounts are integers of minor units.
12.50in a two decimal currency is1250. Money in a float is a rounding error waiting for a big enough auction. - Every bid is the same size on the wire. The record is padded to 320 bytes before encryption, so a bid of five and a bid of five hundred thousand are indistinguishable until the auction opens. Without this the ciphertext length ranks the bids for anyone watching.
- A reserve and a maximum, both optional. Nothing is escrowed, so a bid is cheap talk. The maximum is what stops a joke bid of ninety nine million taking your auction.
- The result is a queue, not just a winner. For the same reason: if the top bidder does not pay, the seller works down the list rather than losing the sale.
- Ties break on batch position, which comes from the ciphertext hashes rather than arrival order. So a tie cannot be won by bidding earlier, and the coordinator cannot reorder a batch to choose a winner.
- A bid naming a different auction is discarded, with the reason. A ciphertext is not bound to a round, so the same sealed bytes can be replayed into another auction; the id inside the record is what makes that detectable.
A page bidders can open
Every auction with a title comes back with a bid_url: a hosted page where
somebody reads the terms and places a bid. You do not have to build a bidding interface to
test this, or ever, if the hosted one suits you.
The whole auction rides in the URL fragment, the part after the #. Browsers
never send a fragment to a server, so opening that link tells nobody which auction it is,
including us.
Next, the full integration: creating an auction covers the money rules, contact details, the closing time and a checklist before you ship.