KT KamTeswa APIDeveloper workspace
Realtime tool ← Swagger UI
Realtime developer tool

Chat Socket.IO Playground

Connect as a test user, join a conversation, emit chat events, and inspect every live server response from one focused workspace.

3 client events 7 server events No acknowledgements Text messages · 4000 max
Live session

Client ↔ Provider chat lab

Two isolated Socket.IO connections show the complete realtime cycle from both sides.

0 / 2 connected Add both user IDs to begin
01

Shared connection settings

Both actors use the same host on the fixed Socket.IO port 30123.

CL Client sessionCustomer-side Socket.IO connection Disconnected
Locked actor typeclient
PR Provider sessionProvider-side Socket.IO connection Disconnected
Locked actor typeprovider
chat:enter · chat:exit

Room lifecycle

Client and Provider enter the same existing chat using chatId only.

Waiting for chatId

02 · Client starts the conversation

Enter the existing chatId. The tester copies it to the Provider side automatically.

03 · Provider joins the resolved room

The Provider chatId is synchronized from the Client field and confirmed by chat:participant-joined.

04 · Realtime chat view

Message exchange

Outgoing messages appear immediately as pending, then show the measured latency when the server broadcasts them.

server event: chat:message-received
FCM testSend while the receiver is outside the room. FCM uses that account's device token already stored by sign-in; the generated Socket deviceId above is only a required handshake value.
CL Client viewNot in room received · 0
Push notification testNo server result
Instant pending · confirmed by message-received
PR Provider viewNot in room received · 0
Push notification testNo server result
Instant pending · confirmed by message-received
Contract reference

Event payloads and server behavior

Use this section when you need exact fields, validation rules, or broadcast targets.

Connection

Connect to the API host on fixed port 30123 using Socket.IO path /socket.io/.

const socketOrigin = new URL(baseOrigin);
socketOrigin.port = "30123";

const socket = io(socketOrigin.origin, {
  path: "/socket.io/",
  query: {
    userId: "665f1c2a9b4e1d0012ab34b2",
    lang: "ar",
    userType: "client",
    deviceType: "web",
    deviceId: "browser-session-id"
  }
});
Handshake fieldRules
userIdRequired Mongo ObjectId
langar or en
userTypeadmin, client, store, haraj, or provider
deviceTypeios, android, or web
deviceIdRequired non-empty identifier

The server takes user identity from the validated connection query and checks chat membership. Do not send identity fields as authority inside event payloads.

Success event:

connected
{ "userId": "...", "deviceId": "...", "deviceType": "web" }

An invalid handshake currently emits auction:error with { "message": "..." } and registers no chat handlers.

Client → server

chat:enter

{ "chatId": "665f1c2a9b4e1d0012ab34c1" }

// Or find/create a direct chat:
{ "receiverId": "665f1c2a9b4e1d0012ab34b1" }
  • Send chatId or receiverId; chatId wins when both exist.
  • The selected value must be a Mongo ObjectId. When both fields are sent, receiverId is ignored and only chatId is validated.
  • Existing chat access is member-checked. Direct receiver mode finds or creates a 1:1 chat.
  • Success broadcasts chat:participant-joined to the room, including the joining socket.
{
  "chatId": "...",
  "targetId": null,
  "type": null,
  "totalParticipants": 1,
  "user": { "id": "...", "name": "Example user", "userType": "client" }
}

chat:message

{ "chatId": "665f1c2a9b4e1d0012ab34c1", "message": "Hello" }
  • The socket must enter the room first.
  • The message is trimmed, required, text-only, and limited to 4000 characters.
  • The Socket server rejects Western, Arabic-Indic, or Persian digits through chat:error before persistence.
  • Success broadcasts chat:message-received in the standard response envelope.
{
  "key": "success",
  "message": "Success",
  "status": 200,
  "data": {
    "id": "...",
    "type": "text",
    "message": "Hello",
    "senderPath": "client",
    "senderId": "...",
    "senderName": "Example user",
    "senderAvatar": "https://example.test/avatar.png",
    "date": "a few seconds ago",
    "chatId": "...",
    "direction": "left"
  }
}

chat:exit

{ "chatId": "665f1c2a9b4e1d0012ab34c1" }

The user must be a member and the socket must be inside the room. Success broadcasts chat:participant-left to the other room sockets and then leaves the room.

Server → client

EventRecipient and payload
connectedConnecting socket: userId, deviceId, deviceType
chat:participant-joinedRoom: chatId, targetId, type, totalParticipants, user
chat:message-receivedRoom: ApiResponse envelope with the message DTO
chat:notification-statusSender: server-side FCM acceptance summary; accepted is not a device delivery receipt
chat:participant-leftOther room sockets after explicit exit
chat:participants-updatedRemaining sockets after disconnect: chatId, totalParticipants
chat:errorEmitting socket: localized message only
auction:errorConnecting socket when the shared handshake is invalid

Error and acknowledgement behavior

Chat events currently have no acknowledgement callbacks. chat:error has no stable code or status:

{ "message": "Join the chat room before sending messages." }

HTTP boundary

  • GET /api/chats — list chats.
  • GET /api/chat/messages — paginated history.
  • POST /api/chat/upload — image upload.

The image upload endpoint returns a URL, but the current Socket.IO message handler accepts text only. There is no implemented chat:image event.

Client flow

  1. Connect and wait for connected.
  2. Register all server listeners.
  3. Emit chat:enter and read the resolved chatId from chat:participant-joined.
  4. Emit chat:message only after entering.
  5. Use the HTTP messages endpoint for history.
  6. Emit chat:exit when leaving the screen.
  7. After reconnect, enter the room again before sending.

Repository source: docs/CHAT_SOCKET_EVENTS.md.