Chat Events¶
Chat events provide real-time messaging between auction participants and staff during a live auction. Both events below are planned in the current server build; the socket chat.send and chat.typing contracts are part of the documented protocol but no route is registered yet.
Reference: rooms.md · errors.md · rate-limits.md
Event list¶
| Event | Direction | Status |
|---|---|---|
chat.send | Client → Server | Planned |
chat.typing | Client → Server | Planned |
Chat is delivered within a room (auction:<cycleId> by default). The server validates message size and rate, persists (when enabled), and rebroadcasts the message to every other member of the room.
chat.send¶
Description¶
Sends a chat message to the auction room. The server records the message and emits it to all other room members. The sender does not receive its own message back (the acknowledgement confirms delivery).
Direction¶
Client → Server
Roles Allowed¶
All roles subscribed to the auction (participants and staff).
Permissions Required¶
chat:send (planned).
Request Schema¶
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | chat.send |
data.cycleId | string | Yes | Auction cycle to which the message belongs. |
data.body | string | Yes | Message text, trimmed, max 2000 chars. |
data.clientMessageId | string | Yes | Client-generated id for idempotency and echo control. |
Response Schema¶
| Field | Type | Description |
|---|---|---|
messageId | string | Server-assigned message id. |
clientMessageId | string | Echoes the request's id. |
createdAt | string | ISO-8601 server timestamp. |
Success Response¶
{
"type": "ack",
"requestId": "req_01HQ5BXWYP1Y5RX0W5X0W5X0W5X",
"eventType": "chat.send",
"data": {
"messageId": "msg_01HQ5BYN1K7ZRX0W5X0W5X0W5X",
"clientMessageId": "msg_cl_01HQ5BYN1K7",
"createdAt": "2026-08-03T10:00:00.000Z"
}
}
Error Responses¶
| Code | Description |
|---|---|
FORBIDDEN | Caller not in the auction room or lacks chat:send. |
NOT_FOUND | Auction/cycle not found or not subscribed. |
BAD_REQUEST | body empty/too long, cycleId missing, clientMessageId missing. |
RATE_LIMITED | Chat rate limit exceeded (see rate-limits.md). |
Validation Rules¶
| Rule | Behaviour |
|---|---|
cycleId non-empty string | Required. |
body trimmed, 1–2000 chars | Required. |
clientMessageId non-empty string | Required for idempotency. |
Duplicate clientMessageId in window | Returns previous ack (idempotent). |
Example Request¶
{
"type": "chat.send",
"requestId": "req_01HQ5BXWYP1Y5RX0W5X0W5X0W5X",
"data": {
"cycleId": "cyc_01HQ5BWN3F9P5RX0W5X0W5X0W5X",
"body": "Best of luck, everyone!",
"clientMessageId": "msg_cl_1HQ5KYP1K7"
}
}
Example Response¶
{
"type": "ack",
"requestId": "req_01HQ5BXWYP1Y5RX0W5X0W5X0W5X",
"eventType": "chat.send",
"data": {
"messageId": "msg_01HQ5BY2K7K21X210W5X0W5X0W5X",
"clientMessageId": "msg_cl_1HQ5KYP1K7",
"createdAt": "2026-08-03T10:00:00.000Z"
}
}
Broadcast Behaviour¶
After a successful chat.send, the server pushes the message to every other member of the auction:<cycleId> room (excluding the sender) with type chat.created (planned) and the full message payload. The same clientMessageId is echoed so clients can reconcile order of UI with the ack.
Related Events¶
chat.typing- events/auction.md — room membership via
auction.subscribe.
Notes¶
- Implementation status: Planned.
- Messages are tied to the auction room; joining requires
auction.subscribe/room.joinwith the samecycleId.
Best Practices¶
- Send
clientMessageIdto make retries safe. - Charge
chat.sendrate limit per user + per IP (see rate-limits.md).
chat.typing¶
Description¶
A lightweight typing indicator pushed to the room. Typing events are transient, short-lived, and rate-limited aggressively. They are not persisted.
Direction¶
Client → Server
Roles Allowed¶
All roles subscribed to the auction.
Permissions Required¶
chat:typing (planned).
Request Schema¶
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | chat.typing |
data.cycleId | string | Yes | Auction cycle. |
data.isTyping | boolean | Yes | true to start, false to stop. |
Response (ack)¶
{
"type": "ack",
"requestId": "req_01HQ5BXWYP1Y5RX0W5X0W5X0W5X",
"eventType": "chat.typing",
"data": {
"cycleId": "cyc_01HQ5BWN3F5RX0W6X0W5X0W5X",
"isTyping": true
}
}
Validation Rules¶
| Rule | Behaviour |
|---|---|
cycleId non-empty | Required. |
isTyping boolean | Required. |
Example Request¶
{
"type": "chat.typing",
"requestId": "req_01HQ5HXWYP1Y5RX0W5X0W5X0W5X",
"data": { "cycleId": "cyc_01HQ5BWN3F5RX0W5X0W5X0W5X", "isTyping": true }
}
Broadcast Behaviour¶
Fanned out to the room as chat.typing with the sender identity, throttled server-side to avoid flooding.
Related Events¶
chat.send
Notes¶
- Implementation status: Planned.
- Never block actual sending on a typing indicator; it is best-effort and can be dropped under load.
Best Practices¶
- Coalesce typing events client-side (at most one every few hundred ms).
- Stop the indicator when the message is sent or a timeout elapses.
Example broadcast for a chat message¶
Recipients (other room members) receive a server-push message:
{
"type": "chat.send",
"data": {
"messageId": "msg_01HQ5BY2K7K2RY210W5X0W5X0W5X",
"cycleId": "cyc_01HQ5BWN3F5P5RX0W5X0W5X0W5X",
"clientMessageId": "msg_cl_1HQ5KYP1K7",
"author": {
"userId": "sub_01HQ5BWYP1Y5RX0W5X0W5X0W5X",
"name": "Annie Mohan"
},
"body": "Best of luck, everyone!",
"createdAt": "2026-08-03T10:00:00.000Z"
}
}
Related documents¶
- rate-limits.md —
chat.send30/min,chat.typingthrottled. - rooms.md —
auction:<cycleId>room. - errors.md — error codes.