Skip to content

Auction — Frontend Integration Guide

For the current realtime payload and replay migration, see Auction current changes — complete frontend integration.

This guide documents the complete frontend-facing contract for the Dichit auction feature (v2 API). It covers the REST endpoints used by the subscriber app and the company/admin auction console, plus the WebSocket protocol for the live auction room.

Audiences:

  • Subscriber app (web/mobile) — browse auctions, submit/cancel prebids, join the live room, place live bids.
  • Company console — run prebid review, schedule/start/pause/resume/end the live auction, review bids, declare and disqualify winners, reveal prebids.
  • Superadmin console — same console surface as the company console, with cross-company access.

Related docs:


1. Authentication

REST

All auction endpoints require an authenticated user with the appropriate role:

Authorization: Bearer <access-token>

Route-level role guards:

Role Scope
SUBSCRIBER GET /v2/subscribers/me/** routes
COMPANY GET/PATCH/POST/DELETE /v2/companies/** console routes
SUPERADMIN GET/PATCH/POST/DELETE /v2/admin/** console routes

WebSocket

The realtime room uses a single endpoint for every role:

wss://api.example.com/ws

Native/mobile clients send the access token as an HTTP header:

Authorization: Bearer <access-token>

Browser clients cannot set custom WebSocket headers, so send the token through Sec-WebSocket-Protocol:

Sec-WebSocket-Protocol: websocket.v1, bearer.<access-token>

Invalid or missing tokens close the socket with close code 1008.


2. Common REST Envelope

Every REST response uses the same envelope:

{
  "status": "success",
  "code": 200,
  "data": {},
  "message": "Auctions fetched successfully.",
  "error": null
}

List collections follow the standard pagination shape:

{
  "count": 42,
  "pageNumber": 1,
  "pageSize": 10,
  "totalPages": 5,
  "hasPreviousPage": false,
  "hasNextPage": true
}

Query parameters for pagination are pageNumber (min 1) and pageSize (min 1, max 100).


3. Auction Lifecycle and Phases

Auction status (auctionStatus)

PENDING     — auction created, not yet scheduled
SCHEDULED   — prebid window open/closed, live auction not yet started
READY       — scheduled and approved (only when approval is required)
LIVE        — live bidding in progress
PAUSED      — live auction paused by staff
ENDED       — auction closed (winner selection / reveal may still happen)
COMPLETE    — auction fully settled
CANCELLED   — auction cancelled

Prebid phase (prebidPhase)

Derived server-side from the prebid window state. Use it to drive prebid-related UI; live / paused / ended state comes from auctionStatus:

NONE    — no prebid configured for this program
OPEN    — subscribers can submit/cancel prebids
CLOSED  — prebid window closed; prebids locked

prebidPhase replaces the old availabilityPhase. PREBID_OPEN is now OPEN; PREBID_CLOSED_WAITING_AUCTION / AWAITING_AUCTION are now CLOSED; an auction with no prebid is NONE. LIVE / PAUSED / ENDED are auctionStatus values now, not phase values.

Approval (approvalRequired)

Resolved from the company/platform policy (see §5.13). When approvalRequired is true, the auction must be approved (§5.6) before it can start — approval moves it from SCHEDULED to READY. The default is false, which skips the approval step.

Review status is removed

The old console-only review-status field is gone. Its states now map onto the status/phase model above: a pending-start auction is SCHEDULED (or READY when approval is required), a closed prebid window is prebidPhase === 'CLOSED', live bidding is auctionStatus === 'LIVE', and post-auction winner review is auctionStatus === 'ENDED'.

Settings (settings)

Shared response shape across subscriber and console payloads:

Field Type Notes
hasPrebid boolean Prebid enabled for this program
auctionBidMode string DISCOUNT_INCREASING | TOTAL_VALUE_DECREASING
auctionClosingMode string DURATION_MODE | CALL_MODE
auctionDurationSeconds number? Default duration when scheduling
auctionExtensionSeconds number Auto-extension after a late bid
auctionFirstCallSeconds number Closing-call timing (call mode)
auctionSecondCallSeconds number Closing-call timing (call mode)
auctionThirdCallSeconds number Closing-call timing (call mode)
subscriberJoinGraceSeconds number Join grace after live start
subscriberJoinLeadSeconds number Join-window lead time before auction start
allowStaffOfflineBids boolean Staff may bid on behalf of floor users
prebidMutabilityPolicy string IMMUTABLE_CANCEL_ONLY | MUTABLE_UNTIL_CLOSE
auctionJoiningRule string BEFORE_START | GRACE_PERIOD | ANYTIME

4. Subscriber REST API

All routes below require a SUBSCRIBER token.

4.1 List subscriber auctions

GET /v2/subscribers/me/auctions

Query:

Param Type Default Notes
pageNumber number 1
pageSize number 10 max 100
search string — optional free-text search

Response data:

{
  "count": 2,
  "pageNumber": 1,
  "pageSize": 10,
  "totalPages": 1,
  "hasPreviousPage": false,
  "hasNextPage": false,
  "auctions": [
    {
      "auctionId": "auction-id",
      "cycleId": "cycle-id",
      "enrolledSubscriberId": "enrolled-id",
      "programId": "program-id",
      "programName": "Monthly Chit",
      "chitId": "chit-id",
      "companyId": "company-id",
      "companyName": "Dichit",
      "companyAvatar": "https://...",
      "companyBranch": "Kochi",
      "cycleNumber": 3,
      "cycleStatus": "ACTIVE",
      "auctionStatus": "SCHEDULED",
      "prebidPhase": "OPEN",
      "prebidEndAt": "2026-08-10T18:30:00.000Z",
      "auctionStartAt": "2026-08-11T10:00:00.000Z",
      "auctionDurationSeconds": 1800,
      "auctionEndAt": "2026-08-11T10:30:00.000Z",
      "minimumBidAmount": 25000,
      "totalAmount": 1000000,
      "leadingBidAmount": null,
      "invoiceStatus": null
    }
  ]
}

leadingBidAmount is live-bid-only: it is null before the live auction starts, and when the auction has a prebid it stays null until the auction ends / prebid amounts are revealed — the auction opens with no prebid-derived base amount (see §7 Amount visibility).

The cycle lists on GET /v2/subscribers/me/programs/:programId/cycles and GET /v2/companies/programs/:programId/cycles now include auctionId on each cycle item, so you can deep-link from a cycle to its auction.

4.2 Get subscriber auction detail

GET /v2/subscribers/me/auctions/:auctionId

Query:

Param Type Default Notes
participantPageNumber number 1 pagination for the participants list
participantPageSize number 10 max 100, pagination for participants

Response data:

{
  "auctionId": "auction-id",
  "cycleId": "cycle-id",
  "cycleNumber": 3,
  "cycleStatus": "ACTIVE",
  "programId": "program-id",
  "programName": "Monthly Chit",
  "chitId": "chit-id",
  "companyId": "company-id",
  "companyName": "Dichit",
  "companyAvatar": "https://...",
  "companyBranch": "Kochi",
  "totalAmount": 1000000,
  "auctionStatus": "SCHEDULED",
  "prebidPhase": "OPEN",
  "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": null,
  "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"
  },
  "liveBids": [
    {
      "id": "bid-id",
      "enrolledSubscriberId": "enrolled-id",
      "subscriberName": "Subscriber One",
      "subscriberAvatar": "https://...",
      "amount": 25000,
      "createdAt": "2026-08-11T10:05:00.000Z"
    }
  ],
  "announcements": [
    {
      "id": "announcement-id",
      "auctionId": "auction-id",
      "cycleId": "cycle-id",
      "actorId": null,
      "message": "Auction is live",
      "tone": "INFO",
      "createdAt": "2026-08-11T10:00:00.000Z"
    }
  ],
  "audience": {
    "viewerCount": 4,
    "joinedParticipantCount": 12,
    "presentParticipantCount": 8,
    "bidderCount": 3,
    "participants": {
      "count": 12,
      "pageNumber": 1,
      "pageSize": 10,
      "totalPages": 2,
      "hasPreviousPage": false,
      "hasNextPage": true,
      "items": [
        {
          "subscriberId": "subscriber-id",
          "enrolledSubscriberId": "enrolled-id",
          "name": "Subscriber One",
          "avatar": "https://...",
          "joinSource": "ONLINE",
          "presenceStatus": "PRESENT"
        }
      ]
    }
  },
  "enrollments": [
    {
      "enrolledSubscriberId": "enrolled-id",
      "invoiceStatus": null,
      "currentUser": {
        "canViewDetails": true,
        "canSubscribeRealtime": true,
        "isPrebidDisqualified": false,
        "isLiveBidDisqualified": false,
        "canPrebid": false,
        "prebidBlockedReason": "AUCTION_NOT_ACCEPTING_PREBIDS",
        "canBid": true,
        "hasAlreadyWonProgram": false,
        "isPaymentCompletedForCycle": true
      },
      "liveBids": [
        {
          "id": "bid-id",
          "amount": 25000,
          "status": "LEADING",
          "createdAt": "2026-08-11T10:05:00.000Z"
        }
      ],
      "prebids": [
        {
          "id": "prebid-id",
          "amount": 25000,
          "status": "ACTIVE",
          "createdAt": "2026-08-10T12:00:00.000Z"
        }
      ]
    }
  ],
  "winners": [
    {
      "id": "winner-id",
      "subscriberId": "subscriber-id",
      "enrolledSubscriberId": "enrolled-id",
      "subscriberName": "Subscriber One",
      "subscriberAvatar": "https://...",
      "amount": 25000,
      "division": 1,
      "status": "DECLARED",
      "type": "AUCTION",
      "selectionSource": "PREBID_REVIEW",
      "auctionBidId": null,
      "auctionPrebidId": "prebid-id",
      "selectedAt": "2026-08-11T10:05:00.000Z"
    }
  ]
}

Notes:

  • participants is paginated — it is an object with items, not a plain array. source is ONLINE or FLOOR (AuctionParticipationSource); isOnline reflects live presence.
  • liveBids lists live bids the subscriber may see. Prebid entries are excluded until reveal.
  • enrollments[].liveBids are the subscriber's own live bids (renamed from bids); enrollments[].prebids are the subscriber's own prebids with their current status.
  • winners is populated only once auctionStatus === 'ENDED' and lists the cycle's declared winners (disqualified winners are excluded). Prebid-sourced winner amounts are null until prebid amounts are revealed.
  • enrollments[].currentUser drives detail, realtime, prebid, join, and live-bid controls. Use the server booleans and their blocked reasons directly.

4.3 Get subscriber auction overview (per cycle enrollment)

GET /v2/subscribers/me/cycles/:cycleId/auction/:enrolledSubscriberId

This is the primary screen payload for the auction room screen. Response data:

{
  "auctionId": "auction-id",
  "cycleId": "cycle-id",
  "programId": "program-id",
  "companyId": "company-id",
  "stateVersion": 7,
  "cycleNumber": 3,
  "cycleStatus": "ACTIVE",
  "auctionStatus": "LIVE",
  "programBidType": "AUCTION",
  "minimumBidAmount": 25000,
  "totalAmount": 1000000,
  "leadingBid": {
    "id": "bid-id",
    "subscriberId": "subscriber-id",
    "enrolledSubscriberId": "enrolled-id",
    "amount": 25000,
    "createdAt": "2026-08-11T10:05:00.000Z"
  },
  "bidCount": 3,
  "activePrebidCount": 5,
  "prebidAmountsRevealed": false,
  "prebidAmountsRevealedAt": null,
  "prebidStartAt": "2026-08-05T10:00:00.000Z",
  "prebidEndAt": "2026-08-10T18:30:00.000Z",
  "auctionStartAt": "2026-08-11T10:00:00.000Z",
  "auctionEndAt": "2026-08-11T10:30:00.000Z",
  "minimumBidReachedAt": null,
  "startedAt": "2026-08-11T10:00:00.000Z",
  "pausedAt": null,
  "endedAt": null,
  "auctionDurationSeconds": 1800,
  "prebidPhase": "CLOSED",
  "settings": {},
  "auctionBaseAmount": 1000000,
  "liveBids": [
    {
      "id": "bid-id",
      "subscriberId": "subscriber-id",
      "enrolledSubscriberId": "enrolled-id",
      "subscriberName": "Subscriber One",
      "subscriberAvatar": "https://...",
      "amount": 25000,
      "type": "LIVE",
      "createdAt": "2026-08-11T10:05:00.000Z"
    }
  ],
  "currentUser": {
    "subscriberId": "subscriber-id",
    "enrolledSubscriberId": "enrolled-id",
    "isLeadingBidder": false,
    "isPaymentCompletedForCycle": true,
    "hasAlreadyWonProgram": false,
    "canPrebid": false,
    "prebidBlockedReason": "ACTIVE_PREBID_EXISTS",
    "isPrebidDisqualified": false,
    "isLiveBidDisqualified": false,
    "activePrebid": {
      "id": "prebid-id",
      "amount": 30000,
      "createdAt": "2026-08-05T10:30:00.000Z",
      "updatedAt": "2026-08-06T09:00:00.000Z",
      "documentSubmissionId": "doc-id",
      "documentSubmissionStatus": "GENERATED",
      "generatedPdfUrl": "https://..."
    },
    "latestBid": {
      "id": "bid-id",
      "amount": 25000,
      "createdAt": "2026-08-11T10:05:00.000Z",
      "disqualifiedAt": null,
      "disqualificationReasonCode": null,
      "deletionReason": null,
      "deletedAt": null
    },
    "latestPrebid": {
      "id": "prebid-id",
      "amount": 30000,
      "status": "ACTIVE",
      "createdAt": "2026-08-05T10:30:00.000Z",
      "updatedAt": "2026-08-06T09:00:00.000Z",
      "documentSubmissionId": "doc-id",
      "documentSubmissionStatus": "GENERATED",
      "generatedPdfUrl": "https://...",
      "disqualifiedAt": null,
      "disqualificationReasonCode": null,
      "deletionReason": null,
      "deletedAt": null
    },
    "disqualifications": []
  }
}

programBidType values: AUCTION / AUCTION_AND_LOT / FIXED_PRICE / LOT_ONLY. leadingBid.amount is present once the auction has a leading live bid; prebid-origin amounts are only exposed via prebids / winners after prebid amounts are revealed.

4.4 Prebid form configuration

The dedicated form endpoint was removed together with the legacy cycle-keyed API. Form configuration now comes from the auction detail response (§4.3):

  • prebidDocumentRequired and prebidDocumentTemplateVersionId — whether a prebid document is needed and which template version to render.
  • settings.prebidMutabilityPolicy — whether the submitted prebid can be edited (MUTABLE_UNTIL_CLOSE) or only cancelled (IMMUTABLE_CANCEL_ONLY).
  • Resolve the actual template fields via §4.9 (get template version by id) when a template version is configured.

fieldType values: TEXT, CURRENCY_AMOUNT, SIGNATURE_IMAGE.

4.5 Prebid state (current prebid)

There is no dedicated GET for the subscriber's prebid; read it from the auction detail response (§4.3): latestPrebid (current user's own prebid) and enrollments[].prebids[] (per enrollment). latestPrebid is null when the subscriber has no prebid. status values: ACTIVE, CANCELLED, DISQUALIFIED, APPLIED, SUPERSEDED.

4.6 Place prebid

POST /v2/subscribers/me/auctions/:auctionId/prebid
{
  "enrolledSubscriberId": "enrolled-subscriber-id",
  "amount": 30000,
  "signatureAssetId": "asset-id"
}

enrolledSubscriberId is required and selects the enrollment the prebid is placed for. signatureAssetId is required only when the prebid form requires a signature document. Creating a prebid also creates/queues the prebid document submission.

Response:

{
  "auctionId": "auction-id",
  "cycleId": "cycle-id",
  "prebidId": "prebid-id",
  "enrolledSubscriberId": "enrolled-subscriber-id",
  "status": "ACTIVE",
  "documentSubmissionId": "doc-id"
}

Placement allowed only while prebidPhase === 'OPEN'. Only one active prebid is allowed per enrollment — placing again while one is active is rejected; cancel first.

4.7 Edit prebid

PUT /v2/subscribers/me/auctions/:auctionId/prebid/:prebidId

Body is the same as place (enrolledSubscriberId, amount, optional signatureAssetId). Allowed only while the prebid window is open and settings.prebidMutabilityPolicy === 'MUTABLE_UNTIL_CLOSE'. When the policy is IMMUTABLE_CANCEL_ONLY, updating the amount after creation is rejected; the subscriber must cancel and re-submit.

Response mirrors the place response with status: "ACTIVE".

4.8 Cancel prebid

DELETE /v2/subscribers/me/auctions/:auctionId/prebid/:prebidId?enrolledSubscriberId=enrolled-subscriber-id

Response mirrors the place response with status: "CANCELLED". Cancellation is allowed under both mutability policies while the prebid window is open.

4.9 Get a published template version by id

GET /v2/common/templates/versions/:templateVersionId

Available to any authenticated role (SUBSCRIBER / COMPANY / SUPERADMIN). Resolves a published, active template version from its version id and returns the same template shape used by the prebid form (§4.4) — useful when the app only holds a prebidDocumentTemplateVersionId (e.g. from the auction detail) and needs to render the form without the cycle/program context:

{
  "templateId": "template-id",
  "templateKey": "chit-prebid",
  "templateName": "Prebid Form",
  "templateDescription": null,
  "templateVersionId": "version-id",
  "templateVersion": 1,
  "fileName": "prebid.pdf",
  "fields": [
    {
      "fieldKey": "amount",
      "label": "Bid Amount",
      "fieldType": "CURRENCY_AMOUNT",
      "required": true,
      "maxLength": null,
      "sortOrder": 1
    }
  ]
}

Returns 404 when the version does not exist or is not a published version of an active template (drafts are never exposed).


5. Company / Admin Console REST API

Company and superadmin consoles share the same route handlers under two mounts:

  • GET|PATCH|POST|DELETE /v2/companies/auctions/:auctionId/... (COMPANY role)
  • GET|PATCH|POST|DELETE /v2/admin/auctions/:auctionId/... (SUPERADMIN role)

Company users can only access auctions owned by their company; the server enforces ownership on every call.

5.1 Get auction console overview

GET /v2/companies/auctions/:auctionId
GET /v2/admin/auctions/:auctionId

Query — three independent pagination groups:

Param Default Notes
bidPageNumber 1 pagination for liveBids
bidPageSize 10 max 100
prebidPageNumber 1 pagination for prebids
prebidPageSize 10 max 100
participantPageNumber 1 pagination for participants
participantPageSize 10 max 100

Response data (highlights; full field set in AdminAuctionResponseSchema):

{
  "auctionId": "auction-id",
  "cycleId": "cycle-id",
  "stateVersion": 7,
  "cycleNumber": 3,
  "cycleStatus": "ACTIVE",
  "auctionStatus": "SCHEDULED",
  "programId": "program-id",
  "companyId": "company-id",
  "programBidType": "AUCTION",
  "auctionBaseAmount": null,
  "minimumBidAmount": 25000,
  "totalAmount": 1000000,
  "leadingBid": null,
  "bidCount": 0,
  "activePrebidCount": 5,
  "prebidAmountsRevealed": false,
  "prebidAmountsRevealedAt": null,
  "settings": {},
  "prebidStartAt": "2026-08-05T10:00:00.000Z",
  "prebidEndAt": "2026-08-10T18:30:00.000Z",
  "auctionStartAt": "2026-08-11T10:00:00.000Z",
  "auctionDurationSeconds": 1800,
  "auctionEndAt": "2026-08-11T10:30:00.000Z",
  "prebidPhase": "CLOSED",
  "programDivisions": 1,
  "declaredWinnerCount": 0,
  "remainingWinnerSlots": 1,
  "minimumBidReachedAt": null,
  "startedAt": null,
  "pausedAt": null,
  "endedAt": null,
  "winnerId": null,
  "winners": [],
  "participants": {
    "count": 12,
    "pageNumber": 1,
    "pageSize": 10,
    "totalPages": 2,
    "hasPreviousPage": false,
    "hasNextPage": true,
    "items": [
      {
        "subscriberId": "subscriber-id",
        "enrolledSubscriberId": "enrolled-id",
        "name": "Subscriber One",
        "avatar": "https://...",
        "mobileNumber": "+919000002001",
        "countryCode": "+91",
        "invoiceStatus": null,
        "isPaymentCompletedForCycle": true,
        "isOnline": false,
        "source": "FLOOR",
        "hasBid": false,
        "hasPrebid": true,
        "latestBidAmount": null,
        "isDisqualified": false,
        "hasWonCycle": false,
        "wonCycleNumber": null
      }
    ]
  },
  "announcements": [],
  "realtimeStats": {
    "bidVelocityPerMinute": 0,
    "averageBidIntervalSeconds": null,
    "uniqueBidders": 0,
    "totalBids": 0
  },
  "liveBids": {
    "count": 0,
    "pageNumber": 1,
    "pageSize": 10,
    "totalPages": 0,
    "hasPreviousPage": false,
    "hasNextPage": false,
    "items": []
  },
  "prebids": {
    "count": 5,
    "pageNumber": 1,
    "pageSize": 10,
    "totalPages": 1,
    "hasPreviousPage": false,
    "hasNextPage": false,
    "items": [
      {
        "id": "prebid-id",
        "auctionId": "auction-id",
        "subscriberId": "subscriber-id",
        "enrolledSubscriberId": "enrolled-id",
        "documentSubmissionId": "doc-id",
        "documentSubmissionStatus": "GENERATED",
        "generatedPdfUrl": "https://...",
        "subscriberName": "Subscriber One",
        "subscriberAvatar": null,
        "amount": null,
        "status": "ACTIVE",
        "createdAt": "2026-08-05T10:30:00.000Z",
        "updatedAt": "2026-08-06T09:00:00.000Z"
      }
    ]
  }
}

Console-specific notes:

  • winners is only populated when auctionStatus === 'ENDED' (or COMPLETE); it is an empty array at every other status. This field replaces the old currentWinner / declaredWinners pair.
  • realtimeStats is null before the auction reaches LIVE/PAUSED/ENDED and is otherwise an object with bidVelocityPerMinute, averageBidIntervalSeconds, uniqueBidders, totalBids.
  • participants, liveBids, and prebids are all paginated objects with items.
  • Hidden prebid amounts come back as null until reveal (see §7 Amount visibility).

5.2 Eligible winner candidates

GET /v2/companies/auctions/:auctionId/eligible-winner-candidates
GET /v2/admin/auctions/:auctionId/eligible-winner-candidates

Query: pageNumber, pageSize.

Response data:

{
  "cycleId": "cycle-id",
  "programId": "program-id",
  "eligibleWinnerCandidates": {
    "count": 3,
    "pageNumber": 1,
    "pageSize": 10,
    "totalPages": 1,
    "hasPreviousPage": false,
    "hasNextPage": false,
    "items": [
      {
        "enrolledSubscriberId": "enrolled-id",
        "subscriberId": "subscriber-id",
        "programId": "program-id",
        "name": "Subscriber One",
        "avatar": null,
        "email": "sub@example.com",
        "mobileNumber": "+919000002001"
      }
    ]
  }
}

5.3 Auction action logs

GET /v2/companies/auctions/:auctionId/action-logs
GET /v2/admin/auctions/:auctionId/action-logs

Response data:

{
  "auctionId": "auction-id",
  "cycleId": "cycle-id",
  "actionLogs": [
    {
      "id": "log-id",
      "auctionId": "auction-id",
      "cycleId": "cycle-id",
      "actorId": "user-id",
      "action": "SCHEDULE",
      "reason": null,
      "metadata": {},
      "createdAt": "2026-08-05T10:00:00.000Z"
    }
  ]
}

action values: SCHEDULE, RESCHEDULE, START, AUTO_START, PAUSE, RESUME, END, AUTO_END, DECLARE_WINNER, DISQUALIFY_WINNER, REPLACE_DISQUALIFIED_WINNER, RECORD_LOT, APPROVE, CANCEL, DELETE_BID, DELETE_PREBID, DISQUALIFY_BIDDER, REVEAL_PREBIDS, UPDATE_SETTINGS, STAFF_OFFLINE_BID.

5.4 Auction audience audit

GET /v2/companies/auctions/:auctionId/audience-sessions
GET /v2/admin/auctions/:auctionId/audience-sessions

Query:

Param Type Notes
enrolledSubscriberId string optional enrollment filter
accessMode string VIEWER | PARTICIPANT
activeOnly boolean only sessions without a disconnect
pageNumber / pageSize number standard pagination

Response data:

{
  "auctionId": "auction-id",
  "cycleId": "cycle-id",
  "count": 2,
  "participationCount": 1,
  "pageNumber": 1,
  "pageSize": 10,
  "totalPages": 1,
  "hasPreviousPage": false,
  "hasNextPage": false,
  "participations": [
    {
      "id": "participant-id",
      "auctionId": "auction-id",
      "cycleId": "cycle-id",
      "subscriberId": "subscriber-id",
      "enrolledSubscriberId": "enrolled-id",
      "source": "ONLINE",
      "joinWindowVersion": 1,
      "joinedAt": "2026-08-11T10:00:05.000Z"
    }
  ],
  "sessions": [
    {
      "id": "session-id",
      "connectionId": "conn-id",
      "initialAccessMode": "VIEWER",
      "currentAccessMode": "PARTICIPANT",
      "connectedAt": "2026-08-11T10:00:00.000Z",
      "lastSeenAt": "2026-08-11T10:05:00.000Z",
      "becameParticipantAt": "2026-08-11T10:00:05.000Z",
      "disconnectedAt": null,
      "disconnectReason": null
    }
  ]
}

Disconnect reasons are UNSUBSCRIBE, SOCKET_CLOSE, HEARTBEAT_EXPIRED, AUCTION_ENDED, and SERVER_SHUTDOWN. Company responses omit IP address and user agent; those fields are available only to super-admin audit access.

5.5 Schedule auction

PATCH /v2/companies/auctions/:auctionId/schedule
PATCH /v2/admin/auctions/:auctionId/schedule
{
  "auctionStartAt": "2026-08-11T10:00:00.000Z",
  "auctionDurationSeconds": 1800,
  "reason": "Schedule for cycle 3",
  "auctionBidMode": "TOTAL_VALUE_DECREASING",
  "auctionClosingMode": "DURATION_MODE",
  "auctionExtensionSeconds": 120,
  "auctionFirstCallSeconds": 30,
  "auctionSecondCallSeconds": 20,
  "auctionThirdCallSeconds": 10,
  "subscriberJoinGraceSeconds": 0,
  "allowStaffOfflineBids": true,
  "prebidMutabilityPolicy": "MUTABLE_UNTIL_CLOSE",
  "auctionJoiningRule": "BEFORE_START"
}

auctionStartAt and auctionDurationSeconds are required; all settings are optional and override the program defaults for this cycle. The start time must be in the future. For immediate start, send the WebSocket staff command auction.status.update with { "status": "START" }.

Response data: auctionId, cycleId, stateVersion, status, prebidStartAt, prebidEndAt, auctionStartAt, auctionDurationSeconds, auctionEndAt, prebidPhase.

5.6 Approve auction (approval-required policy only)

POST /v2/companies/auctions/:auctionId/approve
POST /v2/admin/auctions/:auctionId/approve
{
  "reason": "Approve to start"
}

Only auctions whose resolved settings enable approvalRequired need this step. The request is rejected with 400 when approvalRequired is disabled ("This auction does not require approval. Approving an auction without the approval-required policy is not allowed.") or when the auction is not SCHEDULED. When enabled, approving sets auctionStatus to READY and writes an APPROVE action log entry. Response data: { auctionId, cycleId, status: "READY", approvalRequired, auctionStartAt }.

An auction whose window is closed does not require amount review — prebids are sealed and proceed to the live round directly. When approvalRequired is disabled (the default), no approval is needed: the auction starts directly from SCHEDULED via the WebSocket start command (or its scheduled auto-start).

5.7 Reveal prebid amounts

POST /v2/companies/auctions/:auctionId/prebids/reveal
POST /v2/admin/auctions/:auctionId/prebids/reveal
{
  "reason": "Auction completed"
}

Only allowed when the auction is ENDED and hasPrebid is true. Idempotent — repeating the call after a reveal is a no-op. After reveal the server sets prebidAmountsRevealed: true, prebidAmountsRevealedAt, logs REVEAL_PREBIDS, and publishes auction.state.changed with payload.transition: "prebids_revealed".

The removed cycle-scoped reveal URLs under .../cycles/:cycleId/auction/prebids/reveal should not be used by new clients.

5.8 Replace winner

There is no PATCH /winner endpoint. To replace a declared winner, disqualify the current one via POST .../winner/disqualify (§5.9) and then declare the next candidate via the WebSocket auction.winner.declare command (mode CANDIDATE with a different bidId / prebidId).

5.9 Disqualify winner

POST /v2/companies/auctions/:auctionId/winner/disqualify
POST /v2/admin/auctions/:auctionId/winner/disqualify
{
  "winnerId": "winner-id",
  "disqualificationReasonCode": "PAYMENT_ISSUE",
  "disqualificationNote": "Payment not received",
  "reason": "Disqualify winner"
}

disqualificationReasonCode values: KYC_ISSUE, PAYMENT_ISSUE, ELIGIBILITY_ISSUE, RULE_VIOLATION, OTHER.

5.10 Delete prebid

DELETE /v2/companies/auctions/:auctionId/prebids/:prebidId
DELETE /v2/admin/auctions/:auctionId/prebids/:prebidId

Deletes a specific prebid (disqualification/review workflow). No body.

5.11 Manual prebid window open/close

Opens or closes the prebid window before the live auction. The live auction can only start once the window is closed.

POST /v2/companies/auctions/:auctionId/prebid/open
POST /v2/admin/auctions/:auctionId/prebid/open
POST /v2/companies/auctions/:auctionId/prebid/close
POST /v2/admin/auctions/:auctionId/prebid/close
{
  "reason": "Staff control"
}

Responses carry prebidStartAt / prebidEndAt and a boolean prebidOpened / prebidClosed (false when the action was an idempotent no-op). Opening requires the window to still be naturally open; closing pins prebidEndAt to now (deriving prebidPhase to CLOSED) and clears any pending auto-open job.

5.12 Mutation response envelope

POST/PATCH console mutations return a shared data envelope; fields are null unless relevant to the action:

{
  "auctionId": "auction-id",
  "cycleId": "cycle-id",
  "stateVersion": 8,
  "status": "LIVE",
  "approvalRequired": false,
  "leadingBidId": "bid-id",
  "leadingBidAmount": 25000,
  "prebidAmountsRevealed": false,
  "prebidAmountsRevealedAt": null,
  "prebidAmountsRevealedById": null,
  "prebidStartAt": "2026-08-05T10:00:00.000Z",
  "prebidEndAt": "2026-08-10T18:30:00.000Z",
  "prebidOpened": null,
  "prebidClosed": null,
  "bidId": null,
  "prebidId": null,
  "disqualificationId": null,
  "enrolledSubscriberId": null,
  "phase": null,
  "winnerId": null,
  "winningBidId": null,
  "division": null
}

Use stateVersion to detect stale console state; the realtime stream is the authoritative source for live updates.

5.13 Get resolved company auction policy

Reads the effective auction settings a new program created by this company would inherit before any program exists, folding default < platform < company. Company overrides win, a key the company never set falls back to the platform policy, and anything still unset falls back to the server default. Use it to prefill the auction setup step of program creation.

Role Endpoint
COMPANY GET /v2/companies/company-auction-policy/resolved
SUPERADMIN GET /v2/admin/companies/:companyId/company-auction-policy/resolved

Company callers are scoped to their own tenant; the admin mount targets any company by path. A missing company returns 404.

Response data:

{
  "companyId": "company-id",
  "settings": {
    "hasPrebid": true,
    "auctionBidMode": "TOTAL_VALUE_DECREASING",
    "auctionClosingMode": "DURATION_MODE",
    "auctionDurationSeconds": 1800,
    "auctionExtensionSeconds": 120,
    "auctionFirstCallSeconds": 15,
    "auctionSecondCallSeconds": 15,
    "auctionThirdCallSeconds": 15,
    "subscriberJoinGraceSeconds": 0,
    "allowStaffOfflineBids": true,
    "prebidMutabilityPolicy": "MUTABLE_UNTIL_CLOSE",
    "auctionJoiningRule": "BEFORE_START"
  },
  "allowedSecurities": ["GOLD_ORNAMENTS"],
  "triggerPolicy": {
    "autoStart": false,
    "approvalRequired": false,
    "autoOpenPrebid": false,
    "autoRevealPrebids": false,
    "autoDeclareWinner": false
  },
  "provenance": {
    "hasPrebid": "company",
    "auctionBidMode": "default",
    "auctionClosingMode": "default",
    "auctionDurationSeconds": "company",
    "auctionExtensionSeconds": "platform",
    "auctionFirstCallSeconds": "default",
    "auctionSecondCallSeconds": "default",
    "auctionThirdCallSeconds": "default",
    "subscriberJoinGraceSeconds": "default",
    "allowStaffOfflineBids": "default",
    "prebidMutabilityPolicy": "default",
    "auctionJoiningRule": "default",
    "allowedSecurities": "company",
    "autoStart": "default",
    "approvalRequired": "default",
    "autoOpenPrebid": "default",
    "autoRevealPrebids": "default",
    "autoDeclareWinner": "default"
  }
}

provenance maps every resolved key to its source (default, platform, or company) — use it to tell staff where a prefill value comes from. When no program/draft exists yet, this is the correct endpoint; once a draft program has an id, prefer 5.13's program-scoped sibling GET /v2/companies/programs/:programId/settings, which additionally folds the preset and program layers and surfaces programName plus the prebid document template when the program requires one.


6. Staff WebSocket Bid / Winner Commands

The live auction console acts over WebSocket (auction:staff:<auctionId> room) for fast actions. The same actions are available as HTTP console mutations above; the WebSocket variants are documented in §8.


7. Prebid Amount Visibility

Server-side logic always uses real prebid amounts, but client-facing responses redact them until the completed auction is revealed.

Before reveal:

  • Console prebids rows and winner candidates return amount: null when the amount is prebid-derived.
  • Subscribers can see their own activePrebid / latestPrebid amount.
  • leadingBid sourced from a prebid returns amount: null until a live bid replaces it.
  • Realtime auction.prebid.created is staff-only. Its amount is null while prebids are sealed; clients must still treat the field as nullable after reveal.
  • Subscriber-visible bid history omits prebid entries.

After reveal (prebidAmountsRevealed: true):

  • All auction payloads may include prebid-derived amounts.
  • The console reveals the amounts in the prebids list and winner payloads.

When hasPrebid is false, normal live-bid amount behavior is unchanged.


8. WebSocket Protocol

8.1 Connection

wss://api.example.com/ws

Authenticate per §1 Authentication. Both subscriber and staff roles share this endpoint; authorization happens per message.

8.2 Message envelope

Client → server:

{
  "id": "request-id",
  "type": "auction.subscribe",
  "version": "1.0",
  "source": "web-client",
  "timestamp": "2026-08-11T10:00:00.000Z",
  "data": {},
  "meta": { "traceId": "client-trace-id" }
}

Rules:

  • type is required and must be a registered event.
  • data is validated per type.
  • id is optional but recommended for correlating acks/errors.
  • version, source, timestamp, meta are informational.

Server → client frames add:

  • version — always "1.0".
  • sequence — monotonic counter per connection; a gap means frames were dropped → recover via snapshot + replay.
  • meta.traceId — echoes the client trace id when sent.

8.3 Query vs command

  • Sync query (e.g. auction.subscribe, auction.unsubscribe) returns a single ack frame with the handler result.
  • Async command (e.g. auction.bid.place, all staff commands) returns an immediate command.acknowledged, then business results arrive as pushed auction events or command result frames.

8.4 Subscribe (subscriber)

{
  "id": "subscribe-001",
  "type": "auction.subscribe",
  "data": {
    "auctionId": "auction-id",
    "enrolledSubscriberId": "enrolled-id"
  }
}

The server authorizes an active enrollment for viewer access, joins the auction:<auctionId> room, opens a per-connection audience session, and then sends, in order. Payment and an open join window are not required to watch.

Breaking change: auctionId is now required (the auction row is guaranteed before READY/LIVE). Fetch auctionId via REST (GET /v2/.../auctions/by-cycle/:cycleId or cycle overview) before subscribing.

auction.connected
auction.state.snapshot
auction.audience.snapshot

ack frame:

{
  "id": "subscribe-001",
  "type": "ack",
  "version": "1.0",
  "source": "dichit-backend",
  "timestamp": "2026-08-11T10:00:01.000Z",
  "sequence": 1,
  "data": {
    "eventType": "auction.subscribe",
    "auctionId": "auction-id",
    "cycleId": "cycle-id",
    "room": "auction:auction-id"
  },
  "meta": { "traceId": "client-trace-id" }
}

8.5 Subscribe (company / admin)

Staff omit enrolledSubscriberId:

{
  "id": "subscribe-001",
  "type": "auction.subscribe",
  "data": { "auctionId": "auction-id" }
}

Staff are additionally joined to auction:staff:<auctionId>, and the ack data includes staffRoom. Staff snapshots include the full room (all subscribers, bids, action logs, announcements).

8.6 Resume with replay

{
  "id": "subscribe-002",
  "type": "auction.subscribe",
  "data": {
    "auctionId": "auction-id",
    "enrolledSubscriberId": "enrolled-id",
    "lastSequence": 42
  }
}

lastSequence is the auction-level high-water cursor from the last processed durable data.serverSequence (bids, lifecycle, join-window, participation, prebid, and winner events as permitted for the caller). Replay is role-, scope-, and target-filtered, so visible sequence values can be sparse. When replay data is available it is merged into the auction.state.snapshot payload under a replay key; advance to replay.lastSequence even when no visible event uses that exact sequence.

8.7 Initial events

auction.connected:

{
  "type": "auction.connected",
  "source": "auction-service",
  "timestamp": "2026-08-11T10:00:01.000Z",
  "data": {
    "auctionId": "auction-id",
    "cycleId": "cycle-id",
    "stateVersion": 7,
    "payload": {
      "connectionId": "conn-id",
      "heartbeatIntervalMs": 30000
    }
  }
}

auction.state.snapshot — the payload is the full auction state:

  • Subscriber: { auction, currentUser, viewerCount, joinedParticipantCount, onlineParticipantCount, bidderCount, recentBids, lastSequence }
  • Staff: { auction, allSubscribers, onlineSubscribers, viewerCount, joinedParticipantCount, onlineParticipantCount, bidderCount, recentBids, actionLogs, announcements, lastSequence }

auction.audience.snapshot:

{
  "type": "auction.audience.snapshot",
  "data": {
    "auctionId": "auction-id",
    "cycleId": "cycle-id",
    "payload": {
      "viewerCount": 4,
      "joinedParticipantCount": 3,
      "onlineParticipantCount": 2,
      "bidderCount": 1
    }
  }
}

8.8 Client → server commands

Subscriber commands:

Join an auction after payment while the join window is open:

{
  "id": "join-001",
  "type": "auction.participation.join",
  "data": {
    "auctionId": "auction-id",
    "enrolledSubscriberId": "enrolled-id"
  }
}

The frame id is required and is the idempotency key. A successful terminal ack returns accepted or replayed, participantId, joinedAt, and joinWindowVersion. Once admitted, the subscriber may bid until the auction ends, including after the join window closes and after reconnecting.

Place a bid after admission:

{
  "id": "bid-001",
  "type": "auction.bid.place",
  "data": {
    "auctionId": "auction-id",
    "enrolledSubscriberId": "enrolled-id",
    "amountMinor": "2500000"
  }
}
  • amountMinor is required and is always a positive integer string in minor currency units. Never send floating-point money.
  • The WebSocket frame id is the bid command id. Reuse the same id when retrying the same bid; retries return the original result and do not create duplicate bids.
  • The payload is strict. Do not send client timestamps, auction versions, current bid, previous bid, or ordering state.
  • The response is terminal: ack.data.status is accepted or replayed. Rejections use the correlated error envelope.
  • Rate limit: 100 messages / 60 s for auction.bid.place.
  • Subscriber self-bids become origin: "ONLINE". Staff/floor bids use the same auction.bid.place command with a target enrolledSubscriberId; the server derives origin: "FLOOR" from the authenticated actor and persists the actual staff placedByUserId.
{
  "id": "unsubscribe-001",
  "type": "auction.unsubscribe",
  "data": { "auctionId": "auction-id" }
}

ack data: { eventType: "auction.unsubscribe", auctionId, unsubscribed: true }. Unsubscribing removes the room membership and closes that connection's audience session with disconnectReason: "UNSUBSCRIBE". Durable participation remains.

Staff commands (all permissions: ["auction:staff"], all async):

Type Payload
auction.status.update { auctionId, status: "START" }
auction.pause { auctionId, reason }
auction.resume { auctionId, reason }
auction.end { auctionId, reason }
auction.bid.mark { auctionId, action: "DELETE_BID" \| "DISQUALIFY_BIDDER", bidId?, enrolledSubscriberId?, reason, reasonCode? }
auction.winner.declare { auctionId, mode: "CANDATE" \| "MANUAL", bidId?, prebidId?, enrolledSubscriberId?, amount?, reason? }
auction.winner.record_lot { auctionId, winnerEnrolledSubscriberId, candidateEnrolledSubscriberIds: [≥2], reason? }
auction.announcement.create { auctionId, message, tone: "INFO" \| "WARNING" }
auction.presence.floor.update { auctionId, enrolledSubscriberId, present: boolean }

auction.bid.mark action mapping:

  • DELETE_BID → requires bidId.
  • DISQUALIFY_BIDDER → requires enrolledSubscriberId + reasonCode.

auction.winner.declare mapping:

  • CANDIDATE → declare from an existing bid/prebid (bidId / prebidId).
  • MANUAL → requires enrolledSubscriberId + amount.

8.9 Bid terminal responses

auction.bid.place returns a terminal ack after commit (accepted or replayed) or a correlated error when rejected. Staff commands remain async and continue to use command.acknowledged plus domain events.

Bid rejection codes are machine-readable: AUCTION_NOT_LIVE, AUCTION_ENDED, INVALID_AMOUNT, BID_NOT_IMPROVING, DUPLICATE_COMMAND, and SUBSCRIBER_NOT_ELIGIBLE.

Successful bid broadcasts are authoritative for the shared feed. Reconcile local state by feed serverSequence; do not order bids by client timestamps or WebSocket receipt order.

8.10 Realtime events (server → client)

Events are delivered to the subscribed connection as:

{
  "id": "evt_01HQ5BY3Y7Z2V6Y0W5X0W5X0W5X",
  "type": "auction.bid.created",
  "version": "1.0",
  "source": "auction-service",
  "timestamp": "2026-08-11T10:05:00.000Z",
  "sequence": 7,
  "data": {
    "auctionId": "auction-id",
    "cycleId": "cycle-id",
    "stateVersion": 8,
    "serverSequence": 12,
    "payload": {}
  },
  "meta": { "traceId": "server-trace-id" }
}

Event catalog:

Event Payload / notes
auction.state.changed Durable canonical lifecycle delta. payload is { transition, state, winner?, declaredWinnerCount?, remainingWinnerSlots?, replacementRequired? }; replace the lifecycle slice from the complete state object.
auction.settings.updated Settings changed
auction.bid.created payload is the bid activity item: { id, auctionId, cycleId, subscriberProgramId, subscriberId, bidderName, bidderAvatarUrl, bidderCode, bidAmount, bidRank, isWinningBid, status, createdAt, serverSequence, origin } where status is ACCEPTED | OUTBID and origin is ONLINE | FLOOR | AUTO
auction.bid.updated same bid activity item shape (previous leading bid marked OUTBID)
auction.bid.deleted staff deleted a bid
auction.prebid.created Staff-only durable prebid projection: { id, subscriberId, enrolledSubscriberId, bidderName, amount, createdAt, status, documentSubmissionId }; amount is null while sealed.
auction.prebid.deleted prebid removed/cancelled
auction.announcement.created { id, message, tone, actorId, createdAt }
auction.announcement.updated —
auction.announcement.deleted —
auction.bidder.disqualified bidder disqualified (prebid or live phase)
auction.audience.changed Ephemeral public and staff copies contain aggregate audience counts plus the affected participant projection.
auction.join_window.opened Durable payload { stateVersion, joinWindow }; joinWindow contains status OPEN, version, rule, scheduled/actual opening, close, and null closedAt.
auction.join_window.closed Durable payload { stateVersion, joinWindow, reason }; joinWindow contains status CLOSED and all timestamps.
auction.participation.joined Staff-only durable event for an admitted online or floor participant.
auction.winner.changed Staff-only durable { action, winner, suggestedReplacementCandidate? } event for winner selection/disqualification.

Presence participant payload:

{
  "subscriberId": "subscriber-id",
  "enrolledSubscriberId": "enrolled-id",
  "name": "Subscriber One",
  "avatar": null,
  "lastSeenAt": "2026-08-11T10:05:01.000Z",
  "connectionCount": 2,
  "source": "ONLINE"
}

Subscriber connections only receive events for their own room plus their own targeted events; staff connections receive the full room stream.

Subscriber audience events never expose identities. Durable participants come from AuctionParticipant; online/floor state is an ephemeral overlay. Multiple tabs create separate audit sessions but count once per enrollment.

8.11 Error handling

Dispatch, validation, or authorization failures return an error frame:

{
  "id": "bid-001",
  "type": "error",
  "version": "1.0",
  "source": "dichit-backend",
  "timestamp": "2026-08-11T10:05:00.000Z",
  "sequence": 6,
  "data": {
    "code": "FORBIDDEN",
    "message": "Only subscribers can place live auction bids."
  },
  "meta": { "traceId": "client-trace-id" }
}

Error codes: BAD_REQUEST, UNAUTHORIZED, FORBIDDEN, NOT_FOUND, CONFLICT, RATE_LIMITED, INTERNAL.

8.12 Rate limits

  • Default: 120 messages / 60 s per user + IP per event type.
  • auction.bid.place: 100 messages / 60 s.

Rate-limited messages receive an error frame with code: "RATE_LIMITED".

8.13 Reconnection

On socket close:

  1. Open a new /ws connection with a fresh access token.
  2. Re-send auction.subscribe with the last processed data.serverSequence.
  3. Rebuild UI from the latest auction.state.snapshot, apply visible replay events in ascending sequence, then advance to replay.lastSequence.

Do not treat serverSequence > lastSequence + 1 as proof of loss. Staff-only and target-user events consume sequence values that a subscriber is not allowed to receive.


9. Frontend Screen Mapping

Screen Data source
My auctions list GET /v2/subscribers/me/auctions
Auction detail / lobby GET /v2/subscribers/me/auctions/:auctionId
Prebid form Auction detail (§4.3) + GET /v2/common/templates/versions/:templateVersionId
Prebid form by template version GET /v2/common/templates/versions/:templateVersionId
Place / edit / cancel prebid POST / PUT / DELETE /v2/subscribers/me/auctions/:auctionId/prebid…
Live room (subscriber) GET /v2/subscribers/me/cycles/:cycleId/auction/:enrolledSubscriberId + WebSocket
Live room (company/admin console) GET /v2/companies\|admin/auctions/:auctionId + WebSocket
Winner / review screens console endpoints in §5
Reveal prebids POST .../auctions/:auctionId/prebids/reveal

Recommended realtime flow:

  1. Open /ws with a valid access token.
  2. auction.subscribe for the active cycle.
  3. Render auction.state.snapshot + auction.audience.snapshot.
  4. If currentUser.canJoin, send auction.participation.join after the user chooses to join.
  5. Send auction.bid.place only when currentUser.canBid; staff send staff commands.
  6. Apply pushed events and deduplicate durable events by event ID and serverSequence.
  7. auction.unsubscribe when leaving the screen.
  8. On network loss, reconnect and resubscribe with lastSequence.

10. Migration Notes (from earlier versions)

  • Subscriber auction detail now returns audience: null until the join window opens. Afterward, counts are visible to enrolled subscribers and the paginated participant roster is visible only to subscribers who joined.
  • Staff auction participants changed from a plain array to a paginated object { count, pageNumber, pageSize, totalPages, hasPreviousPage, hasNextPage, items }.
  • Console winner payloads: the old currentWinner + declaredWinners fields were replaced by a single winners array that is only populated when the auction has ended.
  • realtimeStats is null before the live phase (previously an all-zeros object).
  • Prebid reveal endpoints moved from /cycles/:cycleId/auction/prebids/reveal to /auctions/:auctionId/prebids/reveal (company and admin mounts).
  • Cycle lists (subscriber and company) now include auctionId per cycle.
  • Settings now include prebidMutabilityPolicy (IMMUTABLE_CANCEL_ONLY | MUTABLE_UNTIL_CLOSE).