Skip to main content

REST API Endpoints

All HTTP REST requests pass through the central ingress gateway (dev:gateway on :8090 locally, or Nginx on port 443 in production) and are routed internally to their owning microservices.

Standard Request Headers​

Authorization: Bearer <jwt-access-token>
Content-Type: application/json
X-Request-Id: <uuid-v4>

1. Authentication Service (auth-service / :3001)​

Base Route: /api/v1/auth

MethodPathAuth RequiredDescription
POST/registerNoCreates a new user account and mints auth tokens.
POST/loginNoAuthenticates via email/username and password.
POST/refreshNoRotates refresh token and issues a new access token.
GET/meYesRetrieves the caller's PublicUser account profile.
PATCH/meYesUpdates display name, avatar URL, cover photo, or about line.
POST/change-passwordYesChanges account password and invalidates active refresh tokens.
POST/forgot-passwordNoInitiates password recovery request via SMTP or admin reset token.
POST/reset-passwordNoConsumes a one-time password reset token to set a new password.

Example: POST /api/v1/auth/login​

// Request Body
{
"email": "demo@betweenus.local",
"password": "Password123!"
}

// Response (HTTP 200 OK)
{
"accessToken": "eyJhbGciOiJIUzI1NiIsIn...",
"refreshToken": "7c8e9f0a-1b2c-3d4e-5f6a-7b8c9d0e1f2a",
"expiresIn": 900
}

2. Server & Membership Service (server-service / :3003)​

Base Route: /api/v1/servers

MethodPathAuth RequiredDescription
GET/YesLists all servers where the caller is an active member.
POST/YesCreates a new server workspace and sets caller as OWNER.
GET/:serverIdYesFetches server metadata, channels, roles, and member count.
PATCH/:serverIdYesUpdates server name, icon, banner, or default role settings.
DELETE/:serverIdYesPermanently deletes server (requires OWNER role).
GET/:serverId/channelsYesLists text and voice channels within the server.
POST/:serverId/channelsYesCreates a new channel (TEXT or VOICE).
GET/:serverId/categoriesYesLists the server's channel categories.
POST/:serverId/categoriesYesCreates a category (MANAGE_CHANNEL).
PATCH/:serverId/categories/:categoryIdYesRenames a category (MANAGE_CHANNEL).
DELETE/:serverId/categories/:categoryIdYesDeletes a category; its channels move to uncategorized (MANAGE_CHANNEL).
PUT/:serverId/channel-layoutYesReorders categories and moves channels between them, atomically (MANAGE_CHANNEL).
GET/:serverId/membersYesLists enrolled members with assigned roles and joined timestamps.
POST/:serverId/invitesYesCreates a shareable invite code with max uses and TTL.
POST/invites/:code/joinYesJoins a server using an active invite link.

3. Chat & Messaging Service (chat-service / :3004)​

Base Route: /api/v1

MethodPathAuth RequiredDescription
GET/channels/:channelId/messagesYesCursor-paginated message history (sorted newest to oldest).
POST/channels/:channelId/messagesYesPublishes an encrypted or system message.
GET/messages/:messageIdYesOne message by id, tombstone included. 404 outside a channel the caller can see.
PATCH/messages/:messageIdYesEdits message ciphertext or content.
GET/messages/:messageId/editsYesEarlier versions of an edited message, newest first (max 50), sealed. Same visibility as the message; empty for a tombstone.
DELETE/messages/:messageIdYesSoft-deletes a message (renders tombstone).
POST/messages/:messageId/reactionsYesAdds an emoji reaction to a message.
DELETE/messages/:messageId/reactionsYesRemoves the caller's emoji reaction.
POST/messages/:messageId/pinYesPins a message to the channel's pinned list.
PUT/messages/:messageId/poll/voteYesReplaces the caller's whole ballot on a poll: { options: number[] }, option indexes only. An empty list retracts. 400 INVALID_VOTE / SINGLE_CHOICE_POLL, 409 POLL_CLOSED, 404 POLL_NOT_FOUND. Needs SEND_MESSAGE.
POST/messages/:messageId/poll/closeYesStops voting early. The author, or MANAGE_MESSAGE in a server channel. Idempotent.
POST/channels/:channelId/attachments/uploadYesInitiates single or multipart encrypted file upload.

A poll is sent through the ordinary send route with one extra field, poll: { optionCount: 2-10, multiChoice?: boolean, durationSeconds?: 3600 | 86400 | 259200 | 604800 | null }. content is the sealed envelope carrying the question and the option labels; the server is told only the numbers, refuses any other field inside poll (400), and refuses to edit a poll's content afterwards (POLL_NOT_EDITABLE). Every Message that is a poll carries poll: { optionCount, multiChoice, closesAt, closedAt, closedBy, tallies: [{ option, userIds }] }.

Example: POST /api/v1/channels/:channelId/messages​

// Request Body (Encrypted User Message)
{
"kind": "USER",
"encryptedEnvelope": {
"ephemeralPublicKey": "04c8f2a1...",
"iv": "dGVzdGl2MTIzNA==",
"ciphertext": "W2VuY3J5cHRlZCBtZXNzYWdlIGNvbnRlbnRd",
"tag": "ZXhhbXBsZXRhZzEyMw==",
"epoch": 1
}
}

// Response (HTTP 201 Created)
{
"id": "e8a9b2c3-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
"channelId": "f28391a8-73b9-422b-8a46-5b1f863d45b3",
"authorId": "440dbb3b-071f-4567-b4db-095ca4bc22b6",
"kind": "USER",
"encryptedEnvelope": { ... },
"attachments": [],
"reactions": [],
"createdAt": "2026-09-04T02:00:00.000Z"
}

4. Presence & Social Service (presence-service / :3005)​

Base Route: /api/v1/presence

MethodPathAuth RequiredDescription
GET/users/:userIdYesReturns user presence (online, idle, dnd, offline) and last seen.
PUT/statusYesUpdates caller's presence status and custom activity string.
GET/friendsYesLists accepted friends and pending incoming/outgoing requests.
POST/friends/requestsYesSends a friend request via username (username#0000).
POST/friends/requests/:id/acceptYesAccepts an incoming friend request.

5. Notification Service (notification-service / :3006)​

Base Route: /api/v1/notifications

MethodPathAuth RequiredDescription
GET/unreadYesReturns unread message count and mention flags across all channels.
POST/readYesMarks a channel as read up to a specified message ID.
GET/preferencesYesFetches global and per-channel notification preferences.
PUT/preferencesYesUpdates notification level (all, mentions, nothing).
POST/devicesYesEnrolls an FCM push token or Web Push subscription.
DELETE/devices/:deviceIdYesRevokes push token on sign-out.

6. Voice & Call Switchboard (call-service / :3007)​

Base Route: /api/v1/calls

MethodPathAuth RequiredDescription
GET/ice-serversYesReturns STUN/TURN relay credentials with time-limited HMAC auth.
GET/channels/:channelId/rosterYesLists active peers currently connected to a voice stage.
POST/direct/ringYesTriggers an incoming 1-to-1 direct call to another user's devices.
POST/direct/declineYesDismisses a ring across all connected devices.

7. Remote Desktop Gateway (remote-gateway / :3008)​

Base Route: /api/v1/remote

MethodPathAuth RequiredDescription
GET/machinesYesLists enrolled remote desktop target machines.
POST/machines/enrolYesGenerates machine enrolment token and machine key.
GET/machines/:machineId/grantsYesLists user access permissions for a machine.
POST/machines/:machineId/grantsYesGrants or revokes remote control / view permissions.
POST/sessions/startYesNegotiates peer-to-peer WebRTC data channels for remote control.
DELETE/sessions/:sessionIdYesEnds a session. Optional body reports what the controller's machine moved.
GET/usageYesThis account's own remote sessions over days, with totals — the remote half of Calls & Data.