Relay Messenger API Documentation

Base URL

https://relay.plooza.io/api

Authentication

Include JWT token in Authorization header:

Authorization: Bearer <jwt_token>

🔐 Authentication

POST /auth/register

Register a new user

Request Body
{
  "username": "string (3-20 chars)",
  "firstName": "string (1-50 chars)",
  "lastName": "string (1-50 chars)", 
  "age": "number (13-120)",
  "bio": "string (optional, max 500 chars)",
  "password": "string (min 6 chars)"
}

POST /auth/login

Login user

Request Body
{
  "username": "string",
  "password": "string"
}

GET /auth/me

Get current user info (requires authentication)

👥 Users

GET /users/{id}

Get user profile by ID

PUT /users/me

Update current user profile

Request Body
{
  "firstName": "string (optional)",
  "lastName": "string (optional)",
  "bio": "string (optional)",
  "avatarUrl": "string (optional)"
}

GET /users/search?q=query

Search users by username, firstName, or lastName

💬 Chats

GET /chats

Get user's chats

POST /chats

Create or get existing chat with user

Request Body
{
  "userId": "string (cuid)"
}

GET /chats/{chatId}/messages

Get chat messages

Query params: limit (default: 50), offset (default: 0)

📨 Messages

POST /messages/send

Send a message

Request Body
{
  "chatId": "string (cuid)",
  "content": "string (1-4000 chars)",
  "attachments": ["fileId1", "fileId2"], // optional
  "replyToId": "string (cuid)" // optional
}

GET /messages/{messageId}

Get specific message by ID

POST /messages/{messageId}/reactions

Add reaction to message

Request Body
{
  "emoji": "string (emoji character)"
}

DELETE /messages/{messageId}/reactions/{reactionId}

Remove reaction from message

📞 Calls

POST /calls/initiate

Initiate a call

Request Body
{
  "chatId": "string (cuid)",
  "type": "audio" | "video"
}

POST /calls/{callId}/answer

Answer incoming call

POST /calls/{callId}/reject

Reject incoming call

POST /calls/{callId}/end

End active call

😊 Reactions

GET /reactions

Get available reaction emojis

GET /admin/reactions

Get all reactions (admin only)

🎵 Music

GET /music/all

Get all music files with metadata

POST /files/extract-metadata

Extract metadata from audio file

Request Body
{
  "fileId": "string (cuid)"
}

📁 Files

POST /files/upload

Upload a file

Content-Type: multipart/form-data

Form field: file

Max size: 100MB

Supported types: images, videos, audio, documents

GET /files/{fileId}

Download or stream file by ID

Returns file with appropriate Content-Type header

👨‍💼 Admin

POST /admin/login

Admin authentication

Request Body
{
  "username": "admin",
  "password": "admin123"
}

GET /admin/stats

Get system statistics

GET /admin/users

Get all users (admin only)

GET /admin/messages

Get all messages (admin only)

📡 WebSocket

URL: wss://relay.plooza.io/ws?token=YOUR_JWT_TOKEN

Authentication: Pass JWT token as query parameter

Events

Client → Server

// Authentication (alternative to query param)
{
  "type": "auth",
  "data": { "token": "jwt_token" }
}

// Send message
{
  "type": "message:send", 
  "data": { "chatId": "chat_id", "content": "message" }
}

// Typing indicators
{
  "type": "typing:start",
  "data": { "chatId": "chat_id" }
}

{
  "type": "typing:stop",
  "data": { "chatId": "chat_id" }
}

// Call signaling
{
  "type": "call:offer",
  "callId": "call_id",
  "offer": { /* RTCSessionDescription */ }
}

{
  "type": "call:answer",
  "callId": "call_id",
  "answer": { /* RTCSessionDescription */ }
}

{
  "type": "call:ice-candidate",
  "callId": "call_id",
  "candidate": { /* RTCIceCandidate */ }
}

Server → Client

// Authentication
{
  "type": "auth:success",
  "data": { "userId": "user_id", "username": "username" }
}

{
  "type": "auth:error",
  "data": { "message": "error_message" }
}

// Messages
{
  "type": "message:new",
  "data": { 
    "id": "msg_id", 
    "content": "message", 
    "sender": {...},
    "attachments": [...],
    "replyTo": {...}
  }
}

{
  "type": "message:status",
  "data": { 
    "messageId": "msg_id", 
    "status": "delivered" | "read",
    "chatId": "chat_id"
  }
}

// Reactions
{
  "type": "reaction:new",
  "data": { 
    "messageId": "msg_id",
    "chatId": "chat_id",
    "reaction": { "emoji": "👍", "userId": "user_id" }
  }
}

{
  "type": "reaction:removed",
  "data": { 
    "messageId": "msg_id",
    "chatId": "chat_id",
    "reactionId": "reaction_id"
  }
}

// Typing indicators  
{
  "type": "typing:start",
  "data": { "chatId": "chat_id", "userId": "user_id", "username": "username" }
}

{
  "type": "typing:stop",
  "data": { "chatId": "chat_id", "userId": "user_id" }
}

// Calls
{
  "type": "call:incoming",
  "data": { 
    "id": "call_id",
    "chatId": "chat_id",
    "type": "audio" | "video",
    "initiator": {...}
  }
}

{
  "type": "call:ended",
  "data": { 
    "id": "call_id",
    "chatId": "chat_id",
    "status": "ended" | "rejected" | "cancelled",
    "duration": 123
  }
}

// Call signaling (WebRTC)
{
  "type": "call:offer",
  "callId": "call_id",
  "offer": { /* RTCSessionDescription */ }
}

{
  "type": "call:answer",
  "callId": "call_id",
  "answer": { /* RTCSessionDescription */ }
}

{
  "type": "call:ice-candidate",
  "callId": "call_id",
  "candidate": { /* RTCIceCandidate */ }
}

Interactive Documentation

For interactive API testing, visit: /docs

Raw OpenAPI specification: /api/docs