H2V Messenger API

Version 1.1.0 · Updated March 2026

Overview

PropertyValue
Base URLhttps://web.h2von.com
WebSocket URLwss://web.h2von.com/ws
Content-Typeapplication/json (except file upload)
Auth schemeSession cookie (HttpOnly)
Static filesGET /uploads/<filename>

Authentication Flow

H2V uses email OTP (one-time password) authentication — no passwords required.

Step 1 — Request OTP

POST /api/auth/send-otp { "email": "user@example.com" }

A 6-digit code is sent to the user's email (valid for 10 minutes).

Step 2 — Verify OTP

POST /api/auth/verify-otp { "email": "user@example.com", "code": "123456" }

If the user exists, a session is created and an auth cookie is set. If the user is new, the server responds with NICKNAME_REQUIRED — call again with nickname:

POST /api/auth/verify-otp { "email": "user@example.com", "code": "123456", "nickname": "john.doe" }
Nicknames: 5–32 chars, starts with a letter, [a-zA-Z0-9.] only.

Rate Limits

Route groupLimitWindow
/api/auth/*20 requests15 minutes
All other /api/*300 requests1 minute

Exceeding the limit returns HTTP 429 with code RATE_LIMIT.

Response Format

// Success { "success": true, "data": { ... } } // Error { "success": false, "code": "ERROR_CODE", "message": "Human-readable" } // Validation error { "success": false, "code": "VALIDATION_ERROR", "errors": { ... } }

Health Endpoints

GET /health No auth
Basic liveness check.
GET /api/health No auth
Full health check (database + cache status).

Auth Endpoints

POST /api/auth/send-otp No auth
Send a 6-digit OTP to the user's email. Rate limited to once per 60 seconds per email.
POST /api/auth/verify-otp No auth
Verify OTP, create session. For new users, include nickname.
POST /api/auth/logout Session
End the current session and clear the auth cookie.
GET /api/auth/sessions Session
List all active sessions for the current user (device, location, last active).
DELETE /api/auth/sessions/:id Session
Terminate a specific session by ID.
DELETE /api/auth/sessions Session
Terminate all sessions except the current one.

User Endpoints

GET /api/users/me Session
Get the current user's full profile (includes email).
PATCH /api/users/me Session
Update profile. Fields: nickname, firstName, lastName, avatar, bio (max 70 chars).
DELETE /api/users/me Session
Permanently delete account and all associated data.
GET /api/users/search?q=<query> Session
Search users by nickname (case-insensitive, up to 20 results).
GET /api/users/:id Session
Get any user's public profile.
POST /api/users/:id/block Session
Block a user.
DELETE /api/users/:id/block Session
Unblock a user.

Settings

GET /api/users/me/settings Session
Get the current user's settings (synced across devices).
PUT /api/users/me/settings Session
Update settings (partial merge). Available fields:
FieldTypeValues
notifSoundbooleanPlay sound on new messages
notifDesktopbooleanShow push notifications
sendByEnterbooleanEnter = send
fontSizestringsmall / medium / large
showOnlineStatusbooleanVisible to other users
showReadReceiptsbooleanSend read checkmarks
mediaAutoDownloadbooleanAuto-download media
chatWallpaperstringdefault / dark / dots / gradient
localestringen / ru

Chat Endpoints

GET /api/chats Session
List chats (sorted by last activity). Params: cursor, limit (1–100, default 30).
POST /api/chats/direct Session
Create or find a direct chat. Body: { "targetUserId": "..." }
POST /api/chats/group Session
Create a group chat. Body: { "name": "...", "memberIds": [...] }
POST /api/chats/secret Session
Create an E2E encrypted chat. Body: { "targetUserId": "..." }
PATCH /api/chats/:id Session
Update chat name/avatar (OWNER or ADMIN).
POST /api/chats/:id/members Session
Add members. Body: { "userIds": [...] }
DELETE /api/chats/:id/members/:userId Session
Remove a member from a group chat.
DELETE /api/chats/:id/leave Session
Leave a chat. For direct chats, removes both users.
GET /api/chats/:id/shared Session
Shared media. Params: type (IMAGE/VIDEO/FILE/AUDIO), cursor, limit.

Message Endpoints

GET /api/chats/:chatId/messages Session
Message history (cursor pagination, newest first). Params: cursor, limit (1–100), q (full-text search).
PATCH /api/messages/:id Session
Edit your message text. Body: { "text": "..." }
DELETE /api/messages/:id Session
Delete your message permanently.
POST /api/messages/:id/read Session
Mark a message as read.
POST /api/messages/:id/reactions Session
Add a reaction. Body: { "emoji": "👍" }. Allowed: 👍 ❤️ 😂 😮 😢 🔥
DELETE /api/messages/:id/reactions/:emoji Session
Remove your reaction (emoji must be URL-encoded).

Contact Endpoints

GET /api/contacts Session
Get the current user's contact list.
POST /api/contacts/:contactId Session
Add a user to contacts.
DELETE /api/contacts/:contactId Session
Remove from contacts.

File Upload

POST /api/upload Session
Upload a file (multipart/form-data, field: file). Max 20 MB.

Supported formats: JPEG, PNG, GIF, WebP, MP4, WebM, MP3, OGG, PDF, TXT, ZIP, DOC, DOCX.

Images are auto-optimized: resized and converted to WebP. Three versions are generated (original, medium 800px, thumbnail 200px).

POST /api/upload/avatar Session
Upload an avatar (images only, max 10 MB, resized to 400×400).

Keys (Signal Protocol)

H2V supports end-to-end encrypted "secret chats" using the Signal Protocol. These endpoints manage key exchange.

POST /api/keys/bundle Session
Upload your PreKey Bundle (identity key, signed prekey, one-time prekeys).
GET /api/keys/bundle/:userId Session
Fetch a user's PreKey Bundle (consumes one OTP prekey).
GET /api/keys/has-bundle/:userId Session
Check if a user has a bundle (no keys consumed).
POST /api/keys/replenish Session
Add more one-time prekeys when count gets low.
GET /api/keys/count Session
Get remaining OTP prekey count.

WebSocket Connection

const ws = new WebSocket('wss://web.h2von.com/ws'); ws.onopen = () => { ws.send(JSON.stringify({ "event": "auth", "payload": { "token": accessToken } })); }; ws.onmessage = (e) => { const { event, payload } = JSON.parse(e.data); if (event === 'auth:ok') { /* ready */ } };
Send presence:ping every 25 seconds to stay online and prevent timeout.

Client → Server Events

EventPayloadDescription
auth{ token }Authenticate after connecting
message:send{ chatId, text, type?, mediaUrl?, replyToId? }Send a message
message:read{ messageId, chatId }Mark as read
message:listened{ messageId, chatId }Mark voice message as listened
typing:start{ chatId }Start typing indicator
typing:stop{ chatId }Stop typing indicator
presence:pingKeep-alive (every 25s)
presence:awayUser switched away
presence:backUser returned

Server → Client Events

EventRecipientDescription
auth:okConnecting clientAuth successful, includes online user list
message:newAll chat membersNew message received
message:deliveredSender onlyAt least one recipient is online
message:readAll chat membersMessage was read
message:editedAll chat membersMessage text was edited
message:deletedAll chat membersMessage was deleted
message:listenedSenderVoice message was listened to
chat:newRecipientNew chat appeared (first message)
chat:deletedAll former membersChat was removed
chat:updatedAll membersChat metadata changed
reaction:addedAll chat membersReaction added to message
reaction:removedAll chat membersReaction removed
typing:startedAll except senderUser is typing
typing:stoppedAll except senderUser stopped typing
user:onlineRelevant usersUser came online
user:offlineRelevant usersUser went offline
user:updatedShared chat usersProfile updated
presence:snapshotNew clientList of online users on connect
errorRequesting clientServer could not process event

Error Codes

CodeHTTPDescription
OTP_TOO_SOON429Resend requested < 60s after previous
EMAIL_SEND_FAILED502Email delivery failed
OTP_EXPIRED400Code expired (10 min TTL)
INVALID_CODE400Wrong OTP code
OTP_MAX_ATTEMPTS4295 wrong attempts — code invalidated
DISPOSABLE_EMAIL422Temporary email blocked
NICKNAME_REQUIRED422New user must provide nickname
NICKNAME_TAKEN409Nickname already registered
RATE_LIMIT429Too many requests
VALIDATION_ERROR422Invalid request data

Quick Reference

MethodPathAuthDescription
GET/healthLiveness
POST/api/auth/send-otpSend OTP
POST/api/auth/verify-otpVerify OTP
POST/api/auth/logoutSessionLogout
GET/api/auth/sessionsSessionList sessions
DELETE/api/auth/sessions/:idSessionTerminate session
GET/api/users/meSessionMy profile
PATCH/api/users/meSessionUpdate profile
DELETE/api/users/meSessionDelete account
GET/api/users/search?q=SessionSearch users
GET/api/users/me/settingsSessionGet settings
PUT/api/users/me/settingsSessionUpdate settings
GET/api/chatsSessionChat list
POST/api/chats/directSessionCreate direct chat
POST/api/chats/groupSessionCreate group
POST/api/chats/secretSessionCreate E2E chat
GET/api/chats/:chatId/messagesSessionMessage history
POST/api/uploadSessionUpload file
POST/api/upload/avatarSessionUpload avatar