ryOS ryOS / Docs
GitHub Launch

Presence API

Endpoints for presence tracking, user search, and AI integration in chat rooms.

Overview

Presence tracking keeps track of which users are currently active in which rooms. The AI endpoint allows users to get AI-generated responses within chat rooms.

Endpoint Summary

MethodEndpointDescriptionAuth
POST/api/presence/switchSwitch rooms (presence tracking)Yes
POST/api/presence/heartbeatRefresh global online presenceYes
GET/api/presence/heartbeatList globally online usersYes
GET/api/users?search=...Search usersYes
POST/api/ai/ryo-replyGenerate Ryo AI replyYes
POST/api/pusher/authAuthorize a private/presence Pusher channelYes
POST/api/realtime/ticketMint a local WebSocket realtime ticketYes

Presence

Switch Rooms

Update presence when a user switches between rooms. This is used for real-time "who's online" functionality.

POST /api/presence/switch
Authorization: Bearer {token}
X-Username: alice
Content-Type: application/json

{
  "previousRoomId": "general",
  "nextRoomId": "random",
  "username": "alice"
}
Request Body:
FieldTypeRequiredDescription
previousRoomIdstringNoRoom the user is leaving (null if first room)
nextRoomIdstringNoRoom the user is entering (null if leaving all)
usernamestringYesUser's username
Response (200):
{
  "success": true
}
Use Cases:
  • User opens chat app → previousRoomId: null, nextRoomId: "general"
  • User switches rooms → previousRoomId: "general", nextRoomId: "random"
  • User closes chat app → previousRoomId: "random", nextRoomId: null

Global Presence Heartbeat

Track which users are globally online (independent of any specific room). Both methods require authentication.

POST records a heartbeat for the authenticated user (kept in an online sorted-set with a 90-second TTL) and broadcasts a user-heartbeat event on the global presence channel:
POST /api/presence/heartbeat
Authorization: Bearer {token}
X-Username: alice
Response (200):
{
  "success": true
}
GET returns the list of currently-online usernames (stale entries older than 90 seconds are pruned):
GET /api/presence/heartbeat
Authorization: Bearer {token}
X-Username: alice
Response (200):
{
  "users": ["alice", "bob"]
}

User Search

Search Users

Search for users by username prefix.

GET /api/users?search=ali
Authorization: Bearer {token}
X-Username: alice
Query Parameters:
ParameterTypeRequiredDescription
searchstringYesUsername search string (minimum 2 chars; shorter queries return 400)

Requires a valid Authorization token and X-Username pair. User search is rate-limited per authenticated user and can return 429 when the search bucket is exhausted.

Response (200):
{
  "users": [
    {
      "username": "alice",
      "lastActive": 1704067200000
    },
    {
      "username": "alicia",
      "lastActive": 1704000000000
    }
  ]
}

AI Integration

Ryo Reply

Generate an AI response from Ryo within a chat room. This is triggered when users mention @ryo in their messages.

POST /api/ai/ryo-reply
Authorization: Bearer {token}
X-Username: alice
Content-Type: application/json

{
  "roomId": "general",
  "prompt": "what's up?",
  "systemState": {
    "chatRoomContext": {
      "recentMessages": "alice: hey everyone\nbob: hi alice\nalice: @ryo what's up?",
      "mentionedMessage": "@ryo what's up?"
    }
  }
}
Request Body:
FieldTypeRequiredDescription
roomIdstringYesRoom where the mention occurred
promptstringYesThe user's message/question
systemState.chatRoomContext.recentMessagesstringNoRecent chat history
systemState.chatRoomContext.mentionedMessagestringNoMessage that mentioned @ryo
Response (201):
{
  "message": {
    "id": "msg_123",
    "roomId": "general",
    "username": "ryo",
    "content": "hey, what's up",
    "timestamp": 1704067320000
  }
}

Rate Limits

User TypeLimitWindow
Authenticated5 requests1 minute

AI Behavior

When mentioned in chat rooms, Ryo:

  • Considers recent chat context
  • Responds in a casual, friendly tone
  • Can answer questions, provide information, or just chat
  • Respects the room's conversation flow

Realtime Authorization

ryOS supports two realtime providers. The active provider is set by REALTIME_PROVIDER; each authorization endpoint only works for its matching provider (the other returns 400).

Pusher Channel Auth

Authorizes a subscription to an authorization-requiring Pusher channel (private-…, presence-…). The server verifies the authenticated user may access the requested channel before signing. Used with the Pusher provider.

POST /api/pusher/auth
Authorization: Bearer {token}
X-Username: alice
Content-Type: application/json

{
  "socket_id": "123.456",
  "channel_name": "private-sync-alice"
}
Request Body:
FieldTypeRequiredDescription
socket_idstringYesPusher socket ID
channel_namestringYesChannel being subscribed to
Response (200): The Pusher auth signature payload (e.g. { "auth": "key:signature" }; presence channels also include channel_data). Returns 403 when the user is not allowed on the channel.

Realtime Ticket (Local Provider)

Mints a short-lived, single-use ticket for authenticating a self-hosted WebSocket connection. The HttpOnly auth cookie is scoped to /api and unreadable from JS, so the WebSocket (on a different path) presents this ticket instead. Only relevant for the local realtime provider.

POST /api/realtime/ticket
Authorization: Bearer {token}
X-Username: alice
Response (200):
{
  "ticket": "..."
}

Real-time Updates

Presence changes and AI replies trigger Pusher broadcasts to connected clients:

EventChannelPayload
room-updatedchats-public / chats-{username}{ room }
room-messageroom-{roomId}{ roomId, message }

Error Responses

StatusErrorDescription
400Invalid requestMissing or invalid parameters
401Authentication requiredToken missing (for AI reply)
403UnauthorizedOrigin not allowed
404Room not foundRoom ID doesn't exist
429Rate limit exceededToo many AI requests
500Failed to generate replyAI service error

Related