Skip to content

PayPal sandbox only. No real money moves.

ReferenceReference

API reference

The HTTP API of the GAVEL host as an OpenAPI 3.1 document, with authentication, errors, rate limits and the WebSocket note.

Code-checkedread against the code it describes; nothing was run

Verified againstWritten from the route files in packages/server/src/http and the schemas in packages/shared. CI lints it and a test compares its paths with the server router.

Page last changed 9 Nov 2026 (from the git history)

The host serves a small HTTP API and one WebSocket. The HTTP API is described by an OpenAPI 3.1 document.

Get the document

Read every endpoint, with schemas and examples, on the API reference page. Download openapi.yaml. The same file lives in the repository at openapi/gavel.yaml, and the docs site copies it at build time so the two never differ. Open it in any OpenAPI viewer, Postman, Insomnia or an SDK generator.

PayPal sandbox only: no real money moves through any route.

Endpoints

AreaMethod and pathCredential
AuctionsPOST /api/auctionsoperator key
AuctionsGET /api/auctions/{id} (id or join code)none
AuctionsPOST /api/auctions/{id}/auctioneer/rotate, revoke-all, revokeoperator key
ControlPOST /api/auctions/{id}/control, POST /api/auctions/{id}/killauctioneer token
Bidding accessPOST /api/auctions/{id}/invites, POST /api/auctions/{id}/bidders/{bidderId}/inviteauctioneer token
Bidding accessPOST /api/auctions/{id}/joininvite token in the body
ReadGET /api/auctions/{id}/snapshotauctioneer, screen, session or reviewer token
ReadGET /api/auctions/{id}/eventsauctioneer, screen or reviewer token
HoldsPOST /api/holds, POST /api/holds/{holdId}/approve, GET and DELETE /api/holds/{holdId}session token
Judge roomsGET /api/judge/capabilities, POST /api/judge/rooms, POST /api/judge/joinnone (create also accepts the judge key)
Judge roomsPOST /api/judge/keyjudge key
Judge roomsGET /api/judge/rooms/{id}/ledgerreviewer or auctioneer token
Judge roomsPOST /api/judge/rooms/{id}/sim-holdsession token
Judge roomsPOST /api/judge/pauseoperator key
ReceiptsPOST /api/auctions/{id}/receipt-linksession token
ReceiptsGET /api/auctions/{id}/receiptreceipt token
ExportGET /api/auctions/{id}/export (NDJSON)auctioneer token or operator key
HealthGET /healthz, /readyz, /version, /warmupnone
Operator/admin/export, /admin/replay-bundle, /metrics, /metrics/prometheus, /ops/summary, /ops/rooms, /ops/auctions/{id}/void-all, release-reviewoperator key

The PayPal webhook and the three demo routes are left out on purpose: PayPal alone calls the webhook, and the demo routes exist only when the host runs in demo mode, never in production.

Authentication

CredentialSent asLifetime
Operator keyheader X-Admin-Keyset by the host operator
Auctioneer tokenAuthorization: Bearer12 hours
Screen tokenAuthorization: Bearer12 hours
Session tokenAuthorization: Bearer4 hours
Receipt tokenAuthorization: Bearer4 hours
Reviewer tokenAuthorization: Bearer12 hours, read only, from judge-room creation
Judge keyheader X-Judge-Keyset by the host operator, optional, limited (never the operator key)
Invite tokenbody field invite of the join route24 hours, single use

A token is bound to one auction and one kind. A reviewer token reads the snapshot, event log and room ledger of its own judge room and nothing else. The judge key only lifts the public judge-room limits and is sent only in its header. No real credential appears in the document.

Errors

Every error is JSON with a message. Read the stable code as code ?? error: the core and judge routes send code, the hold, judge and operator routes send error, and detail is optional extra text.

{ "code": "bad_message", "message": "invalid request body", "detail": "config.reserve: reserve must be at least 100 cents" }

Statuses in use: 400, 401, 403, 404, 409, 410, 413, 415, 429, 500 and 503. A 429 always carries Retry-After.

Rate limits

Each operation that has its own limit carries an x-rate-limit extension, and the host-wide defaults sit under x-rate-limits. By default a source address gets 60 write requests a minute (reads have their own 300 a minute bucket) on every route except health and webhooks, 10 joins a minute, and 12 judge rooms an hour.

WebSocket protocol

Live bidding runs on wss://<host>/ws. OpenAPI cannot describe a socket, so the document carries a prose section and this site has the full contract on WebSocket protocol. In AsyncAPI terms the channel /ws has three client messages (join, bid, confirm_response) and ten server messages (registered, state, price, bid_accepted, bid_rejected, confirm_request, hammer, settlement_update, audit_event, error).

SDKs with APIMatic

GAVEL is entered for the sponsor prize "Best Use of APIMatic".

Status: spec ready, SDK not generated yet

The OpenAPI document is ready. Generating the TypeScript SDK and the developer portal needs an APIMatic account, which does not exist yet, so no SDK and no portal have been generated. Nothing is checked in as generated output.

The flow once the account exists:

  1. Create an APIMatic account.
  2. Import the API from https://raw.githubusercontent.com/harshbhx/gavel-auction/main/openapi/gavel.yaml, or upload openapi/gavel.yaml.
  3. Review the validation report and fix anything it names in the document.
  4. Generate the TypeScript SDK (other languages the same way) and the API developer portal.
  5. Publish the portal and record its address and the SDK package here and in the README.

The WebSocket is outside what an OpenAPI-based SDK generates, so live bidding stays on the documented socket protocol.

Edit on GitHub

Last updated on