Dichit WebSocket API¶
The Dichit real-time API delivers live auction data, presence, notifications, and staff controls over a single authenticated WebSocket connection. Subscribers, companies, auctioneers, and administrators all use the same endpoint; the server derives each connection's identity, role, and permissions from the JWT presented during the handshake.
This documentation is the authoritative contract for the real-time API. It is written for frontend engineers, backend engineers, mobile developers, QA engineers, and third-party integrators.
Overview¶
The real-time API is a request/response protocol over WebSocket (RFC 6455) with a server-pushed event stream. Clients send JSON messages inside a common envelope, the server validates and authorizes each message, and responds with an acknowledgement (ack) or an error. State changes (new bids, auction state transitions, presence transitions) are pushed to clients asynchronously.
Key properties:
- One endpoint for every role.
- JWT authentication at connection time.
- Permission-based, message-level authorization.
- Room-based fan-out backed by Redis Pub/Sub, so any WebSocket server instance can deliver to any client.
- Server-driven event log with sequence numbers, enabling snapshot + replay recovery after reconnection.
Endpoint¶
All roles connect to a single WebSocket endpoint:
Production: wss://api.example.com/ws
Staging: wss://api.staging.example.com/ws
Local dev: ws://localhost:3500/ws
There are no role-specific endpoints. Requesting a path other than /ws is not supported. See connection.md.
Supported protocol¶
- Transport: WebSocket (RFC 6455) over TLS (
wss://). Plainws://is allowed only for local development. - Subprotocols:
websocket.v1— current protocol version (use this).auction-room.v1— legacy, accepted for backward compatibility.bearer.<access-token>— subprotocol used to carry the JWT when a customAuthorizationheader cannot be set (for example, in browsers).- Framing: JSON text frames. Binary frames are not supported.
- The
Sec-WebSocket-Protocolheader may carrywebsocket.v1, bearer.<token>.
See connection.md and versioning.md.
Authentication¶
Authentication happens during the WebSocket handshake, before any message is processed. An access token (JWT, type: access) is required for every connection. Clients present the token either as a standard HTTP header or as a WebSocket subprotocol:
or
Invalid, expired, or missing tokens close the connection with close code 1008 and reason Authentication failed.
Roles are derived from the token claim:
| Role | Description | Key permissions |
|---|---|---|
SUBSCRIBER | Individual auction participant | auction:subscribe, auction:bid:place, room:join, room:leave |
COMPANY | Company user / auctioneer staff | auction:subscribe, auction:staff, broadcast:receive, room:join, room:leave |
SUPERADMIN | Platform administrator | auction:subscribe, auction:staff, broadcast:receive, room:join, room:leave |
See authentication.md.
Message format¶
Every client-to-server message uses the same envelope:
{
"type": "auction.bid.place",
"requestId": "req_01HQ5BXWYP1Y5RX0W5X0W5X0W5X",
"timestamp": "2026-08-03T10:00:00.000Z",
"data": {
"cycleId": "cyc_01HQ5BXWYP1Y5RX0W5X0W5X0W5X",
"amount": "25000",
"idempotencyKey": "bid_req_01HQ5BY3K7Z2Z6Y0W5X0W5X0W5X"
}
}
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | Dot-separated event name, e.g. auction.bid.place. 1–128 chars. |
requestId | string | Yes (recommended) | Client-generated identifier echoed back in acknowledgements and errors. 1–128 chars. |
timestamp | string | Optional | Client-side ISO-8601 timestamp. Server does not trust it for ordering. |
data | object | Depends | Event payload, validated against the per-event Zod schema. |
Server responses come in two shapes, acknowledgements and errors:
{
"type": "ack",
"requestId": "req_01HQ5BXWYP1Y5RX0W5X0W5X0W5X",
"eventType": "auction.bid.place",
"data": {
"auctionId": "auc_01HQ5BXWYP1Y5RX0W5X0W5X0W5X",
"cycleId": "cyc_01HQ5BXWYP1Y5RX0W5X0W5X0W5X",
"bidId": "bid_01HQ5BY3K7Z2Z6Y0W5X0W5X0W5X",
"amount": 25000,
"stateVersion": 7,
"idempotencyKey": "bid_req_01HQ5BY3K7Z2Z6Y0W5X0W5X0W5X",
"wasReplayed": false
}
}
{
"type": "error",
"requestId": "req_01HQ5BXWYP1Y5RX0W5X0W5X0W5X",
"code": "FORBIDDEN",
"message": "You are not authorized to perform this WebSocket action."
}
Server-pushed events (bids, presence, auction state) use the same type / requestId / data shape; the type is the canonical event name such as bid.created.
See protocol.md for the full contract and errors.md for all error codes.
Rooms¶
State is distributed through named rooms. Clients join rooms they are allowed to see, and the server publishes updates to a room exactly once, regardless of how many WebSocket servers are running:
| Room | Purpose |
|---|---|
auction:<cycleId> | Live auction state, bids, and presence |
company:<companyId> | Company-scoped staff updates |
user:<userId> | Private updates for a single user |
admins | Platform-wide administrative broadcasts |
notifications | User notifications |
Room membership is per-connection and cleared automatically when a connection closes. See rooms.md.
Documentation index¶
Getting started¶
| Document | Content |
|---|---|
| protocol.md | Message envelope, request/response model, event naming, client/server events |
| connection.md | Endpoint, TLS, reconnection, heartbeats, timeouts, message size |
| authentication.md | JWT flow, token expiration, re-authentication, roles and permissions |
| rooms.md | Room architecture, membership rules, lifetimes |
Events¶
| Document | Content |
|---|---|
| events/system.md | system.ping, system.pong |
| events/auth.md | auth.login, auth.logout |
| events/auction.md | auction.subscribe, auction.unsubscribe, auction.bid.place, auction.bid.cancel, auction.started, auction.updated, auction.ended, auction.bid.created, staff commands, server events |
| events/company.md | Company-scoped events and the company:{companyId} room |
| events/presence.md | presence.joined, presence.left, presence.update, presence.changed |
| events/notification.md | notification.created, notification.read |
| events/chat.md | chat.send, chat.typing |
Reference¶
| Document | Content |
|---|---|
| errors.md | Error codes, HTTP equivalents, retryability, examples |
| rate-limits.md | Per-event limits and server behaviour when exceeded |
| lifecycle.md | Full connection lifecycle: connect → auth → join → updates → heartbeat → disconnect → reconnect |
| versioning.md | Protocol versioning, compatibility, deprecation policy |
| diagrams.md | Mermaid diagrams for connection, auth, bidding, broadcast, Redis Pub/Sub, scaling, rooms, routing, and authorization |
Implementation status¶
The following events are part of the documented contract. The current server build marks events as Implemented (registered socket routes) or Planned (contract defined, route not yet registered). Integrators should gate on the Implemented set; Planned events are documented so contracts evolve in a backward-compatible way.
| Domain | Implemented | Planned |
|---|---|---|
| System | system.ping | system.pong is the response shape |
| Rooms | room.join, room.leave | — |
| Auction (client) | auction.subscribe, auction.unsubscribe, auction.bid.place, auction.status.update, auction.pause, auction.resume, auction.end, bid.mark, winner.declare, winner.record_lot | auction.bid.cancel |
| Auction (server) | auction.connected, auction.snapshot, presence.snapshot, auction.started, auction.paused, auction.resumed, auction.extended, auction.call_started, auction.closed, auction.winner_selected, auction.state_refreshed, auction.status_changed, bid.created, bid.updated, bid.rejected, bid.deleted, prebid.deleted, bidder.disqualified, presence.joined, presence.left, presence.changed | auction.updated, auction.ended, auction.bid.created (documented aliases of canonical events) |
| Auth (in-band) | — | auth.login, auth.logout (authentication is performed at the handshake) |
| Presence (client) | — | presence.update (presence is server-managed) |
| Notification | — | notification.created, notification.read |
| Chat | — | chat.send, chat.typing |
Each event page in events/ states its implementation status and, where names differ from the canonical server event, the mapping in Notes.
Related platform documentation¶
- WebSocket infrastructure — internal implementation walkthrough (source:
src/interfaces/websocket,src/infrastructure/websocket). - Auction room frontend integration — client wiring guide for the auction room.