Subscriber Auction Detail — REST & WebSocket Integration Guide¶
Complete contract for the subscriber auction detail screen: the REST read endpoint GET /v2/subscribers/me/auctions/:auctionId plus the realtime WebSocket events that keep that screen in sync.
Prebid is split across two transports:
- REST — all reads and writes (auction detail, prebid place/edit/cancel).
- WebSocket (
/ws) — the live room: state snapshots, prebid/bid lifecycle events, announcements, presence, and phase transitions.
The WebSocket never creates or modifies prebids — REST is the source of truth for every write. The socket tells the UI what changed.
Related docs: Auction — Frontend Integration Guide · Subscriber Prebid REST · Auction participant presence and counts · WebSocket auction events · WebSocket prebid events · WebSocket protocol
1. The endpoint¶
| Aspect | Value |
|---|---|
| Auth | Authorization: Bearer <access-token> |
| Role | SUBSCRIBER (403 otherwise) |
| Purpose | Auction detail + prebid context for one auction the subscriber is enrolled in |
1.1 Path parameter¶
| Param | Type | Notes |
|---|---|---|
auctionId | string | CUID. Invalid id → 400. |
1.2 Query parameters¶
| Param | Type | Default | Notes |
|---|---|---|---|
participantPageNumber | integer | 1 | Minimum 1. |
participantPageSize | integer | 10 | Between 1 and 100. |
1.3 Response envelope¶
Every successful response uses the standard envelope:
1.4 Error responses¶
| Status | Message (abridged) | When |
|---|---|---|
| 400 | Invalid auctionId | auctionId is not a valid CUID. |
| 400 | Auction is not enabled for this program. | Program bid type is not auction-based. |
| 401 | — | Missing/invalid bearer token. |
| 403 | — | Authenticated user is not a SUBSCRIBER. |
| 404 | Auction not found. | Auction does not exist, or the subscriber is not part of the auction's program. |
2. Response data — field reference¶
2.1 Top level¶
| Field | Type | Description |
|---|---|---|
auctionId | string | Auction id. |
cycleId | string | Cycle the auction belongs to. |
cycleNumber | number | Cycle number within the program. |
cycleStatus | string | CycleStatus enum (ACTIVE, UPCOMING, …). |
programId | string | Program id. |
programName | string | Program display name. |
prebidDocumentRequired | boolean | Whether a prebid document + signature are required. |
prebidDocumentTemplateVersionId | string | null | Pinned prebid document template version (form fields source). |
chitId | string | null | Program chit id. |
companyId | string | Operating company user id. |
companyName / companyAvatar | string | null | Company branding. |
companyBranch | string | null | Company branch. |
totalAmount | number | null | Cycle total amount. |
auctionStatus | string | AuctionStatus enum (SCHEDULED, LIVE, PAUSED, ENDED, …). |
prebidPhase | string | Derived prebid phase: NONE | OPEN | CLOSED. OPEN drives prebid placement; live participation is driven by auctionStatus (LIVE/PAUSED/ENDED). |
currentPhase | string | Always present — lifecycle summary (e.g. PENDING, PREBID_OPEN, PREBID_CLOSED, READY_TO_START, LIVE, PAUSED, ENDED). Render directly as a phase badge. |
liveStartedAt | string | null | Always present — ISO-8601 live-start marker (null until the auction actually goes live; set once, never cleared). |
prebidEndAt | string | null | Prebid window close (ISO-8601). |
auctionStartAt | string | null | Scheduled live start (ISO-8601). |
auctionEndAt | string | null | Computed end time (ISO-8601). |
auctionDurationSeconds | number | null | Live auction duration. |
prebidAmountsRevealed | boolean | True after staff reveal prebid amounts. |
prebidAmountsRevealedAt | string | null | Reveal timestamp, or null before reveal. |
minimumBidAmount | number | null | Floor for the bid amount. |
settings | object | Auction config snapshot (below). |
joinWindow | object | Current versioned join-window state. |
audience | object | null | null until the persisted join window opens; afterward contains audience counts and conditionally visible participant identities. |
liveBids | array | Visible live bids (auction-wide; empty unless LIVE/PAUSED/ENDED). |
announcements | array | Room announcements (max 50). |
enrollments | array | The subscriber's enrollments in this program (one per enrollment). |
winners | array | Declared winners; populated once the auction has ended. |
Note:
leadingBidAmountand per-enrollmenthasPlacedBid/bidCount/isLeadingBidderwere removed from this endpoint. Live-bid leading state is served by the WebSocket snapshot and the cycle-scoped overview (GET /v2/subscribers/me/cycles/:cycleId/auction/:enrolledSubscriberId).
audience stays visible after the join window closes or the auction ends. Its counts are available to every enrolled subscriber once the window has opened:
interface SubscriberAuctionAudience {
viewerCount: number;
joinedParticipantCount: number;
presentParticipantCount: number;
bidderCount: number;
participants: PaginatedResponse<{
subscriberId: string;
enrolledSubscriberId: string;
name: string | null;
avatar: string | null;
joinSource: 'ONLINE' | 'FLOOR';
joinedAt: string;
presenceStatus: 'PRESENT' | 'LEFT';
lastSeenAt: string | null;
}> | null;
}
participants is populated only when at least one of the requesting subscriber's enrollments has joined the auction. It includes all durable joined participants, including the requester. joinSource records how participation was created, while joinedAt is the durable admission time. presenceStatus reflects current online or floor presence. lastSeenAt is always null for a present participant; for a participant who left, it is the most recent present-to-left transition time, or null if they have never been observed present.
2.2 settings¶
| Field | Type | Description |
|---|---|---|
hasPrebid | boolean | Whether prebid is enabled. |
auctionBidMode | string | TOTAL_VALUE_DECREASING | DISCOUNT_INCREASING. |
auctionClosingMode | string | DURATION_MODE | CALL_MODE. |
auctionDurationSeconds | number | null | Live auction duration. |
auctionExtensionSeconds | number | Per-bid extension. |
auctionFirstCallSeconds / auctionSecondCallSeconds / auctionThirdCallSeconds | number | Call-mode timing. |
subscriberJoinGraceSeconds | number | Late-join grace window. |
subscriberJoinLeadSeconds | number | Seconds before start when the join window opens. |
allowStaffOfflineBids | boolean | Offline bid support. |
prebidMutabilityPolicy | string | MUTABLE_UNTIL_CLOSE | IMMUTABLE_CANCEL_ONLY. |
auctionJoiningRule | string | BEFORE_START | … |
2.3 liveBids[] (visible, auction-wide)¶
| Field | Type | Description |
|---|---|---|
id | string | Bid id. |
enrolledSubscriberId | string | Bidder enrollment id. |
subscriberName | string | null | Bidder display name. |
subscriberAvatar | string | null | Bidder avatar URL. |
amount | number | Bid amount. |
createdAt | string | ISO-8601. |
2.4 announcements[]¶
| Field | Type | Description |
|---|---|---|
id | string | Announcement id. |
auctionId | string | — |
cycleId | string | — |
actorId | string | null | Author user id. |
message | string | Announcement text. |
tone | string | Tone marker (e.g. INFO). |
createdAt | string | ISO-8601. |
2.5 joinWindow¶
| Field | Type | Description |
|---|---|---|
status | string | SCHEDULED, OPEN, or CLOSED. |
version | number | Increments on every reschedule. |
opensAt / openedAt | string | null | Configured opening boundary and actual opening time. |
closesAt / closedAt | string | null | Predicted and actual closing time. |
joiningRule | string | BEFORE_START, GRACE_PERIOD, or ANYTIME. |
Participant identities follow the conditional audience.participants rules above. Viewer identities and session audit data remain staff-only.
2.6 enrollments[]¶
One entry per enrollment of the subscriber in the program's cycle. Pick the one matching your enrolledSubscriberId — every prebid write must pass that id (see Subscriber Prebid REST).
| Field | Type | Description |
|---|---|---|
enrolledSubscriberId | string | Enrollment id — used for prebid place/edit/cancel. |
invoiceStatus | string | null | InvoiceStatus enum (PAID, DRAFT, …). |
currentUser | object | Eligibility for this enrollment (below). |
liveBids | array | This subscriber's own live bids. |
prebids | array | This subscriber's own prebids (max 20). |
currentUser¶
| Field | Type | Description |
|---|---|---|
canViewDetails | boolean | True after the endpoint authorizes this subscriber and enrollment, including for a PENDING auction. |
canSubscribeRealtime | boolean | True only for SCHEDULED, READY, LIVE, or PAUSED; use this before opening the auction WebSocket room. |
accessMode | string | VIEWER or PARTICIPANT; restored from durable admission on reconnect. |
hasJoined / joinedAt | boolean / string | null | Durable admission state and original join time. |
canJoin / joinBlockedReason | boolean / string | null | Authoritative join-button state. |
isPrebidDisqualified | boolean | Disqualified from the PREBID phase. |
isLiveBidDisqualified | boolean | Disqualified from the LIVE phase. |
canPrebid / prebidBlockedReason | boolean / string | null | Authoritative prebid-form state and stable reason when disabled. See the values below. |
canBid / bidBlockedReason | boolean / string | null | Requires LIVE, durable admission, no prior win, and no live disqualification. Payment reversal after admission does not revoke bidding. |
hasAlreadyWonProgram | boolean | One-win-per-program gate. |
isPaymentCompletedForCycle | boolean | Cycle invoice paid — prebid gate. |
prebidBlockedReason is one of:
| Value | Meaning |
|---|---|
PREBID_DISABLED | The auction configuration has prebid disabled. |
CYCLE_NOT_ACTIVE | Prebid operations require an active cycle. |
AUCTION_NOT_ACCEPTING_PREBIDS | The auction is no longer PENDING, SCHEDULED, or READY. |
PREBID_NOT_OPEN | No active prebid window is available. |
PREBID_CLOSED | The prebid deadline has passed. |
PAYMENT_REQUIRED | The cycle invoice has not been paid. |
PRIOR_WINNER | This enrollment already won in the program. |
PREBID_DISQUALIFIED | This enrollment is disqualified specifically from prebidding. |
ACTIVE_PREBID_EXISTS | One active prebid already exists; edit or cancel it according to policy. |
null | canPrebid is true. |
Viewing details does not require payment and does not require joining the live auction. Prebid placement also does not require live-auction participation. The backend rechecks eligibility when the prebid mutation is submitted.
liveBids[] (own)¶
| Field | Type | Description |
|---|---|---|
id | string | Bid id. |
amount | number | Bid amount. |
status | string | LEADING when this bid is the auction's current leader, otherwise OUTBID. |
createdAt | string | ISO-8601. |
prebids[] (own)¶
| Field | Type | Description |
|---|---|---|
id | string | Prebid id — used for prebid edit/cancel. |
amount | number | Prebid amount. |
status | string | AuctionPrebidStatus: ACTIVE, CANCELLED, DISQUALIFIED, APPLIED, SUPERSEDED. |
createdAt | string | ISO-8601. |
2.7 winners[]¶
| Field | Type | Description |
|---|---|---|
id | string | Winner record id. |
subscriberId | string | Winner user id. |
enrolledSubscriberId | string | Winner enrollment id. |
subscriberName / subscriberAvatar | string | null | Winner info. |
amount | number | null | null for prebid-sourced winners until prebid amounts are revealed. |
division | number | null | Winner division. |
status | string | CYCLE_WINNER_STATUSES (e.g. DECLARED). |
type | string | null | CycleWinningType (AUCTION, …). |
selectionSource | string | null | AUCTION_WINNER_SELECTION_SOURCES: PREBID_REVIEW, LIVE_BID_REVIEW, MANUAL_SELECTION, LOT_SELECTION |
auctionBidId / auctionPrebidId | string | null | Source bid/prebid id. |
selectedAt | string | null | ISO-8601. |
3. Example response¶
{
"status": "success",
"code": 200,
"message": "Auction fetched successfully.",
"data": {
"auctionId": "auction-id",
"cycleId": "cycle-id",
"cycleNumber": 3,
"cycleStatus": "ACTIVE",
"programId": "program-id",
"programName": "Monthly Chit",
"prebidDocumentRequired": true,
"prebidDocumentTemplateVersionId": "tv-id",
"chitId": "chit-id",
"companyId": "company-id",
"companyName": "Dichit",
"companyAvatar": null,
"companyBranch": "Kochi",
"totalAmount": 1000000,
"auctionStatus": "SCHEDULED",
"prebidPhase": "OPEN",
"currentPhase": "PREBID_OPEN",
"liveStartedAt": null,
"prebidEndAt": "2026-08-10T18:30:00.000Z",
"auctionStartAt": "2026-08-11T10:00:00.000Z",
"auctionEndAt": "2026-08-11T10:30:00.000Z",
"auctionDurationSeconds": 1800,
"prebidAmountsRevealed": false,
"prebidAmountsRevealedAt": null,
"leadingBidAmount": 20000,
"minimumBidAmount": 25000,
"settings": {
"hasPrebid": true,
"auctionBidMode": "TOTAL_VALUE_DECREASING",
"auctionClosingMode": "DURATION_MODE",
"auctionDurationSeconds": 1800,
"auctionExtensionSeconds": 120,
"auctionFirstCallSeconds": 30,
"auctionSecondCallSeconds": 20,
"auctionThirdCallSeconds": 10,
"subscriberJoinGraceSeconds": 0,
"subscriberJoinLeadSeconds": 600,
"allowStaffOfflineBids": true,
"prebidMutabilityPolicy": "MUTABLE_UNTIL_CLOSE",
"auctionJoiningRule": "BEFORE_START"
},
"joinWindow": {
"status": "OPEN",
"version": 2,
"opensAt": "2026-08-11T09:50:00.000Z",
"openedAt": "2026-08-11T09:50:00.012Z",
"closesAt": "2026-08-11T10:00:00.000Z",
"closedAt": null,
"joiningRule": "BEFORE_START"
},
"audience": {
"viewerCount": 4,
"joinedParticipantCount": 3,
"presentParticipantCount": 2,
"bidderCount": 1,
"participants": null
},
"liveBids": [],
"announcements": [],
"enrollments": [
{
"enrolledSubscriberId": "enrolled-id",
"invoiceStatus": "PAID",
"currentUser": {
"canViewDetails": true,
"canSubscribeRealtime": true,
"accessMode": "VIEWER",
"hasJoined": false,
"joinedAt": null,
"canJoin": true,
"joinBlockedReason": null,
"isPrebidDisqualified": false,
"isLiveBidDisqualified": false,
"canPrebid": false,
"prebidBlockedReason": "ACTIVE_PREBID_EXISTS",
"canBid": false,
"bidBlockedReason": "PARTICIPATION_REQUIRED",
"hasAlreadyWonProgram": false,
"isPaymentCompletedForCycle": true
},
"liveBids": [],
"prebids": [
{
"id": "prebid-id",
"amount": 25000,
"status": "ACTIVE",
"createdAt": "2026-08-10T12:00:00.000Z"
}
]
}
],
"winners": []
}
}
4. Related REST endpoints (same screen)¶
| Method | Path | Purpose |
|---|---|---|
GET | /v2/subscribers/me/auctions | Discover auctionId / enrolledSubscriberId. |
POST | /v2/subscribers/me/auctions/:auctionId/prebid | Place a prebid (body: enrolledSubscriberId, amount, signatureAssetId?). |
PUT | /v2/subscribers/me/auctions/:auctionId/prebid/:prebidId | Edit prebid (MUTABLE_UNTIL_CLOSE only). |
DELETE | /v2/subscribers/me/auctions/:auctionId/prebid/:prebidId?enrolledSubscriberId=… | Cancel prebid (both policies). |
GET | /v2/subscribers/me/cycles/:cycleId/auction/:enrolledSubscriberId | Cycle-scoped overview — primary live room screen payload (leadingBid, activePrebidCount, currentUser.isLeadingBidder, latestBid, activePrebid). |
GET | /v2/subscribers/me/documents/signatures | List READY signature assets for signatureAssetId. |
Full prebid write contract: Subscriber Prebid REST.
5. WebSocket — realtime contract¶
5.1 Connect & authenticate¶
Browser: Sec-WebSocket-Protocol: websocket.v1, bearer.<access-token> Native/mobile: Authorization: Bearer <access-token> header. Invalid/missing token → socket closes with code 1008.
5.2 Subscribe to the auction room¶
{
"id": "sub-001",
"type": "auction.subscribe",
"version": "1.0",
"source": "web-client",
"data": {
"auctionId": "auction-id",
"enrolledSubscriberId": "enrolled-id",
"lastSequence": 0
}
}
enrolledSubscriberId is required for subscriber sockets. Optional lastSequence (last seen auction-level data.serverSequence) requests replay.
The server then sends, in order:
ack— echo witheventType,auctionId,cycleId,room.auction.connected— confirmation +connectionId+heartbeatIntervalMs.auction.state.snapshot— full subscriber-scoped state (initial source of truth).auction.audience.snapshot— current participants and authoritative counters.
Leave with auction.unsubscribe (data.auctionId) when the screen closes.
5.3 Common envelope¶
{
"type": "auction.state.snapshot",
"id": "evt-1",
"version": "1.0",
"source": "auction-service",
"timestamp": "2026-08-10T10:00:00.000Z",
"sequence": 2,
"data": {}
}
5.4 Server → Client events for this screen¶
| Event | When | What to do |
|---|---|---|
auction.connected | On subscribe | Store connectionId / heartbeatIntervalMs. |
auction.state.snapshot | On subscribe, on reconnect | Render initial state from data.payload. |
auction.audience.snapshot + auction.audience.changed | Aggregate audience changes | Replace the four audience counters. |
auction.state.changed | Phase/schedule transitions (schedule_changed, started, paused, resumed, extended, closed, winner_selected, prebids_revealed) | Switch UI mode, update countdowns, re-check canPrebid. |
auction.settings.updated | Settings edited | Refresh settings display. |
auction.prebid.created | Staff-only; subscribers do not receive this event | Update own prebid state from the REST response/snapshot. |
auction.prebid.deleted | Staff/admin deleted a prebid (targeted) | Clear own activePrebid if ids match. |
auction.bidder.disqualified | Bidder disqualified (phase: "PREBID" blocks prebid) | Lock form / treat in-flight prebid as void. |
auction.bid.created · updated · rejected · deleted | Live bidding activity | Update live bid list + own bid state. |
auction.announcement.created · updated · deleted | Room announcements | Refresh announcements. |
5.5 Snapshot fields that matter for prebid¶
data.payload contains:
| Field | Type | Notes |
|---|---|---|
auction.auctionId, auction.cycleId | string | Room identity. |
auction.prebidPhase | string | Same phases as the REST detail (NONE/OPEN/CLOSED). |
auction.prebidStartAt / prebidEndAt | string | Prebid window. |
auction.activePrebidCount | number | Only surfaced once live. |
auction.minimumBidAmount / totalAmount | number | Amounts. |
auction.settings.hasPrebid / prebidMutabilityPolicy | object | Prebid gates. |
currentUser.canPrebid | boolean | Server-computed eligibility, including payment, prior winner, PREBID disqualification, and active-prebid state. It does not validate a submitted amount or signature asset. |
currentUser.prebidBlockedReason | string | null | Stable reason to display when canPrebid is false. |
currentUser.isPrebidDisqualified / isLiveBidDisqualified | boolean | Separate phase-specific restrictions. |
currentUser.activePrebid / latestPrebid | object | null | Own prebid state (id, amount, status, documentSubmissionId, generatedPdfUrl, …). |
currentUser.isLeadingBidder | boolean | Live-phase lead flag. |
currentUser.latestBid | object | null | Own latest live bid. |
currentUser.isPaymentCompletedForCycle / hasAlreadyWonProgram | boolean | Prebid gates. |
currentUser.disqualifications | array | phase: "PREBID" blocks prebid. |
Frontend rule: render from currentUser.canPrebid, currentUser.prebidBlockedReason, activePrebid, and auction.prebidPhase. Never decide eligibility client-side.
5.6 Prebid lifecycle events¶
auction.prebid.created — persisted and delivered only to staff. Subscriber clients do not receive it. After the REST POST, update the current user's prebid state from the response and reconcile from a snapshot/detail fetch when needed.
auction.prebid.deleted — staff/admin deletion path only, targeted at the affected subscriber. Payload: metadata.prebidId / metadata.enrolledSubscriberId. The subscriber's own REST cancel (DELETE …/prebid/:prebidId) publishes no event — the REST response (status: "CANCELLED") is the source of truth.
auction.state.changed — schedule_changed (window open/close) recomputes the prebid form state; started means the prebid window is over.
6. Recommended integration flow¶
- Fetch
GET /v2/subscribers/me/auctions/:auctionId→ render auction + prebid context (fields, settings, ownprebids, admission state, and audience counts). - Open
/ws,auction.subscribewithauctionId+enrolledSubscriberId(fetchauctionIdvia REST first; auction row guaranteed beforeREADY/LIVE) (+lastSequenceon reconnect). - On
auction.state.snapshot→ adopt as the live source of truth (phase,canPrebid,activePrebid,isLeadingBidder). - User places a prebid: REST
POST …/prebidwithenrolledSubscriberId+amount(+signatureAssetIdwhenprebidDocumentRequired). Update UI from the REST response (prebidId,status: "ACTIVE"); reconcile from a fresh detail fetch when needed. - User cancels: REST
DELETE …/prebid/:prebidId?enrolledSubscriberId=…— response is truth; no socket event follows. - Apply
auction.state.changedtransitions to switch prebid ⇄ live modes and update countdowns; updatecanPrebidfromauction.bidder.disqualified. - During LIVE: render
liveBidsfrom REST or socket bid events; own-bid leading state fromcurrentUser.isLeadingBidder(socket) or the cycle overview. auction.unsubscribewhen leaving the screen.
Reconnection¶
- Persist the last seen auction-level
data.serverSequence(present on bid-activity events) and pass it back aslastSequenceon resubscribe. - Prebid events are not persisted in the replay log — after a gap, re-read own prebid state from the REST detail response or the fresh snapshot.
- The envelope-level
sequenceis per-connection only.