DEV3 Bidhaus – Online Auction Laravel Script with Proxy Bidding, Anti-Sniping, Escrow & Flutter App

A self-hosted timed-auction platform on Laravel 12 and Filament 4: proxy bidding, anti-sniping extensions, reserves, deposits, buyer's premium, escrowed settlement, second-chance offers, consignor and admin panels, a REST API and a Flutter bidder/consignor app.

by DEV3 TechnologiesVerified Author(0) 0 sales 1 viewsUpdated 04 Nov 2026

Video tour. Pick a section below to browse 106 screenshots in 8 sections.

Bidhaus is a self-hosted timed-auction platform by DEV3 Technologies: a Laravel 12 + Filament 4 backend, one Flutter app for bidders and consignors, a public catalogue and a marketing site. Lots close on a clock, bidders enter a private maximum, and the engine bids for them in increments. Winners pay into escrow, consignors ship, and money is released when delivery is confirmed. The bundled demo house is the fictional "Harrowmere Rooms" in Port Lindqvist.

No live demo: the 72 grouped web screenshots and two video tours above show the catalogue, the checkout and every staff and consignor panel. Install with demo data to try each role on your own server. The Flutter app runs on its own offline demo mode; its 34 screenshots are in the download's apps/bidder folder.

Bidding engine

  • Every bid is a maximum. A challenger above the leader's maximum wins at the lower of their own maximum and the leader's maximum plus one increment. Otherwise the earlier bidder stays ahead. Ties go to the earlier bid.
  • Increment table with bands (the band with the largest from-amount at or below the price applies), editable in the admin panel.
  • Reserve prices stay private: only "has reserve" and "reserve met" are public. A maximum that reaches the reserve lifts the price to it.
  • Anti-sniping: a bid that changes the price or the leader in the last 120 seconds adds 120 seconds, capped by a hard close set 60 minutes after the original end. All three numbers are settings.
  • Staggered sales: an event closes one lot after another at a set interval, and each lot extends on its own.
  • Buy now with a rule you choose (until the first bid, or until the reserve is met). Bids are idempotent per client key.
  • The public JSON never carries other bidders' maximums, the reserve value or identities. Bidders appear as masks that are stable per lot.

Deposits, orders and escrow

  • A refundable deposit can be held from the bidder's wallet on the first bid of higher-value lots. Losers are released at close, and the winner's deposit is applied to the invoice.
  • The invoice shows hammer price, buyer's premium (category override or global), shipping, tax and the deposit already applied.
  • Payment goes into escrow. Settlement to the consignor, commission, premium and tax runs when the buyer confirms delivery or after a release period, unless a dispute is open.
  • Refunds before release come out of escrow. After release they reverse from the consignor's earnings, the tax wallet and the platform. Partial refunds split in proportion.
  • Every money movement is a ledger entry with an idempotent key, so a repeated job or a duplicate payment never moves money twice.
  • Defaults: an unpaid winner forfeits the deposit and gets a strike, and repeated strikes block bidding. The next bidder can receive a second-chance offer. A reserve-not-met lot lets the consignor offer the high bidder the lot.
  • Voiding: staff can void a bidder with a recorded reason. The engine replays the remaining placements to rebuild the price, leader and counters.

Panels

  • /admin: dashboard with KPIs and a 3D Closing Room, lots with moderation, status tabs and the hidden-maximum view, events, categories, increment tables, consignors with KYC, bidders with limits, strikes and blocks, orders, shipments, disputes, second-chance offers, defaults, forfeits, fraud flags, escrow statement, wallets, payouts, tax rates, reports, settings, roles and audit log.
  • /seller: consignor dashboard, a five-step lot wizard, lot performance with a price chart, orders to ship, disputes, earnings, payouts, reviews, messages and KYC documents.
  • /account: my bids, watchlist, orders, second-chance offers, wallet with held deposits, addresses and chat.
  • Public catalogue: lots with filters (department, status, closing window, reserve, sort), sales, consignor pages, how-it-works and a 3D marketing story (gavel, proxy columns, closing countdown, SOLD stamp).

Flutter app

One app with buy and sell modes: home, browse and filters, lot detail with a countdown that follows the server clock, bid sheet, my bids, watchlist, wallet, orders and tracking, lot wizard, consignor orders, earnings and chat. Light, dark and Arabic. Demo mode needs no server; to use your backend, point it at /api/v1.

Also included

  • REST API under /api/v1 with Sanctum tokens that only carry the bidder app ability, an error envelope with stable codes, and an OpenAPI file.
  • English and Arabic (right to left) on the public site and the marketing pages, dark and light themes.
  • Web installer and command-line installer, demo and empty data, cron jobs for closing lots, opening scheduled lots, settling escrow and processing defaults, optional Reverb for live pushes (otherwise polling every 5 seconds, every 2 seconds in the last five minutes).
  • Roles (admin, auction manager, finance, support, consignor, bidder), audit log, devices and push log from the shared DEV3 core.

Quality checks

  • 130 Pest tests (20,912 assertions) pass, plus Larastan level 6 with 0 errors and Pint clean.
  • A browser smoke run checked 81 pages. A concurrency check fires parallel bids at one lot on MySQL.
  • The installer was tested from the packaged zip, on MySQL and SQLite seeds.
  • The Flutter app passes format, analyze (0 issues) and 62 tests, and a debug Android build completes.
  • The public page ships 10.8 KB of JS and 16.5 KB of CSS gzipped, with three.js loaded lazily.

Good to know

  • Payments are not tested live. The simulated gateway is the default. Stripe, Razorpay and PayPal drivers are present, but none has been run against a live or sandbox account. Card money only moves when the gateway confirms payment.
  • SMS, email providers and push are not tested live. Push (FCM and APNs), real carriers and SMS are interfaces only. Mail goes to the log in demo mode.
  • The app has not been run on physical phones. It was tested with unit and widget tests, a debug Android build, and screenshots from a simulator. Store builds, signing and push setup are yours to do.
  • The app's server mode is untested against a live deployment. In the packaged build it defaults to demo mode.
  • Fraud rule 1 (shared device or IP with the consignor) only sees consignors who have also placed bids on the platform.
  • Second-chance offers have no unique database index on lot and origin. The code re-checks under the lot lock instead.
  • The web gallery shows only step one of the five-step consignor lot wizard (on three different lots). The Flutter app's wizard steps are in the download's apps/bidder screenshots.
  • The lot image art is generated in code (SVG), with no photo uploads in the demo data.
  • Right-to-left Arabic is shown on the public site, the marketing story and the app home. No Lighthouse score is recorded for this product; the measured public page weight is given above.
  • No hosted demo. Requires PHP 8.2+; Node.js is not needed. The Flutter source is included, and you need the Flutter SDK to build the app.

How it's built

Architecture, stack, key decisions and the quality gates DEV3 Bidhaus passed before release.

The engineering behind Bidhaus: a pure PHP auction engine ported to Dart and tested against one vector file, bids placed under a row lock on the lot, anti-sniping with a hard close, idempotent ledger keys, replay-based voiding and a REST API that never leaks a maximum.

The problem it solves

A timed auction is a race with money attached. Two bids can arrive in the same millisecond a lot closes, a maximum bid must stay secret while the price still has to be explained, and a refund or a voided bid has to leave every wallet consistent. The rules also repeat on every screen: the website, the admin panel and a mobile app all show the same price, leader and countdown, and a phone with a wrong clock must never announce a winner. Settlement adds more: deposits held per lot, a winner who never pays, a reserve that was not met, a dispute opened after the consignor was paid. If any of these is handled in more than one place, the places drift apart.

Architecture and approach

Bidhaus is a Laravel 12 application with three Filament 4 panels (/admin, /seller and /account) over one user table, a public Blade catalogue and a Flutter app. The auction rules live in one place.

A pure engine

  • No database, no clock. AuctionEngine takes a state and a placement and returns the new price, leader and ladder rows. Every bid is a maximum, so an exact bid is simply a maximum equal to the minimum next bid.
  • One vector file, two languages. The same JSON of worked cases (the spec cases plus 24 extras) is run by the PHP tests and by the Dart port inside the app, so demo mode and the server cannot disagree about who is leading.
  • Invariants. Price never falls, never exceeds the leader's maximum, and the sequence number only rises. Property tests run seeded random sequences against them, and a replay test checks that incremental state equals a rebuild from the placements.

Placing a bid

  • A row lock on the lot. BidService::place locks the lot, reads the time after the lock, checks idempotency by client key, then the lot window, the bidder, the limit, the amount and the deposit. The lock order is always lot, then wallet.
  • Anti-sniping with a ceiling. A bid that changes price or leader inside the window extends the lot once per transaction, capped at the hard close frozen when the lot goes live.
  • Public data only. The live endpoint returns the server time, a sequence number, price, minimum next bid and a stable masked leader. The app computes a clock offset from each response, ignores older sequence numbers and shows "Closing…" at zero until the server says sold.

Money

  • Idempotent ledger keys. Payment, wallet payment, deposit application, settlement, refunds and defaults each write entries under a key such as order-settle-{order}, so a repeated job writes nothing new. Card money moves only on a confirmed payment event, and a payment for a defaulted order or with a stale amount is refunded at once.
  • One order per lot and source. A unique index makes a double run of the closing job safe.
  • Voiding by replay. Staff voiding marks a bidder's placements and derived ladder rows, then replays the rest through the engine. The end time never moves, and the demo data's wallets reconcile with the ledger.

Shared DEV3 core and realtime

Installer, settings, roles, audit log, wallets, payouts, tax and the Flutter foundation come from DEV3's shared packages. Events publish after the database commit; without Reverb, the site and app poll every 5 seconds, every 2 in the final five minutes.

Quality gates and results

Bidhaus 1.0.0 passed the DEV3 Laravel release gates and the Flutter gates:

  • Static analysis: composer validate, php -l on 397 files, Pint clean and Larastan level 6 with 0 errors.
  • Tests: 130 Pest tests with 20,912 assertions, including the engine vectors and properties, replay, anti-sniping boundaries, closing, deposits, settlement money, defaults and second chance, voiding, buy now and the API contract.
  • Front-end budget: 10.8 KB of JS and 16.5 KB of CSS gzipped on the public page, with the three.js chunk (187.4 KB gzipped) loaded lazily.
  • Seeding: demo and empty seeders on MySQL 8 and SQLite; the demo data holds about 9,800 bid placements and 428 lots.
  • Browser smoke: 81 pages checked headless, with a parallel-bid race on a seeded lot.
  • Installer: the packaged zip was unzipped and installed through the web wizard on MySQL with demo data.
  • Secret scan: clean.
  • Flutter app: format, analyze with 0 issues, 62 tests and a debug Android build.

Not verified: live payment gateways, push and SMS, or the app on physical phones. The Good to know section on the listing lists the known gaps.

Tech stack

Area Technologies
Backend Laravel 12, Filament 4 panels per role, Livewire 3, Laravel Sanctum REST API, spatie/laravel-permission, Scheduler and database queue, Optional Laravel Reverb
Auction engine Pure AuctionEngine, BidService under row lock, Anti-sniping with hard close, Replay-based voiding, Shared test vector file
Money Escrow ledger, Idempotent ledger keys, Deposit holds, Second-chance offers, Simulated gateway driver
Frontend Blade, Tailwind CSS 4, Vite 7, Lenis, three.js
Mobile Flutter, Riverpod, go_router, dio, Dart port of the engine
Data MySQL 8 / MariaDB, SQLite, Integer cents, Deterministic demo seeders, Audit log

Inside the build

Gavel room: A brass gavel above a black marble block under one museum spotlight, in a dark room. Gavel room — A brass gavel above a black marble block under one museum spotlight, in a dark room.

Proxy bidding: Two translucent price columns climb in increments as the higher maximum pulls ahead. Proxy bidding — Two translucent price columns climb in increments as the higher maximum pulls ahead.

Guides & articles

Practical guides and engineering write-ups for DEV3 Bidhaus.

Online auction script: 8 rules to test before you launch

Last updated
Online auction script: 8 rules to test before you launch: DEV3 Bidhaus

Auction scripts look alike in a feature list: lots, bids, a countdown, a winner. The differences appear under load and at the edges, when two people bid in the last second, when a tied maximum is entered, when a winner never pays, or when a bid has to be removed after the price has climbed. This guide covers eight rules worth testing before you pick a self-hosted timed-auction script, and how Bidhaus, built on Laravel 12, Filament 4 and a Flutter app, handles each one.

Bidhaus marketing story: two translucent price columns climb in increments as the higher maximum pulls ahead

1. Is every bid a maximum, and who wins a tie?

Proxy bidding means the system bids for you up to a private ceiling. Ask what happens when a challenger's maximum is higher than the leader's, lower, or exactly equal. Many scripts handle the first two and guess at the third.

In Bidhaus every bid is a maximum; an "exact" bid is just a maximum equal to the minimum next bid. A challenger above the leader's maximum wins at the lower of their own maximum and the leader's maximum plus one increment. Otherwise the earlier bidder stays ahead, and a tie goes to the earlier bid. The rules are a small pure function with no database and no clock, so they can be tested alone.

2. Does the same logic run on every screen?

If the website, the admin panel and the phone each work out the price, they will eventually disagree. Bidhaus keeps the rules in one engine. The Flutter app carries a Dart port of it for its offline demo mode, and the PHP tests and the Dart tests run the same JSON file of worked cases, so the two cannot drift without a test failing.

3. What stops a last-second race?

Two bids that land together must not both win. Bidhaus places each bid under a row lock on the lot, reads the time after the lock is taken, and treats a bid at exactly the closing time as closed. A repeated request with the same client key returns the stored result rather than a second bid. Ask any vendor how their script behaves with parallel requests on a real database, not just in a single-threaded test.

Bidhaus anti-sniping story: the countdown flips, the gavel hovers and the clock jumps back two minutes

4. How does anti-sniping end?

An extension rule needs a ceiling, or a lot never closes. In Bidhaus a bid that changes the price or the leader inside the closing window adds time, once per transaction, and the lot can never run past a hard close fixed when it went live. The window, the extension and the hard close are settings. A staggered sale closes lots one after another at a set interval, and each lot extends on its own.

Bidhaus Sale page: a staggered closing schedule, one lot every ninety seconds

5. Are reserves and maximums really private?

The public price endpoint should never reveal the leader's maximum, the reserve value or who is bidding. Bidhaus exposes only whether a lot has a reserve and whether it is met, and shows bidders as masks that are stable within a lot. Staff, by contrast, can open a lot and see every bidder's maximum.

Bidhaus admin lot view showing each bidder's hidden maximum with a void action

6. What happens to the money around a win?

Check the order of operations: buyer's premium, shipping, tax and deposit. Bidhaus holds a refundable deposit on the first bid of higher-value lots, releases it for losers at close, and applies it to the winner's invoice. The premium comes from a category override or the global setting. Payment goes into escrow, and settlement to the consignor runs when the buyer confirms delivery or after a release period, unless a dispute is open. Every ledger entry carries an idempotent key, so a repeated job or a duplicate payment does nothing the second time.

Bidhaus admin order view splitting hammer, premium, commission and tax

7. What if the winner does not pay?

An unpaid order past its payment window becomes a default: the deposit is forfeited, the bidder gets a strike, and enough strikes block bidding. The next highest bidder can receive a second-chance offer for a limited time. When a reserve is not met, the consignor can offer the lot to the high bidder. Disputes can end in a full refund, a partial refund or a rejection, with the split worked out automatically.

Bidhaus dispute resolution: refund in full, in part or reject

8. Can you remove a bad bid cleanly?

Deleting a row from a bid table leaves the price and leader wrong. In Bidhaus, staff void a bidder with a recorded reason. The engine replays the remaining placements in order and rebuilds price, leader and counters, and the lot's end time never moves. A sold-but-unpaid lot cancels its order and can go to a second-chance offer.

See it in action

The tour follows a bid through the catalogue, the closing countdown and the invoice, then the admin Closing Room.

Video tour of Bidhaus

What else to compare

  • Fraud flags: shared devices, one-sided bidding and repeat defaults are flagged for staff review. Bidhaus's device rule only sees consignors who have also bid.
  • App: one Flutter app with buy and sell modes. It was tested with unit and widget tests and a debug Android build, not on physical phones.
  • Payments and push: the simulated gateway is the default, and Stripe, Razorpay and PayPal drivers are present but were not run against live accounts. Push and SMS are interfaces only.
  • Quality: 130 Pest tests and Larastan level 6 with no errors on the backend, and 62 tests on the app.

Frequently asked questions

The complete source code (version 1.0.0) as a download from your account, with the setup and usage guides shown on this page. You can modify the code to suit your product.

Buying guides: Laravel scripts with Filament panels and a web installer · Next.js or Laravel for a SaaS script?

More from this author

View all

Related in Web Scripts & Software

View all