OpenAPI 3.0.3 + Socket.io v4|Formalized Response Schemas

Chatterbox API Reference

Complete, tested documentation for the Chatterbox real-time messaging engine. Featuring formalized request & response models, copyable multi-language snippets, live testing consoles, and WebSocket protocol definitions.

Base URL:https://frontend-task-chatapp.onrender.com/api
Socket Host:https://frontend-task-chatapp.onrender.com
Original Swagger UI
Interactive Auth Token:

REST API Endpoints

13 endpoints
POST
/auth/login
Public
Auth

Log in or Auto-Register

Single-step authentication. If the phone number exists, generates a JWT session token. If the phone number is new, automatically registers the user account.

Request Body (application/json)
FieldTypeRequiredDescription
phonestringYesE.164 formatted or raw phone string
namestringYesDisplay name for profile & messages
Formalized Response Schemas

Successfully authenticated. Returns JWT token and User entity.

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": {
    "_id": "6a886007e5d6aac9752288cb",
    "name": "Alice Developer",
    "phone": "+19991234567",
    "createdAt": "2026-08-21T14:26:15.688Z"
  }
}
curl -X POST "https://frontend-task-chatapp.onrender.com/api/auth/login" \
  -H "Content-Type: application/json" \
  -d '{ "phone": "+19991234567", "name": "Alice Developer" }'
Live Backend Testing
GET
/auth/me
JWT Bearer
Auth

Get Current User Profile

Retrieves profile metadata for the active user matching the Bearer JWT token.

Formalized Response Schemas

Active user profile details

{
  "_id": "6a886007e5d6aac9752288cb",
  "name": "Alice Developer",
  "phone": "+19991234567",
  "createdAt": "2026-08-21T14:26:15.688Z"
}
curl -X GET "https://frontend-task-chatapp.onrender.com/api/auth/me" \
  -H "Authorization: Bearer <YOUR_JWT_TOKEN>"
Live Backend Testing
GET
/conversations
JWT Bearer
Conversations

List All Conversations

Returns all 1:1 direct and group conversations for the authenticated user, ordered chronologically by last activity.

Formalized Response Schemas

List of conversations wrapped in data array

{
  "data": [
    {
      "_id": "6a886020e5d6aac9752289b2",
      "type": "direct",
      "participant": {
        "_id": "6a88601ee5d6aac97522899c",
        "name": "Bob Test",
        "phone": "+1888489938"
      },
      "lastMessage": {
        "text": "Hello Bob! How are you?",
        "sender": "6a88601de5d6aac975228994",
        "createdAt": "2026-08-21T14:26:41.507Z"
      },
      "updatedAt": "2026-08-21T14:26:41.741Z"
    },
    {
      "_id": "6a886063e5d6aac975228b0f",
      "type": "group",
      "name": "Avengers Elite",
      "createdBy": "6a886060e5d6aac975228afa",
      "admins": [
        "6a886060e5d6aac975228afa"
      ],
      "participants": [
        {
          "_id": "6a886060e5d6aac975228afa",
          "name": "Alice",
          "phone": "+1999901945"
        },
        {
          "_id": "6a886060e5d6aac975228aff",
          "name": "Bob",
          "phone": "+1888628604"
        }
      ],
      "lastMessage": {
        "text": "Avengers Assemble!",
        "sender": "6a886060e5d6aac975228afa",
        "createdAt": "2026-08-21T14:27:48.632Z"
      },
      "createdAt": "2026-08-21T14:27:47.444Z",
      "updatedAt": "2026-08-21T14:27:50.778Z"
    }
  ]
}
curl -X GET "https://frontend-task-chatapp.onrender.com/api/conversations" \
  -H "Authorization: Bearer <YOUR_JWT_TOKEN>"
Live Backend Testing
POST
/conversations
JWT Bearer
Conversations

Start Direct 1:1 Conversation

Creates a new direct chat or returns the existing conversation ID if one already exists with the recipient.

Request Body (application/json)
FieldTypeRequiredDescription
userIdstringYesTarget recipient user ID
Formalized Response Schemas

Existing conversation returned

{
  "_id": "6a886020e5d6aac9752289b2",
  "participants": [
    "6a88601de5d6aac975228994",
    "6a88601ee5d6aac97522899c"
  ],
  "createdAt": "2026-08-21T14:26:40.553Z"
}
curl -X POST "https://frontend-task-chatapp.onrender.com/api/conversations" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <YOUR_JWT_TOKEN>" \
  -d '{ "userId": "6a88601ee5d6aac97522899c" }'
Live Backend Testing
POST
/conversations/group
JWT Bearer
Groups

Create Group Conversation

Creates a multi-participant group. Requires a group name and at least 2 member IDs (3+ total members including creator).

Request Body (application/json)
FieldTypeRequiredDescription
namestringYesGroup title
participantIdsstring[]YesArray of at least 2 user IDs
Formalized Response Schemas

Group created successfully

{
  "_id": "6a886063e5d6aac975228b0f",
  "type": "group",
  "name": "Avengers Core",
  "createdBy": "6a886060e5d6aac975228afa",
  "admins": [
    "6a886060e5d6aac975228afa"
  ],
  "participants": [
    {
      "_id": "6a886060e5d6aac975228afa",
      "name": "Alice",
      "phone": "+1999901945"
    },
    {
      "_id": "6a886060e5d6aac975228aff",
      "name": "Bob",
      "phone": "+1888628604"
    },
    {
      "_id": "6a886061e5d6aac975228b05",
      "name": "Charlie",
      "phone": "+1777335673"
    }
  ],
  "createdAt": "2026-08-21T14:27:47.444Z",
  "updatedAt": "2026-08-21T14:27:47.444Z"
}
curl -X POST "https://frontend-task-chatapp.onrender.com/api/conversations/group" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <YOUR_JWT_TOKEN>" \
  -d '{ "name": "Avengers Core", "participantIds": [ "6a886060e5d6aac975228aff", "6a886061e5d6aac975228b05" ] }'
Live Backend Testing
PATCH
/conversations/{id}
JWT Bearer
Groups

Rename Group Conversation

Updates the title of a group conversation. Caller must be an admin of the group.

Parameters1 param
NameTypeInDescription
id*reqstringpathGroup conversation ID
Request Body (application/json)
FieldTypeRequiredDescription
namestringYesNew group title
Formalized Response Schemas

Group updated successfully

{
  "_id": "6a886063e5d6aac975228b0f",
  "type": "group",
  "name": "Avengers Elite Team",
  "updatedAt": "2026-08-21T14:30:10.123Z"
}
curl -X PATCH "https://frontend-task-chatapp.onrender.com/api/conversations/6a886063e5d6aac975228b0f" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <YOUR_JWT_TOKEN>" \
  -d '{ "name": "Avengers Elite Team" }'
Live Backend Testing
POST
/conversations/{id}/admins
JWT Bearer
Groups

Promote Member to Admin

Grants administrator privileges to an existing group participant. Requires admin authorization.

Parameters1 param
NameTypeInDescription
id*reqstringpathGroup conversation ID
Request Body (application/json)
FieldTypeRequiredDescription
userIdstringYesUser ID to promote
Formalized Response Schemas

Admin list updated

{
  "_id": "6a886063e5d6aac975228b0f",
  "admins": [
    "6a886060e5d6aac975228afa",
    "6a886060e5d6aac975228aff"
  ]
}
curl -X POST "https://frontend-task-chatapp.onrender.com/api/conversations/6a886063e5d6aac975228b0f/admins" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <YOUR_JWT_TOKEN>" \
  -d '{ "userId": "6a886060e5d6aac975228aff" }'
Live Backend Testing
POST
/conversations/{id}/participants
JWT Bearer
Groups

Add Participants to Group

Appends one or more user IDs to the group membership list. Requires admin authorization.

Parameters1 param
NameTypeInDescription
id*reqstringpathGroup conversation ID
Request Body (application/json)
FieldTypeRequiredDescription
userIdsstring[]YesArray of user IDs to add
Formalized Response Schemas

Participants added

{
  "_id": "6a886063e5d6aac975228b0f",
  "participants": [
    {
      "_id": "6a886060e5d6aac975228afa",
      "name": "Alice",
      "phone": "+1999901945"
    },
    {
      "_id": "6a886061e5d6aac975228b05",
      "name": "Charlie",
      "phone": "+1777335673"
    }
  ]
}
curl -X POST "https://frontend-task-chatapp.onrender.com/api/conversations/6a886063e5d6aac975228b0f/participants" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <YOUR_JWT_TOKEN>" \
  -d '{ "userIds": [ "6a886061e5d6aac975228b05" ] }'
Live Backend Testing
DELETE
/conversations/{id}/participants/{userId}
JWT Bearer
Groups

Remove Member / Leave Group

Removes a specific user from the group. If userId matches the caller, the user leaves the group; otherwise requires admin role.

Parameters2 params
NameTypeInDescription
id*reqstringpathGroup conversation ID
userId*reqstringpathUser ID to remove or self-leave
Formalized Response Schemas

Participant removed or left successfully

{
  "_id": "6a886063e5d6aac975228b0f",
  "participants": [
    {
      "_id": "6a886060e5d6aac975228afa",
      "name": "Alice",
      "phone": "+1999901945"
    }
  ]
}
curl -X DELETE "https://frontend-task-chatapp.onrender.com/api/conversations/6a886063e5d6aac975228b0f/participants/6a886061e5d6aac975228b05" \
  -H "Authorization: Bearer <YOUR_JWT_TOKEN>"
Live Backend Testing
GET
/conversations/{id}/messages
JWT Bearer
Messages

Get Message History

Retrieves chronological messages for a conversation.

Parameters1 param
NameTypeInDescription
id*reqstringpathConversation ID
Formalized Response Schemas

List of messages and pagination flag

{
  "messages": [
    {
      "_id": "6a886021e5d6aac9752289be",
      "conversation": "6a886020e5d6aac9752289b2",
      "sender": "6a88601de5d6aac975228994",
      "text": "Hello Bob! How are you?",
      "createdAt": "2026-08-21T14:26:41.507Z"
    }
  ],
  "hasMore": false
}
curl -X GET "https://frontend-task-chatapp.onrender.com/api/conversations/6a886020e5d6aac9752289b2/messages" \
  -H "Authorization: Bearer <YOUR_JWT_TOKEN>"
Live Backend Testing
POST
/messages
JWT Bearer
Messages

Send Message

Dispatches a new text message. Reconciles with optimistic local state and triggers Socket.io broadcast to all participants.

Request Body (application/json)
FieldTypeRequiredDescription
conversationIdstringYesTarget conversation ID
textstringYesMessage body text
Formalized Response Schemas

Message persisted and broadcasted

{
  "_id": "6a886021e5d6aac9752289be",
  "conversation": "6a886020e5d6aac9752289b2",
  "sender": "6a88601de5d6aac975228994",
  "text": "Hello world!",
  "createdAt": "2026-08-21T14:26:41.507Z"
}
curl -X POST "https://frontend-task-chatapp.onrender.com/api/messages" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <YOUR_JWT_TOKEN>" \
  -d '{ "conversationId": "6a886020e5d6aac9752289b2", "text": "Hello world!" }'
Live Backend Testing
GET
/health
Public
System

Service Health Check

Health check endpoint hosted at server root /health.

Formalized Response Schemas

Server is healthy

{
  "status": "ok"
}
curl -X GET "https://frontend-task-chatapp.onrender.com/health"
Live Backend Testing

Real-Time Socket.io Protocol

WEBSOCKET
wss://frontend-task-chatapp.onrender.com (Socket.io v4)
Bi-Directional

Real-Time Socket.io Protocol Specification

Chatterbox pairs stateless HTTP REST mutations with a high-throughput persistent Socket.io connection at root origin. The server automatically routes messages to active participant rooms.

Payload Schema: message:newTriggered when a peer sends a message
{
  "id": "6a886064e5d6aac975228b1a",
  "conversation": "6a886063e5d6aac975228b0f",
  "sender": "6a886060e5d6aac975228afa",
  "text": "Avengers Assemble!",
  "createdAt": 1787322468632
}

Backend Nuance: Socket events transmit id (instead of _id) and createdAt: number (Unix ms). Chatterbox normalizes both at the store layer.

Empirically Verified Backend Quirks & Solutions

During integration testing against the Render backend, our team discovered several undocumented behaviors and payload discrepancies. Here is how Chatterbox handles them defensibly:

Socket Timestamp & Key Normalization

WebSocket message:new
REST endpoints return ISO strings (createdAt: "2026-08-21T...") and _id, whereas incoming Socket.io broadcasts emit Unix millisecond integers (createdAt: 1787322468632) and id.
The client normalizes all incoming socket messages at the Zustand store ingestion layer before sorting or rendering.
const normalized: Message = {
  _id: rawMessage._id || rawMessage.id,
  conversation: rawMessage.conversation,
  sender: typeof rawMessage.sender === 'object' ? rawMessage.sender?._id : rawMessage.sender,
  text: rawMessage.text,
  createdAt: typeof rawMessage.createdAt === 'number'
    ? new Date(rawMessage.createdAt).toISOString()
    : rawMessage.createdAt,
};

POST /conversations Minimal Shape

POST /conversations (Direct)
Creating or starting a direct chat returns a minimal object { _id, participants, createdAt } that lacks populated participant objects and type: "direct".
Client performs an immediate cache update and triggers a background query invalidation to fetch the fully populated conversation model.
// Reconcile and invalidate conversations list
queryClient.invalidateQueries({ queryKey: ['conversations', userId] });

Group Creation 3+ Member Validation

POST /conversations/group
Backend strictly expects { name: string, participantIds: string[] } and validates that at least 2 target IDs are provided (for a total of 3+ members including the creator). Passing { participants } fails.
The group creation modal enforces a minimum of 2 selected contacts before enabling the submit button, and maps IDs into participantIds.

Root Origin vs /api Separation

Socket.io Handshake
The REST API is scoped under https://frontend-task-chatapp.onrender.com/api, but the Socket.io WebSocket engine is bound to the root origin at /socket.io/. Attempting to connect to /api/socket.io fails.
Environment constants separate the REST base URL from the Socket root host origin.

User Search Self-Inclusion

GET /users/search
The search endpoint returns all matching users in the database, including the currently logged-in account.
The search UI automatically filters out the active user._id so users cannot start a 1:1 conversation with themselves.

TypeScript Shared Type Definitions

lib/types/index.ts

These core types represent the normalized state across both the REST persistence layer and the Socket.io live stream.

export interface User {
  _id: string;
  name: string;
  phone: string;
  createdAt?: string;
}

export interface DirectParticipant {
  _id: string;
  name: string;
  phone: string;
}

export interface Conversation {
  _id: string;
  type: 'direct' | 'group';
  name?: string;
  createdBy?: string;
  admins?: string[];
  participants?: DirectParticipant[] | string[];
  participant?: DirectParticipant;
  lastMessage?: {
    text: string;
    sender: string;
    createdAt: string;
  };
  createdAt?: string;
  updatedAt?: string;
}

export interface Message {
  _id: string;
  conversation: string;
  sender: string; // user ID
  text: string;
  createdAt: string;
  status?: 'sending' | 'sent' | 'failed';
  tempId?: string;
}