Skip to content

Auction Events

Auction events are the core of the real-time API. They let clients subscribe to a live auction, place and moderate bids, declare winners, and receive a continuously updated stream of auction state.

Reference: events/presence.md · events/prebid.md (subscriber prebid contract) · events/system.md · errors.md · rate-limits.md · Starting an auction (the full start flow, incl. the auction.status.update command)


Event list

Client → Server (commands)

Event Permission Status
auction.subscribe auction:subscribe Implemented
auction.unsubscribe auction:subscribe Implemented
auction.participation.join auction:subscribe Implemented
auction.bid.place auction:bid:place Implemented
auction.bid.cancel auction:bid:place Planned
auction.status.update auction:staff Implemented
auction.pause auction:staff Implemented
auction.resume auction:staff Implemented
auction.end auction:staff Implemented
auction.bid.mark auction:staff Implemented
auction.winner.declare auction:staff Implemented
auction.winner.record_lot auction:staff Implemented
auction.announcement.create auction:staff Implemented
auction.presence.floor.update auction:staff Implemented

Server → Client

Event Direction Status
auction.connected Server → Client Implemented
auction.state.snapshot Server → Client Implemented
auction.audience.snapshot Server → Client Implemented (see presence.md)
auction.audience.changed Server → Client Implemented
auction.join_window.opened · auction.join_window.closed Server → Client Implemented, durable, replayable
auction.participation.joined Server → Client Implemented, staff only
auction.state.changed Server → Client Implemented (all live transitions; data.payload.transition distinguishes them)
auction.winner.changed Server → Client Implemented, durable, replayable, staff only
auction.settings.updated Server → Client Implemented
auction.bid.created · auction.bid.updated · auction.bid.deleted Server → Client Implemented
auction.prebid.created · auction.prebid.deleted Server → Client Implemented
auction.bidder.disqualified Server → Client Implemented
auction.announcement.created · auction.announcement.updated · auction.announcement.deleted Server → Client Implemented

The event names above are canonical. Earlier names such as auction.started, auction.paused, auction.resumed, auction.extended, auction.call_started, auction.closed, auction.winner_selected, auction.status_changed, auction.state_refreshed, bid.created, prebid.created, auction.announcement.created and auction.snapshot were collapsed/renamed during the canonical event migration. Clients should key off the canonical names above.


auction.subscribe

Description

Subscribes to an auction as a viewer and starts receiving the realtime stream. An eligible subscriber may watch without payment and without joining. Subscriber viewing is available in SCHEDULED, READY, LIVE, and PAUSED. On success the server:

  1. authorizes the caller against the specific (auctionId) participation rule;
  2. joins the auction:<auctionId> room and the Redis fan-out channel;
  3. subscribes to the domain realtime channel;
  4. for COMPANY / SUPERADMIN, also joins the staff-only auction:staff:<auctionId> room and subscribes to the staff-scoped realtime channel (staff-only events, published with scope: "staff", are delivered only on this channel and never reach subscribers);
  5. creates a per-connection viewer or participant audit session (for SUBSCRIBER);
  6. returns an acknowledgement with the auction identity;
  7. sends auction.connected, auction.state.snapshot, and auction.audience.snapshot (in that order) after the acknowledgement.

Direction

Client → Server

Roles Allowed

SUBSCRIBER, COMPANY, SUPERADMIN (any role with an eligible participation or admin access to the cycle).

Permissions Required

auction:subscribe.

Request Schema

Field Type Required Description
type string Yes auction.subscribe
data.auctionId string Yes The auction id.
data.enrolledSubscriberId string No For SUBSCRIBER, the specific enrollment to join.
data.lastSequence number No Last serverSequence seen; server replay will merge missed events into the snapshot payload.

Response Schema

The handler returns an acknowledgement first, and then pushes auction.connected, auction.state.snapshot and auction.audience.snapshot immediately after it.

Field Type Description
auctionId string Auction id (echoed from the request).
cycleId string Cycle id for the auction.
room string The room name joined, auction:<auctionId>.
staffRoom string For staff only, the joined staff room auction:staff:<auctionId>. Absent for SUBSCRIBER.

Success Response

{
  "id": "req_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
  "type": "ack",
  "version": "1.0",
  "source": "dichit-backend",
  "timestamp": "2026-08-05T10:00:00.000Z",
  "sequence": 1,
  "data": {
    "eventType": "auction.subscribe",
    "auctionId": "auc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "cycleId": "cyc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "room": "auction:auc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "staffRoom": "auction:staff:auc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X"
  }
}

Initial server events pushed after subscribe:

{
  "type": "auction.connected",
  "id": "req_01HQ5BWNJ5Y1P3V0W5X0W5X0W5X",
  "data": {
    "auctionId": "auc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "cycleId": "cyc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X0",
    "occurredAt": "2026-08-03T10:00:00.000Z",
    "payload": {
      "connectionId": "conn_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
      "heartbeatIntervalMs": 20000
    }
  }
}
{
  "type": "auction.state.snapshot",
  "id": "req_01HQ5BWNJ5Y1P3V0W5X0W5X0W5X",
  "data": {
    "auctionId": "auc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "cycleId": "cyc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "occurredAt": "2026-08-03T10:00:00.000Z",
    "payload": {
      "auction": {},
      "currentUser": {},
      "viewerCount": 2,
      "joinedParticipantCount": 3,
      "onlineParticipantCount": 0,
      "recentBids": [],
      "lastSequence": 12
    }
  }
}
{
  "type": "auction.audience.snapshot",
  "id": "req_01HQ5BWNJ5Y1P3V0W5X0W5X0W5X",
  "data": {
    "auctionId": "auc_01HQ5BWNJ5Y1P5RX0W4X0W5X0W5X",
    "cycleId": "cyc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "occurredAt": "2026-08-03T10:00:00.000Z",
    "payload": {
      "viewerCount": 4,
      "joinedParticipantCount": 3,
      "onlineParticipantCount": 2,
      "bidderCount": 1
    }
  }
}

Error Responses

Code Description
FORBIDDEN Subscriber is not eligible to view the auction, or viewing is unavailable in the current state.
NOT_FOUND Auction not found.
BAD_REQUEST auctionId missing/invalid, or the cycle invoice is not paid.
CONFLICT Auction state conflicts (e.g. already ended).

Validation Rules

Rule Behaviour
auctionId non-empty string Required.
lastSequence non-negative integer Optional; if provided, replay is merged into the snapshot payload as replay.

A subscribe without lastSequence into an auction that is past live start returns a snapshot whose payload.replay.events contains the persisted started transition (see Server events).

Fetching auctionId: the auction row is now guaranteed before READY/LIVE (ensureAuctionsForEligibleCycles), so auctionId always exists. Resolve it via REST before subscribing — e.g. GET /v2/.../auctions/by-cycle/:cycleId or the cycle overview — then subscribe with auctionId.

Example Request

{
  "type": "auction.subscribe",
  "id": "req_01HQ5BWNJ5Y1P3V0W5X0W5X0W5X",
  "data": {
    "auctionId": "auc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "lastSequence": 12
  }
}

Broadcast Behaviour

Local (unicast to the requester) — but it triggers room membership and the server-pushed initial events.

  • auction.unsubscribe
  • auction.connected, auction.state.snapshot, auction.audience.snapshot
  • events/presence.md

Notes

  • Implementation status: Implemented.
  • enrolledSubscriberId is required by the subscriber authorization flow (or you retry without it and the server resolves), and omitted entirely by staff.
  • Use lastSequence after reconnection to minimize the lost-event window.

Best Practices

  • Subscribe once per auction; re-subscribe after reconnect using the last serverSequence.
  • Apply the auction.state.snapshot as the base, then deltas.

auction.participation.join

Explicitly admits a paid subscriber to bid. The command requires a message id; reuse the same id after a timeout. The auction row is locked and the server uses database time for the T−10 boundary. Concurrent joins produce one immutable participant row per auction and enrollment.

{
  "id": "join-command-id",
  "type": "auction.participation.join",
  "data": {
    "auctionId": "auction-id",
    "enrolledSubscriberId": "enrollment-id",
    "confirmFloorToOnline": false
  }
}

The acknowledgement payload is:

{
  "status": "accepted",
  "commandId": "join-command-id",
  "participantId": "participant-id",
  "auctionId": "auction-id",
  "cycleId": "cycle-id",
  "joinedAt": "2026-09-06T09:50:00.000Z",
  "joinWindowVersion": 2,
  "source": "ONLINE"
}

status is accepted for the first commit and replayed when durable admission already exists. Joining opens 600 seconds before auctionStartAt. It closes at actual start for BEFORE_START, at startedAt + subscriberJoinGraceSeconds for GRACE_PERIOD, and at auction end/cancellation for ANYTIME.

Leaving or losing the socket never removes admission. A participant may reconnect after the window closes and may bid until the auction ends. Payment reversal also does not revoke admission; live disqualification still blocks bidding.

An existing FLOOR participant receives status: "confirmation_required" with currentSource: "FLOOR" and requestedSource: "ONLINE" unless the client sends confirmFloorToOnline: true. Until confirmed, the socket remains a viewer. Confirmation rechecks the online join window and all current eligibility rules. Staff floor-presence updates can switch ONLINE back to FLOOR; clearing floor presence never switches it online automatically.

Possible rejections include payment required, prior program winner, disqualification, inactive enrollment/cycle, window not open, window closed, or auction not viewable. Clients cannot send an access mode.

Join-window events

auction.join_window.opened and auction.join_window.closed are committed to the durable activity outbox before publication. Delivery is at least once. Deduplicate by event id, order by serverSequence, and reconnect with lastSequence to replay missed events.

Both events use { stateVersion, joinWindow, reason? }. joinWindow always contains status, version, joiningRule, opensAt, openedAt, closesAt, and closedAt. Opened events set status: "OPEN" and closedAt: null; closed events set status: "CLOSED" and add one of STARTED, GRACE_EXPIRED, AUCTION_ENDED, CANCELLED, or RESCHEDULED as reason. Rescheduling increments the window version. Ignore an older version after observing a newer one.

Sequences are global to the auction but replay is access-filtered. Visible events can therefore have numeric gaps; use replay.lastSequence as the high-water cursor instead of requiring contiguity.

auction.participation.joined is durable and staff-scoped. Subscriber clients learn their own admission from the command acknowledgement and snapshots. Its participant payload includes the durable joinedAt timestamp and nullable lastSeenAt, which is null at initial admission.

auction.participation.source_changed is also durable and staff-scoped. Its payload contains participant/subscriber/enrollment IDs, fromSource, toSource, and changedAt.

auction.unsubscribe

Description

Ends a subscription to an auction: leaves auction:<auctionId>, removes presence, and unsubscribes from the realtime channel.

Direction

Client → Server

Roles Allowed

All subscription roles.

Permissions Required

auction:subscribe.

Request Schema

Field Type Required Description
type string Yes auction.unsubscribe
data.auctionId string Yes Auction to leave.

Response Schema

Field Type Description
auctionId string Auction id.
unsubscribed boolean true if an active subscription was torn down.

Success Response

{
  "id": "req_01HQ5BXWYP1Y5RX0W5X0W5X0W5X",
  "type": "ack",
  "version": "1.0",
  "source": "dichit-backend",
  "timestamp": "2026-08-05T10:00:00.000Z",
  "sequence": 1,
  "data": {
    "eventType": "auction.unsubscribe",
    "auctionId": "auc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "unsubscribed": true
  }
}

Error Responses

Code Description
BAD_REQUEST auctionId missing/invalid.

Validation Rules

auctionId required non-empty.

Example Request

{
  "type": "auction.unsubscribe",
  "id": "req_01HQ5BXWN1Y2RX0W5X0W5X0W5X",
  "data": { "auctionId": "auc_01HQ5BWNJ5Y1P1RX0V0X0W5X0W5X" }
}

Example Response

{
  "id": "req_01HQ5BXWN1Y2RX0W5X0W5X0W5X",
  "type": "ack",
  "version": "1.0",
  "source": "dichit-backend",
  "timestamp": "2026-08-05T10:00:00.000Z",
  "sequence": 1,
  "data": {
    "eventType": "auction.unsubscribe",
    "auctionId": "auc_01HQ5BWNJ5Y1P1RX0W5X0W5X0W5X",
    "unsubscribed": true
  }
}

Broadcast Behaviour

None, except that other connections may receive auction.audience.changed if this was the subscriber's last chunk.

  • auction.subscribe
  • auction.audience.changed

Notes

  • Implementation status: Implemented.
  • Idempotent: unsubscribing when not subscribed returns unsubscribed: false.

Best Practices

  • Unsubscribe when the user leaves an auction view to free resources.

auction.bid.place

Description

Places a live bid on an active auction. For SUBSCRIBER users it is their own bid. For COMPANY/SUPERADMIN (staff) it can place a bid on behalf of an offline subscriber with enrolledSubscriberId (only when settings allow). amountMinor is the bid amount expressed in minor currency units (e.g. "150000" = 1500.00) as a decimal string.

Direction

Client → Server

Roles Allowed

  • SUBSCRIBER — own live bid.
  • COMPANY, SUPERADMIN — offline staff bid (needs enrolledSubscriberId).

Permissions Required

auction:bid:place for the route. Staff offline placement additionally requires auction:staff-level authority at the application layer.

Request Schema

Field Type Required Description
type string Yes auction.bid.place
id string Yes Client-generated request id (1–128 chars); becomes the idempotency command id.
data.auctionId string Yes Auction id.
data.amountMinor string Yes Amount in minor units as a decimal string, regex /^[1-9]\d*$/.
data.enrolledSubscriberId string Conditional Required for staff offline bids; optional for subscriber.

Response Schema

The route returns one terminal response after transactional validation.

Field Type Description
type string Always "ack" for a committed bid.
id string Echoes the request id.
data.eventType string auction.bid.place.
data.status string accepted or replayed.
data.commandId string Scoped idempotency key.
data.bidId string Persisted bid id.
data.amountMinor string Committed amount in minor units.
data.stateVersion number Auction state version after the committed operation.

Success Response

{
  "id": "req_01HQ5BXWYP1Y5RX0W5X0W5X0W5X",
  "type": "ack",
  "version": "1.0",
  "source": "dichit-backend",
  "timestamp": "2026-08-05T10:00:00.000Z",
  "data": {
    "eventType": "auction.bid.place",
    "status": "accepted",
    "commandId": "req_01HQ5BXWYP1Y5RX0W5X0W5X0W5X",
    "auctionId": "auc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "cycleId": "cyc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "bidId": "bid_01HQ5BY3K7Z2V6Y0W5X0W5X0W5X",
    "amountMinor": "2500000",
    "stateVersion": 12
  }
}

Error Responses

Business, validation, and authorization rejections use the existing correlated WebSocket error envelope with a safe code and public message:

Code Description
AUCTION_NOT_LIVE Auction is not live (not started, window closed, or cycle inactive).
AUCTION_ENDED Auction already ended.
INVALID_AMOUNT Amount failed validation (non-positive or malformed).
BID_NOT_IMPROVING Bid below the minimum, above the maximum, or not an improvement over the current lead.
BID_INCREMENT_TOO_SMALL / BID_DECREMENT_TOO_SMALL Bid improves but misses the minimum step.
ONLINE_PARTICIPATION_REQUIRED Online bid while durably floor-backed; confirm the floor→online switch and retry with the same command id. data.details carries currentSource/requiredSource.
FLOOR_PARTICIPATION_REQUIRED Staff floor bid while durably online.
DUPLICATE_COMMAND Same command id reused with a different amount.
SUBSCRIBER_NOT_ELIGIBLE Payment, eligibility, or winning constraints are not met.

The payload schema is strict, so removed fields are rejected rather than ignored.

Validation Rules

Rule Behaviour
amountMinor regex /^[1-9]\d*$/ Required.
id 1–128 chars Required; doubles as the idempotency key.
auctionId non-empty Required.
staff requires enrolledSubscriberId Missing → BAD_REQUEST, then FORBIDDEN if the target is online.

Example Request

{
  "type": "auction.bid.place",
  "id": "req_01HQ5BXWYP1Y5RX0W5X0W5X0W5X",
  "data": {
    "auctionId": "auc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "amountMinor": "2500000"
  }
}

Example Response

  1. Terminal ack after commit, or correlated error on rejection.
  2. Domain events update the shared feed independently of the requester response.

Broadcast Behaviour

A successful bid is fanned out to every subscriber of auction:<auctionId> as auction.bid.created (leading bid) or auction.bid.updated (outbid) — see auction.bid.created server event below. The sender sees the same events.

  • auction.bid.created, auction.bid.updated
  • auction.state.changed (start, pause, resume, extended transitions)

Notes

  • Implementation status: Implemented (synchronous transactional command).
  • Rate limit: 100 messages / window (overridden per-route).
  • Idempotency prevents double-bids on replays: reusing the same id for the same bid returns the existing result as replayed; changing the amount under the same id is rejected (DUPLICATE_COMMAND).

Best Practices

  • Reuse the request id on reconnect for the same bid intent.
  • Treat the terminal ack as authoritative for the request and domain events as authoritative for the shared feed.

auction.bid.cancel

Description

Planned. Cancels/revokes a bid the client previously placed. Because a live floor bid cannot simply be undone, cancel behaviour maps to the canonical auction.bid.deleted workflow (staff auction.bid.mark with action: DELETE_BID) in the current build; a client-driven cancel is planned.

Direction

Client → Server (planned)

Roles Allowed

SUBSCRIBER (cancel own bid); staff may delete any bid via auction.bid.mark.

Permissions Required

auction:bid:place.

Request Schema

Field Type Required Description
type string Yes auction.bid.cancel
data.auctionId string Yes Auction id.
data.bidId string Yes Bid to cancel.

Response Schema

Planned. Will follow async CQRS: an immediate command.acknowledged with no business data, followed by an auction.bid.deleted domain event carrying the cancelled bid id on success.

Success Response

{
  "id": "req_01HQ5BXWYP1Y3RX0W5X0W5X0W5X",
  "type": "ack",
  "version": "1.0",
  "source": "dichit-backend",
  "timestamp": "2026-08-05T10:00:00.000Z",
  "sequence": 1,
  "data": {
    "eventType": "auction.bid.cancel",
    "bidId": "bid_01HQ5BY3K7Z2V6Y0W5X0W5X0W5X",
    "cancelled": true
  }
}

Error Responses

FORBIDDEN, NOT_FOUND, BAD_REQUEST, CONFLICT.

Validation Rules

Rule Behaviour
auctionId, bidId non-empty Required.
Bid ownership Must belong to the caller.

Example Request

{
  "type": "auction.bid.cancel",
  "id": "req_01HQ5BXWYP1Y5RX0W1X0W5X0W5X0W5X",
  "data": {
    "auctionId": "auc_01HQ5BWNJ5Y1P0X0W5X0W5X0W5X",
    "bidId": "bid_01HQ5BY3K1Z2V1Y0W5X0W5X0W5X"
  }
}

Broadcast Behaviour

Broadcast to the room as auction.bid.deleted.

  • auction.bid.deleted
  • auction.bid.mark (staff) — the current safe way to delete a bid

Notes

  • Implementation status: Planned. Use auction.bid.mark DELETE_BID (staff) today.
  • Policy constraint: deleting a bid that is currently leading may not be allowed; clients should be ready for CONFLICT.

Best Practices

  • Only cancel the client's own in-flight bids; for moderation use auction.bid.mark.

Staff command events

All staff events require the auction:staff permission and an auctionId. They run the corresponding auction command and return an immediate command.acknowledged. No business data (e.g. stateVersion) is returned in the acknowledgement; the result arrives via domain events (auction.state.changed with the relevant transition, auction.announcement.created, etc.). Subscribers and insufficiently-permissioned users receive command.rejected/error (FORBIDDEN).

Event Purpose Example data
auction.status.update Start live auction { "auctionId": "...", "status": "START" }
auction.pause Pause auction { "auctionId": "...", "reason": "network issue" }
auction.resume Resume auction { "auctionId": "...", "reason": "resolved" }
auction.end End auction { "auctionId": "...", "reason": "auction complete" }
auction.bid.mark Moderate a bid action variants below
auction.winner.declare Declare winner mode variants below
auction.winner.record_lot Record lot + runners-up list of ids
auction.announcement.create Create an announcement { "auctionId": "...", "message": "...", "tone": "INFO" }
auction.presence.floor.update Toggle floor presence { "auctionId": "...", "enrolledSubscriberId": "...", "present": true }

auction.bid.mark

One of two actions:

action payload
DELETE_BID { action, bidId, reason, reasonCode? } — reasonCode optional
DISQUALIFY_BIDDER { action, enrolledSubscriberId, reason, reasonCode }

reasonCode ∈ KYC_ISSUE | PAYMENT_ISSUE | ELIGIBILITY_ISSUE | RULE_VIOLATION | OTHER (required except for DELETE_BID).

Example:

{
  "type": "auction.bid.mark",
  "id": "req_01HQ5BXWYP1Y5RX0W5X0W5X0W5X",
  "data": {
    "auctionId": "auc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "action": "DELETE_BID",
    "bidId": "bid_01HQ5BY3K1Y1V1Y0W5X0W5X0W5X",
    "reason": "errored entry"
  }
}

auction.winner.declare

mode payload
CANDIDATE { mode, bidId? , prebidId?, reason? } — derive from candidate
MANUAL { mode, enrolledSubscriberId, amount, reason } — manual override

auction.winner.record_lot

{
  "type": "auction.winner.record_lot",
  "id": "req_01HQ5BXWYP1Y5RX0W5X0W5X",
  "data": {
    "auctionId": "auc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "winnerEnrolledSubscriberId": "enr_01HQ5BY3K7Z1V1Y0W5X0W5X0W5X",
    "candidateEnrolledSubscriberIds": [
      "enr_01HQ5BY3K7Z1V2Y0W5X0W5X0W5X",
      "enr_01HQ5BY3K7Z1V3Y0W5X0W5X0W5X"
    ]
  }
}

auction.announcement.create

Description

Creates an auction-scoped announcement visible to all room members. The server stores the announcement and publishes auction.announcement.created to the auction:<auctionId> room. This is a staff-only command.

Direction

Client → Server

Roles Allowed

COMPANY, SUPERADMIN (staff).

Permissions Required

auction:staff.

Request Schema

Field Type Required Description
type string Yes auction.announcement.create
data.auctionId string Yes The auction id.
data.message string Yes Announcement text, trimmed, 1–1000 chars.
data.tone string No INFO (default) or WARNING.

Response Schema

This is an async command — the immediate response is a command.acknowledged with no business data. The created announcement is delivered to the room as an auction.announcement.created event.

Field Type Description
type string Always "command.acknowledged".
correlationId string Echoes the request's id for correlation.
data.command string The acknowledged command type (auction.announcement.create).
data.status string Always "accepted".

Success Response

{
  "id": "ack_01HQ5BXWYP1Y5RX0W5X0W5X0W5X",
  "type": "command.acknowledged",
  "version": "1.0",
  "source": "dichit-backend",
  "timestamp": "2026-08-05T10:00:00.000Z",
  "correlationId": "req_01HQ5BXWYP1Y5RX0W5X0W5X0W5X",
  "causationId": "req_01HQ5BXWYP1Y5RX0W5X0W5X0W5X",
  "data": {
    "command": "auction.announcement.create",
    "status": "accepted"
  }
}

Error Responses

Code Description
FORBIDDEN Non-staff caller.
NOT_FOUND Cycle/auction not found.
BAD_REQUEST message empty/too long, tone invalid.

Validation Rules

Rule Behaviour
auctionId non-empty string Required.
message trimmed, 1–1000 chars Required.
tone ∈ INFO, WARNING Optional; default INFO.

Example Request

{
  "type": "auction.announcement.create",
  "id": "req_01HQ5BXWYP1Y5RX0W5X0W5X0W5X",
  "data": {
    "auctionId": "auc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "message": "Heads up: the reserve is being lowered.",
    "tone": "WARNING"
  }
}

Broadcast Behaviour

A successful command publishes auction.announcement.created to the auction:<auctionId> room.

  • auction.announcement.created, auction.announcement.updated, auction.announcement.deleted

Notes

  • Implementation status: Implemented.
  • Announcements are persisted and also surfaced in the auction snapshot payload (payload.announcements).

auction.presence.floor.update

Description

Allows a staff member to mark a subscriber as physically present on the auction floor (or remove the floor-presence flag). This sets the participant's source to "FLOOR" (AuctionParticipationSource) in the staff audience view. Marking a subscriber present also creates immutable FLOOR participation after the server verifies eligibility, payment, and the current join window. The resulting auction.audience.changed event is pushed to the room. Floor presence is independent of WebSocket connections, so a floor participant has connectionCount: 0.

Direction

Client → Server

Roles Allowed

COMPANY, SUPERADMIN (staff only; subscribers cannot set floor presence).

Permissions Required

auction:staff.

Request Schema

Field Type Required Description
type string Yes auction.presence.floor.update
data.auctionId string Yes The auction id.
data.enrolledSubscriberId string Yes The subscriber whose floor presence is being set.
data.present boolean Yes true to mark as floor-present, false to remove.

Response Schema

This is an async command — the immediate response is a command.acknowledged with no business data. The resulting presence transition is delivered to the room as auction.audience.changed.

Field Type Description
type string Always "command.acknowledged".
correlationId string Echoes the request's id for correlation.
data.command string The acknowledged command type (auction.presence.floor.update).
data.status string Always "accepted".

Success Response

{
  "id": "ack_01HQ5BXWYP1Y5RX0W5X0W5X0W5X",
  "type": "command.acknowledged",
  "version": "1.0",
  "source": "dichit-backend",
  "timestamp": "2026-08-05T10:00:00.000Z",
  "correlationId": "req_01HQ5BXWYP1Y5RX0W5X0W5X0W5X",
  "causationId": "req_01HQ5BXWYP1Y5RX0W5X0W5X0W5X",
  "data": {
    "command": "auction.presence.floor.update",
    "status": "accepted"
  }
}

Error Responses

Code Description
FORBIDDEN Non-staff caller; subscriber is not eligible for this auction.
NOT_FOUND Cycle/auction not found; subscriber not eligible.
BAD_REQUEST Required data is malformed or the paid invoice cannot be resolved.

Validation Rules

Rule Behaviour
auctionId non-empty string Required.
enrolledSubscriberId non-empty Required.
present boolean Required.
present: true Requires eligibility, payment, and an open join window.
present: false Clears floor presence without revoking participation.

Example Request

{
  "type": "auction.presence.floor.update",
  "id": "req_01HQ5BXWYP1Y5RX0W5X0W5X",
  "data": {
    "auctionId": "auc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "enrolledSubscriberId": "enr_01HQ5BWYP1Y5RX0W5X0W5X0W5X",
    "present": true
  }
}

Broadcast Behaviour

The server publishes auction.audience.changed to the auction room:

  • Adding floor presence durably admits the paid subscriber, if needed, then adds the floor presence overlay. Both public and staff-scoped copies include a participant with source: "FLOOR" and connectionCount: 0.
  • Removing floor presence removes only the floor overlay. Durable admission remains.
  • auction.audience.changed — public and staff-scoped copies both include aggregate counts plus the affected participant projection.
  • auction.audience.snapshot — aggregate counts for subscribers; staff may also receive identities.

Notes

  • Implementation status: Implemented.
  • Floor participants are distinct from online ("ONLINE") subscribers. A single subscriber can be both online (via auction.subscribe) and floor-present; in that case the online presence dominates in the snapshot and source reflects the active state.
  • Use this to represent paddle/bidder-room presence in a live sales room where the bidder is not connected via a browser.

Staff event Error Responses

Code Description
FORBIDDEN Non-staff (e.g. SUBSCRIBER).
BAD_REQUEST Missing/ill-typed fields.
NOT_FOUND/CONFLICT Business rejections.

auction.state.changed, auction.bid.created, auction.bid.deleted, auction.bidder.disqualified, auction.announcement.created, auction.audience.changed (floor).


Server events

Below are the canonical server-pushed auctions. All use the standard envelope with data.auctionId, data.cycleId, optional data.stateVersion, data.occurredAt, and data.payload.

auction.connected

Description — Sent once by auction.subscribe. Confirms live subscription and gives the connection id + heartbeat interval.

Direction Server → Client · Roles all subscribed · Permissions – · Request N/A.

Field Type Description
payload.connectionId string Connection id.
payload.heartbeatIntervalMs number Heartbeat interval.

Example:

{
  "type": "auction.connected",
  "id": "req_01HQ5BWNJ5Y1P3V0W5X0W5X0W5X",
  "data": {
    "auctionId": "auc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "cycleId": "cyc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "occurredAt": "2026-08-03T10:00:00.000Z",
    "payload": {
      "connectionId": "conn_01HQ5BWNJ5Y4X5RX0W5X0W5X0W5X",
      "heartbeatIntervalMs": 20000
    }
  }
}

Related: auction.state.snapshot, auction.audience.snapshot.

auction.state.snapshot

Description — the current auction state delivered right after subscribe (or merged with a replay parcel when lastSequence was provided). When the auction is past live start, the snapshot also carries the authoritative live-start marker and, for late joiners, a storage-backed started transition in replay.events (see below).

Direction Server → Client · Roles all subscribed · Permissions -

Field Description
payload.auction Auction summary (role-scoped).
payload.auction.startedAt ISO-8601 live-start marker or null; set once the started transition ran and never cleared.
payload.currentUser Current bidder/lead, role-scoped.
payload.viewerCount Distinct online viewers.
payload.joinedParticipantCount Durable admitted participants.
payload.onlineParticipantCount Distinct admitted participants currently online or floor-present.
payload.bidderCount Durable participants with an accepted bid.
payload.recentBids Recent bid activity items.
payload.lastSequence Last event sequence for replay resume.

Example (subscriber view):

{
  "type": "auction.state.snapshot",
  "id": "req_01HQ5BWNJ5Y1P3V0W5X0W5X0W5X",
  "data": {
    "auctionId": "auc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "cycleId": "cyc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "occurredAt": "2026-08-03T10:00:00.000Z",
    "payload": {
      "auction": {
        "id": "auc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
        "cycleId": "cyc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
        "status": "LIVE",
        "startedAt": "2026-08-03T10:00:00.000Z"
      },
      "currentUser": {
        "bidderCode": "*********3210",
        "bidAmount": "24500.00"
      },
      "viewerCount": 0,
      "joinedParticipantCount": 0,
      "onlineParticipantCount": 0,
      "bidderCount": 0,
      "recentBids": [],
      "lastSequence": 12
    }
  }
}

Late-join replay — a fresh subscribe (no lastSequence) into an auction that is past live start includes a replay parcel whose events contain the persisted started transition. The started transition is written to the auction's activity feed with a real serverSequence when the auction goes live (manual start or scheduled auto-start), so the replay event is storage-backed — never synthesized by the server. The same event is prepended to the gap-fill replay.events on reconnect when the auction is past live start and the gap does not already carry it; clients should treat it as idempotent (re-applying the started transition is harmless).

{
  "type": "auction.state.snapshot",
  "data": {
    "auctionId": "auc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "cycleId": "cyc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "occurredAt": "2026-08-03T10:00:00.100Z",
    "payload": {
      "auction": {
        "id": "auc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
        "status": "LIVE",
        "startedAt": "2026-08-03T10:00:00.000Z"
      },
      "currentUser": {},
      "viewerCount": 0,
      "joinedParticipantCount": 0,
      "onlineParticipantCount": 0,
      "bidderCount": 0,
      "recentBids": [],
      "lastSequence": 12,
      "replay": {
        "events": [
          {
            "type": "auction.state.changed",
            "id": "evt_01HQ5BY3K7Z2V6Y0W5X0W5X0W5X",
            "serverSequence": 1,
            "payload": {
              "transition": "started",
              "state": {
                "status": "LIVE",
                "stateVersion": 2,
                "currentPhase": "LIVE_BIDDING",
                "prebidPhase": "CLOSED",
                "auctionStartAt": "2026-08-03T10:00:00.000Z",
                "prebidStartAt": null,
                "prebidEndAt": null,
                "auctionEndAt": "2026-08-03T10:30:00.000Z",
                "startedAt": "2026-08-03T10:00:00.000Z",
                "pausedAt": null,
                "closingPhase": null,
                "closingPhaseEndsAt": null,
                "prebidAmountsRevealed": false,
                "prebidAmountsRevealedAt": null,
                "approvalRequired": false,
                "cycleStatus": "ACTIVE",
                "joinWindow": {
                  "status": "CLOSED",
                  "version": 1,
                  "joiningRule": "BEFORE_START",
                  "opensAt": "2026-08-03T09:50:00.000Z",
                  "openedAt": "2026-08-03T09:50:00.000Z",
                  "closesAt": "2026-08-03T10:00:00.000Z",
                  "closedAt": "2026-08-03T10:00:00.000Z"
                }
              }
            }
          }
        ],
        "lastSequence": 12
      }
    }
  }
}

Related: auction.connected, auction.bid.created, auction.state.changed.


The canonical live-state event is auction.state.changed. Earlier granular events (auction.started, auction.paused, auction.resumed, auction.extended, auction.call_started, auction.closed, auction.winner_selected, auction.status_changed, auction.state_refreshed) are collapsed into it; data.payload.transition identifies the specific transition.

auction.state.changed

Description

Published whenever persisted auction lifecycle state changes. One durable event type carries scheduling, prebid, approval, live, close, cancellation, and winner transitions; data.payload.transition identifies the cause and data.payload.state is the complete post-transition lifecycle state.

transition Published when
schedule_changed Auction timing/settings are scheduled or rescheduled.
prebid_opened / prebid_closed Manual or automatic prebid-window transition.
prebids_revealed Staff reveals sealed prebid amounts.
approved Approval-required auction moves to READY.
started Auction goes live manually or automatically.
paused / resumed Staff pauses or resumes live bidding.
extended A committed bid extends the duration-mode deadline.
call_started A call-mode closing phase begins.
closed Auction enters ENDED.
cancelled Auction is cancelled.
winner_selected / winner_disqualified Winner state changes and division counts are recalculated.

Direction

Server → Client

Roles Allowed

All subscribers of the auction.

Permissions Required

None at the event level (delivered to room members).

Response Schema

Field Type Description
id string Durable event id; deduplicate replay/live overlap with this value.
data.stateVersion number Same value as data.payload.state.stateVersion.
data.serverSequence number Durable per-auction high-water sequence.
data.payload.transition string Cause of the state change.
data.payload.state object Complete post-transition lifecycle state.
data.payload.winner object Optional public winner projection.
data.payload.declaredWinnerCount number Optional, winner transitions only.
data.payload.remainingWinnerSlots number Optional, winner transitions only.
data.payload.replacementRequired bool Optional, disqualification only.

payload.state always contains status, stateVersion, currentPhase, prebidPhase, auctionStartAt, prebidStartAt, prebidEndAt, auctionEndAt, startedAt, pausedAt, closingPhase, closingPhaseEndsAt, prebidAmountsRevealed, prebidAmountsRevealedAt, approvalRequired, cycleStatus, and the complete joinWindow object. Live and replay deliveries use this same payload. Replace the local lifecycle slice from payload.state; do not expect root-level startedAt, pausedAt, resumedAt, or deadline fields.

Example Response

{
  "type": "auction.state.changed",
  "data": {
    "auctionId": "auc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "cycleId": "cyc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "stateVersion": 2,
    "serverSequence": 14,
    "payload": {
      "transition": "started",
      "state": {
        "status": "LIVE",
        "stateVersion": 2,
        "currentPhase": "LIVE_BIDDING",
        "prebidPhase": "CLOSED",
        "auctionStartAt": "2026-08-03T10:00:00.000Z",
        "prebidStartAt": null,
        "prebidEndAt": null,
        "auctionEndAt": "2026-08-03T10:30:00.000Z",
        "startedAt": "2026-08-03T10:00:00.000Z",
        "pausedAt": null,
        "closingPhase": null,
        "closingPhaseEndsAt": null,
        "prebidAmountsRevealed": false,
        "prebidAmountsRevealedAt": null,
        "approvalRequired": false,
        "cycleStatus": "ACTIVE",
        "joinWindow": {
          "status": "CLOSED",
          "version": 1,
          "joiningRule": "BEFORE_START",
          "opensAt": "2026-08-03T09:50:00.000Z",
          "openedAt": "2026-08-03T09:50:00.000Z",
          "closesAt": "2026-08-03T10:00:00.000Z",
          "closedAt": "2026-08-03T10:00:00.000Z"
        }
      }
    }
  }
}

Broadcast Behaviour

Broadcast to auction:<auctionId> room across servers.

auction.connected, auction.state.snapshot, auction.bid.created.

Notes

  • Implementation status: Implemented across schedule, prebid, approval, start/pause/resume/end, automatic lifecycle, bid extension, cancellation, winner declaration/lot, and winner disqualification paths.
  • Consume the full state from auction.state.snapshot on connect, then replace lifecycle fields from each newer payload.state.

auction.bid.created

The auction.bid.created server event announces a new leading bid. The full payload is a bid activity object.

{
  "type": "auction.bid.created",
  "id": "bid_req_01HQ5BY3K7Z2V6Y0W5X0W5X0W5X",
  "data": {
    "auctionId": "auc_01HQ5BWRJ5Y1P5RX0W5X0W5X0W5X",
    "cycleId": "cyc_01HQ5BWRJ5Y1P5RX0W5X0W5X0W5X",
    "stateVersion": 7,
    "occurredAt": "2026-08-03T10:00:00.000Z",
    "payload": {
      "id": "bid_01HQ5BY3J7Z2V6Y0W5X0W5X0W5X",
      "auctionId": "auc_01HQ5BWRJ3J5Y1P5RX0W5X0W5X0W5X",
      "cycleId": "cyc_01HQ5BWRJ5Y1P5RX0W5X0W5X0W5X",
      "subscriberProgramId": "enr_01HQ5BY3K7Z2V6Y0W5X0W5X0W5X",
      "subscriberId": "sub_01HQ5BWYP1Y5RX0W5X0W5X0W5X",
      "bidderName": "Annie Mohan",
      "bidderAvatarUrl": null,
      "bidderCode": "*********3210",
      "bidAmount": "25000.00",
      "bidRank": 1,
      "isWinningBid": true,
      "status": "ACCEPTED",
      "createdAt": "2026-08-03T10:00:00.000Z",
      "serverSequence": 12
    }
  }
}
Payload field Type Description
id string Bid id.
subscriberProgramId string Enrollment id of the bidder.
subscriberId string User id of the bidder.
bidderName / bidderAvatarUrl string | null Display.
bidderCode string | null Masked mobile (e.g. *********3210).
bidAmount string Decimal string amount.
bidRank / isWinningBid number / bool Rank & winning flag.
status string ACCEPTED or OUTBID.
serverSequence number Monotonic ordering.
  • Target-scoped: for subscriber sockets, a bid event carrying targetUserId only arrives when it matches the socket's user. (See [protocol.md]).

Handler behaviour Server → Client · Roles all subscribed · Permissions — · Broadcast to auction:<auctionId>. · Error none. Related auction.bid.place, auction.state.changed, auction.bid.updated.


Other server events (compact reference)

Event Meaning Payload snippets
auction.state.changed Any lifecycle transition transition + complete state (see auction.state.changed)
auction.settings.updated Auction settings changed updated settings fields
auction.bid.created New leading bid (see auction.bid.created)
auction.bid.updated Existing bid outbid same item shape, status: OUTBID
auction.bid.deleted Bid deleted (staff) deleted bid
auction.prebid.created New prebid placed staff-only durable prebid projection
auction.winner.changed Winner console delta staff-only durable selected/disqualified winner projection
auction.prebid.deleted Prebid deleted id
auction.bidder.disqualified Bidder disqualified participant + reason
auction.announcement.created New announcement posted announcement object
auction.announcement.updated Announcement edited announcement object
auction.announcement.deleted Announcement removed { id, auctionId, cycleId }
  • Direction: Server → Client
  • Roles: all subscribed
  • Permissions: none at event level
  • Broadcast: to auction:<auctionId> room, across servers; subscriber filtering by targetUserId where present.
  • Error Responses: none (server-pushed).
  • Validation: N/A.

Payload excerpt for auction.state.changed (auto-extension): The real state object also contains every lifecycle field listed in the canonical schema above.

{
  "type": "auction.state.changed",
  "data": {
    "auctionId": "auc_11HQ5BWRJ5Y1P5RX0W5X0W5X0W5X",
    "cycleId": "cyc_11HQ5BWRJ5Y1P5RX0W5X0W5X0W5X",
    "stateVersion": 8,
    "serverSequence": 31,
    "payload": {
      "transition": "extended",
      "state": {
        "status": "LIVE",
        "stateVersion": 8,
        "currentPhase": "LIVE_BIDDING",
        "auctionEndAt": "2026-08-03T10:12:00.000Z",
        "regularAuctionEndAt": "2026-08-03T10:11:00.000Z",
        "extensionStartedAt": null
      }
    }
  }
}

extended is emitted immediately when a qualifying bid moves auctionEndAt. At regularAuctionEndAt, the server emits one additional state event with transition: "extension_started" and a non-null extensionStartedAt. Reconnecting clients restore both fields from the snapshot instead of inferring the extension phase locally.

Example auction.bidder.disqualified:

{
  "type": "auction.bidder.disqualified",
  "data": {
    "auctionId": "auc_11HQ0W5X1Y3P5RX0W0X0W1X0X5X",
    "cycleId": "cyc_11HQ0W5X1Y3P5RX0W0X0W1X0X5X",
    "stateVersion": 5,
    "occurredAt": "2026-08-03T10:05:00.000Z",
    "payload": { "subscriberId": "enr_...", "reason": "RULE_VIOLATION" }
  }
}

auction.announcement.created / auction.announcement.updated / auction.announcement.deleted

These server-pushed events announce changes to auction-scoped announcements (persistent text messages posted by staff). They are published to the auction:<auctionId> room whenever the corresponding command succeeds.

auction.announcement.created

Description — A new announcement was created via the auction.announcement.create client command.

Field Type Description
payload.id string Announcement id.
payload.auctionId string Auction id.
payload.cycleId string Cycle id.
payload.actorId string Staff user who created it.
payload.message string Announcement text.
payload.tone string INFO or WARNING.
payload.createdAt string ISO-8601 creation time.
{
  "type": "auction.announcement.created",
  "data": {
    "auctionId": "auc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "cycleId": "cyc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "occurredAt": "2026-08-03T10:00:00.000Z",
    "payload": {
      "id": "ann_01HQ5BY3K7Z2V6Y0W5X0W5X0W5X",
      "auctionId": "auc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
      "cycleId": "cyc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
      "actorId": "com_01HQ5BWYP1Y5RX0W5X0W5X0W5X",
      "message": "Heads up: the reserve is being lowered.",
      "tone": "WARNING",
      "createdAt": "2026-08-03T10:00:00.000Z"
    }
  }
}

auction.announcement.updated

Description — An existing announcement was edited via the REST updateAnnouncement command. Same payload shape as auction.announcement.created.

auction.announcement.deleted

Description — An announcement was deleted via the REST deleteAnnouncement command.

Field Type Description
payload.id string Deleted announcement id.
payload.auctionId string Auction id.
payload.cycleId string Cycle id.
{
  "type": "auction.announcement.deleted",
  "data": {
    "auctionId": "auc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "cycleId": "cyc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
    "occurredAt": "2026-08-03T10:05:00.000Z",
    "payload": {
      "id": "ann_01HQ5BY3K7Z2V6Y0W5X0W5X0W5X",
      "auctionId": "auc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X",
      "cycleId": "cyc_01HQ5BWNJ5Y1P5RX0W5X0W5X0W5X"
    }
  }
}

auction.prebid.created

Description — A staff-only, durable event emitted when a subscriber places a prebid. It is published to auction:staff:<auctionId> and included only in staff replay. Subscriber sockets do not receive it. The payload has a nullable amount so sealed values remain redacted.

The subscriber write/snapshot contract is in events/prebid.md.

Field Type Description
payload.id string Prebid id.
payload.enrolledSubscriberId string Enrollment id of the bidder.
payload.subscriberId string User id of the bidder.
payload.bidderName string Staff display name.
payload.amount number | null null while the prebid amount remains sealed.
payload.createdAt string ISO-8601 creation time.
payload.status string Current AuctionPrebidStatus value.
payload.documentSubmissionId string | null Associated document submission, when required.
{
  "type": "auction.prebid.created",
  "id": "bid_req_01HQ5BY3K7Z2V6Y0W5X0W5X0W5X",
  "data": {
    "auctionId": "auc_01HQ5BWRJ5Y1P5RX0W5X0W5X0W5X",
    "cycleId": "cyc_01HQ5BWRJ5Y1P5RX0W5X0W5X0W5X",
    "serverSequence": 22,
    "payload": {
      "id": "pb_01HQ5BY3J7Z2V6Y0W5X0W5X0W5X",
      "enrolledSubscriberId": "enr_01HQ5BY3K7Z2V6Y0W5X0W5X0W5X",
      "subscriberId": "sub_01HQ5BWYP1Y5RX0W5X0W5X0W5X",
      "bidderName": "Annie Mohan",
      "amount": null,
      "createdAt": "2026-08-03T09:30:00.000Z",
      "status": "ACTIVE",
      "documentSubmissionId": null
    }
  }
}

After staff reveals completed-auction prebids, clients receive auction.state.changed with payload.transition: "prebids_revealed" and should refresh the auction snapshot. Snapshot and REST payloads expose prebidAmountsRevealed: true and include prebid amounts from that point onward.


auction.winner.changed

Description — A staff-only, durable console event emitted alongside the public auction.state.changed winner transition. action is SELECTED or DISQUALIFIED.

The winner object includes public winner fields (id, subscriber and enrollment ids, display identity, nullable amount, division, status, type, selection source, bid/prebid ids, and selectedAt) plus staff-only email, mobile, selecting/replacing/disqualifying actor ids and timestamps, reason code, and note. A disqualification may also include suggestedReplacementCandidate, or explicit null when no suggestion exists.

{
  "type": "auction.winner.changed",
  "data": {
    "auctionId": "auc_01HQ5BWRJ5Y1P5RX0W5X0W5X0W5X",
    "cycleId": "cyc_01HQ5BWRJ5Y1P5RX0W5X0W5X0W5X",
    "serverSequence": 38,
    "payload": {
      "action": "DISQUALIFIED",
      "winner": {
        "id": "winner-id",
        "subscriberId": "subscriber-id",
        "enrolledSubscriberId": "enrollment-id",
        "subscriberName": "Annie Mohan",
        "subscriberAvatar": null,
        "subscriberEmail": "annie@example.com",
        "subscriberMobileNumber": "+919999999999",
        "amount": 1500,
        "division": 1,
        "status": "DISQUALIFIED",
        "type": "AUCTION",
        "selectionSource": "LIVE_BID_REVIEW",
        "auctionBidId": "bid-id",
        "auctionPrebidId": null,
        "selectedById": "staff-id",
        "selectedAt": "2026-08-03T10:35:00.000Z",
        "replacedById": null,
        "replacedAt": null,
        "disqualifiedById": "staff-id",
        "disqualifiedAt": "2026-08-03T10:40:00.000Z",
        "disqualificationReasonCode": "KYC_ISSUE",
        "disqualificationNote": "Document mismatch"
      },
      "suggestedReplacementCandidate": null
    }
  }
}

Deduplicate using the event id; apply it in serverSequence order. The public winner UI should use the companion auction.state.changed event, whose winner projection omits staff-only contact and audit fields.


auction.settings.updated

Description — Auction configuration (e.g. reserve price, extension policy, bid increments) was changed by staff, typically via the program/cycle management API. Pushed to the auction:<auctionId> room so live clients can reconcile.

Field Type Description
payload object The changed settings fields (shape is implementation-defined).
{
  "type": "auction.settings.updated",
  "data": {
    "auctionId": "auc_01HQ5BWRJ5Y1P5RX0W5X0W5X0W5X",
    "cycleId": "cyc_01HQ5BWRJ5Y1P5RX0W5X0W5X0W5X",
    "stateVersion": 3,
    "occurredAt": "2026-08-03T09:45:00.000Z",
    "payload": {
      "reservePrice": "20000.00",
      "allowStaffOfflineBids": true
    }
  }
}

Notes

  • These events are server-pushed; clients should treat them as informational and reconcile from auction.state.snapshot when available.
  • auction.prebid.created is only emitted before the auction goes live; during the live phase use auction.bid.created instead.
  • auction.announcement.updated and auction.announcement.deleted are currently published from the REST command path, not from a socket command.