v0.9.1 routes - nself-org/nchat GitHub Wiki
Quick reference for all API routes added/completed in v0.9.1.
GET /api/channels/categories?workspaceId={uuid}&includeChannels=trueResponse:
{
"success": true,
"categories": [...],
"pagination": {
"total": 10,
"offset": 0,
"limit": 50,
"hasMore": false
}
}POST /api/channels/categories
Authorization: Bearer {token}
Content-Type: application/json
{
"name": "Important Channels",
"description": "High priority channels",
"workspaceId": "uuid",
"position": 0,
"isCollapsed": false
}Permissions: admin, owner
PUT /api/channels/{channelId}/category
Authorization: Bearer {token}
Content-Type: application/json
{
"categoryId": "uuid",
"position": 2,
"reorderExisting": true
}Response:
{
"success": true,
"channel": {
"id": "uuid",
"name": "general",
"category_id": "uuid",
"position": 2,
"updated_at": "2026-02-03T..."
},
"message": "Channel assigned to category successfully"
}Permissions: admin, owner, moderator
DELETE /api/channels/{channelId}/category
Authorization: Bearer {token}Permissions: admin, owner, moderator
GET /api/channels/guild?organizationId={uuid}&isDiscoverable=true&limit=20POST /api/channels/guild
Authorization: Bearer {token}
Content-Type: application/json
{
"name": "My Community",
"slug": "my-community",
"description": "A place for friends",
"iconUrl": "https://...",
"bannerUrl": "https://...",
"vanityUrl": "mycommunity",
"isDiscoverable": true,
"verificationLevel": 1,
"explicitContentFilter": 1,
"maxMembers": 5000,
"maxChannels": 100,
"maxFileSizeMb": 25
}Note: Auto-creates default categories and channels.
GET /api/channels/broadcast?workspaceId={uuid}&ownerId={uuid}POST /api/channels/broadcast
Authorization: Bearer {token}
Content-Type: application/json
{
"workspaceId": "uuid",
"name": "Product Updates",
"description": "Weekly product announcements",
"subscriptionMode": "invite",
"allowReplies": false,
"showSenderName": true,
"trackDelivery": true,
"trackReads": false,
"maxSubscribers": 1000,
"initialSubscriberIds": ["uuid1", "uuid2"]
}POST /api/calls/{callId}/recording
Authorization: Bearer {token}
Content-Type: application/json
{
"format": "mp4",
"quality": "high",
"includeAudio": true,
"includeVideo": true,
"includeScreenShare": true,
"layout": "grid"
}Options:
- Format:
mp4,webm,mp3 - Quality:
low,medium,high,hd - Layout:
grid,spotlight,presentation
GET /api/calls/{callId}/recording
Authorization: Bearer {token}DELETE /api/calls/{callId}/recording
Authorization: Bearer {token}GET /api/calls/{callId}/participants
Authorization: Bearer {token}POST /api/calls/{callId}/participants
Authorization: Bearer {token}
Content-Type: application/json
{
"userIds": ["uuid1", "uuid2"]
}DELETE /api/calls/{callId}/participants/{userId}
Authorization: Bearer {token}GET /api/streams/{streamId}/analytics
Authorization: Bearer {token}Response:
{
"success": true,
"analytics": {
"viewerCount": 42,
"peakViewers": 68,
"duration": 3600,
"chatMessages": 234,
"reactions": {
"likes": 156,
"loves": 89,
"fire": 45
}
}
}GET /api/streams/{streamId}/viewers?includeMetadata=true&includeInactive=false&sortBy=joinTime&sortOrder=asc&limit=100&offset=0Query Parameters:
-
includeMetadata(boolean): Include LiveKit participant data -
includeInactive(boolean): Include viewers who left -
sortBy(enum):joinTime,username,duration -
sortOrder(enum):asc,desc -
limit(int): 1-1000, default 100 -
offset(int): >= 0, default 0
Response:
{
"success": true,
"viewers": [
{
"id": "uuid",
"userId": "uuid",
"username": "john_doe",
"displayName": "John Doe",
"avatarUrl": "https://...",
"joinedAt": "2026-02-03T12:00:00Z",
"duration": 1234,
"isActive": true,
"isAudioEnabled": true,
"isVideoEnabled": false,
"isScreenSharing": false,
"connectionQuality": "excellent",
"livekitParticipant": { ... }
}
],
"stats": {
"active": 15,
"total": 42,
"streamStatus": "connected",
"duration": 3600
},
"pagination": {
"total": 42,
"offset": 0,
"limit": 100,
"hasMore": false
},
"stream": {
"id": "uuid",
"name": "Stream by John",
"type": "video",
"status": "connected",
"startedAt": "2026-02-03T12:00:00Z",
"initiator": {
"id": "uuid",
"username": "john_doe",
"displayName": "John Doe",
"avatarUrl": "https://..."
}
}
}GET /api/auth/idme/callback?code={code}&state={state}Response: Redirects to app with session cookie
POST /api/auth/resend-verification
Content-Type: application/json
{
"email": "[email protected]"
}Rate Limit: 3 requests per hour per IP
Response:
{
"success": true,
"message": "If your account exists and is unverified, a verification email has been sent."
}Note: Always returns success to prevent email enumeration.
GET /api/auth/verify-email/{token}Response: Redirects to app with verified status
All routes follow this error format:
{
"success": false,
"error": "Error message",
"details": {
"field": ["validation error"]
}
}-
200 OK- Success (GET, PUT, DELETE) -
201 Created- Success (POST) -
400 Bad Request- Validation error -
401 Unauthorized- Authentication required -
403 Forbidden- Insufficient permissions -
404 Not Found- Resource not found -
409 Conflict- Duplicate resource -
500 Internal Server Error- Server error
Most routes require authentication via Bearer token:
Authorization: Bearer {token}Or user ID header (dev mode):
x-user-id: {userId}
x-user-role: {role}Rate limits apply to:
- Email verification: 3 per hour per IP
- Authentication endpoints: varies by endpoint
Rate limit headers:
X-RateLimit-Limit: 3
X-RateLimit-Remaining: 2
X-RateLimit-Reset: 1675436400List endpoints support pagination:
Query Parameters:
-
limit: Items per page (default varies by endpoint) -
offset: Skip N items
Response:
{
"pagination": {
"total": 100,
"offset": 0,
"limit": 20,
"hasMore": true
}
}Real-time updates via Socket.io:
channel:updatedchannel:category_changedcategory:createdcategory:updatedcategory:deleted
call:participant_joinedcall:participant_leftcall:recording_startedcall:recording_stopped
stream:viewer_joinedstream:viewer_leftstream:stats_updated
Alternative to WebSocket events, use GraphQL subscriptions:
subscription SubscribeToCategoryUpdates($workspaceId: uuid!) {
nchat_channel_categories(
where: { workspace_id: { _eq: $workspaceId } }
order_by: { position: asc }
) {
id
name
position
channels {
id
name
position
}
}
}Use curl for testing:
# Test category assignment
curl -X PUT http://localhost:3000/api/channels/{channelId}/category \
-H "Content-Type: application/json" \
-H "x-user-id: {userId}" \
-H "x-user-role: admin" \
-d '{"categoryId": "{categoryId}", "position": 1}'
# Test stream viewers
curl http://localhost:3000/api/streams/{streamId}/viewers?limit=10&sortBy=joinTime
# Test resend verification
curl -X POST http://localhost:3000/api/auth/resend-verification \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]"}'Version: v0.9.1 Last Updated: February 3, 2026