Public documentation draft

Open, auditable messaging protocol for Benty.

Benty publishes its protocol model so developers can inspect Type Benty, build compatible clients, and understand how the platform evolves — cleanly, transparently, and without exposing production secrets.

Overview

Benty is a messaging platform for Russia and CIS markets, built around a Rust backend and a compact binary protocol called Type Benty. This documentation site is the public, readable layer: what the protocol is, how compatibility works, and how developers can reason about clients and forks.

Public by design. This site documents protocol and architecture principles. It does not publish private keys, credentials, internal production routes, admin paths, or deployment secrets.
Protocol first

Type Benty is the source of truth for entities, RPCs, layers, and compatibility rules.

Backend first

The server implementation is Rust-based and validates protocol drift before client rollout.

Single app entry

Production clients use one stable public entrypoint while routing remains infrastructure-side.

Type Benty protocol

Type Benty is Benty's own schema format. It is not Telegram TL. The goal is the same class of transparency: a protocol that can be inspected, tested, and implemented by serious developers.

40
namespaces
433
definitions
284
rpc methods
149
types

Namespaces

coresessionauthprofiledevicessecurityprivacycontactsdialogsarchivefoldersgroupschannelspublicChatsmessagesmediafilesstoriescallscallSignalingstickersemojireactionspollssearchnotificationspaymentspremiumbotssafetymoderationlegalappConfigstatsadminLogbannerssavedMessagespresenceactivityupdates

Published schema

The first public artifact is the current Type Benty schema draft. Developers can download it directly or inspect the opening section below.

Download /protocol/benty.tb

// Type Benty Protocol Schema
// File: protocol/benty.tb
// Status: draft v0 approved product scope
// Owner: Benty
// Note: TB is Benty's own protocol schema format. It is not Telegram TL.

protocol Benty {
  name = "benty"
  schema = "TB"
  schema_name = "Type Benty"
  current_layer = 1
  min_supported_layer = 1
  byte_order = "little_endian"
  id_width = "u32"
}

// ═══════════════════════════════════════════════════════════════
// Core
// ═══════════════════════════════════════════════════════════════

namespace core {
  type BoolFalse #00000001 = {}
  type BoolTrue  #00000002 = {}
  type Error     #00000003 = {
    code: i32
    message: string
  }
  type Null      #00000004 = {}
}

// ═══════════════════════════════════════════════════════════════
// Session / layer negotiation
// ═══════════════════════════════════════════════════════════════

namespace session {
  rpc clientHello #10000010 = {
    app_version: string
    engine_version: string
    platform: string
    device_id: string
    protocol_layer: i32
    supported_layers: vector<i32>
    feature_flags: vector<string>
  } -> serverHello

  type serverHello #20000010 = {
    selected_layer: i32
    min_supported_layer: i32
    max_supported_layer: i32
    server_time: i64
    feature_flags: vector<string>
  }
}

// ═══════════════════════════════════════════════════════════════
// Auth / profile / devices / security / privacy
// ═══════════════════════════════════════════════════════════════

namespace auth {
  rpc registerDevice #10000001 = {
    device_id: string
    platform: string
    push_token: optional<string>
  } -> profile.User

  rpc getMe #10000002 = {} -> profile.User

  rpc listDevices #10000003 = {} -> devices.DeviceList

  rpc updateProfile #10000004 = {
    display_name: optional<string>
    bio: optional<string>
    avatar_media_id: optional<string>
  } -> profile.User

  rpc requestCode #19000001 = {
    email: string
  } -> core.BoolTrue

  rpc verifyCode #19000002 = {
    email: string
    code: string
    device_id: string
  } -> AuthSession

  type AuthSession #01000003 = {
    account_id: i64
    token: string
    expires_at: i64
  }
}

namespace profile {
  type User #01000001 = {
    account_id: i64
    display_name: string
    username: optional<string>
    bio: optional<string>
    avatar_url: optional<string>
    premium: bool
    verified: bool
  }

  rpc getUser #11010010 = {
    account_id: i64
  } -> User

  rpc searchUsers #17000020 = {
    query: string
    offset: i32
    limit: i32
  } -> UserSearchResult

  rpc setUsername #11010004 = {
    username: string
  } -> User

  rpc setBio #11010005 = {
    bio: string
  } -> User

  type UserSearchResult #27000020 = {
    users: vector<User>
  }
}

namespace devices {
  type Device #01000002 = {
    id: i64
    device_id: string
    platform: string
    name: optional<string>
    last_active_at: i64
    trusted: bool
  }

  type DeviceList #01000020 = {
    devices: vector<Device>
  }

  rpc list #11020001 = {} -> DeviceList
  rpc revoke #11020002 = { device_id: string } -> core.BoolTrue
  rpc revokeAllExceptCurrent #11020003 = {} -> core.BoolTrue
  rpc rename #11020004 = { device_id: string name: string } -> Device
  rpc setTrusted #11020005 = { device_id: string trusted: bool } -> Device
}

namespace security {
  rpc listSessions #11030001 = {} -> AuthSessionList
  rpc terminateSession #11030002 = { session_id: i64 } -> core.BoolTrue
  rpc terminateAllSessions #11030003 = {} -> core.BoolTrue
  rpc setPassword #11030004 = { password_hash: bytes } -> core.BoolTrue
  rpc changePassword #11030005 = { old_password_hash: bytes new_password_hash: bytes } -> core.BoolTrue
  rpc disablePassword #11030006 = {} -> core.BoolTrue
  rpc set2fa #11030007 = { enabled: bool } -> core.BoolTrue

  type AuthSessionList #11031001 = {
    sessions: vector<auth.AuthSession>
  }
}

namespace privacy {
  rpc getSettings #11040001 = {} -> PrivacySettings
  rpc setLastSeen #11040002 = { mode: PrivacyMode } -> PrivacySettings
  rpc setProfilePhoto #11040003 = { mode: PrivacyMode } -> PrivacySettings
  rpc setCalls #11040004 = { mode: PrivacyMode } -> PrivacySettings
  rpc setGroupInvites #11040005 = { mode: PrivacyMode } -> PrivacySettings
  rpc setStories #11040006 = { mode: PrivacyMode } -> PrivacySettings
  rpc blockUser #11040007 = { account_id: i64 } -> core.BoolTrue
  rpc unblockUser #11040008 = { account_id: i64 } -> core.BoolTrue
  rpc getBlocked #11040009 = { offset: i32 limit: i32 } -> BlockedUsers

  enum PrivacyMode { everyone contacts nobody custom }

  type PrivacySettings #11041001 = {
    last_seen: PrivacyMode
    profile_photo: PrivacyMode
    calls: PrivacyMode
    group_invites: PrivacyMode
    stories: PrivacyMode
  }

  type BlockedUsers #11041002 = {
    users: vector<profile.User>
  }
}

// ═══════════════════════════════════════════════════════════════
// Contacts / dialogs / archive / folders
// ═══════════════════════════════════════════════════════════════

namespace contacts {
  type Contact #02000001 = {
    account_id: i64
    display_name: string
    username: optional<string>
    avatar_url: optional<string>
  }

  rpc list #17000010 = { offset: i32 limit: i32 } -> ContactList
  rpc add #17000001 = { account_id: i64 message: optional<string> } -> ContactRequest
  rpc accept #17000002 = { request_id: i64 } -> core.BoolTrue
  rpc decline #17000003 = { request_id: i64 } -> core.BoolTrue
  rpc delete #17000004 = { account_id: i64 } -> core.BoolTrue
  rpc createInvite #17000005 = { expires_at: optional<i64> max_uses: optional<i32> } -> ContactInvite
  rpc redeemInvite #17000006 = { code: string } -> Contact
  rpc importPhonebook #17000030 = { contacts: vector<PhonebookContact> } -> ImportResult
  rpc deleteImported #17000031 = {} -> core.BoolTrue
  rpc getImportStatus #17000032 = {} -> ImportStatus

  type ContactList #28000003 = { contacts: vector<Contact> }
  type ContactRequest #02000002 = { request_id: i64 from_account_id: i64 to_account_id: i64 message: optional<string> }
  type ContactInvite #02000003 = { code: string url: string expires_at: optional<i64> }
  type PhonebookContact #17001001 = { phone: optional<string> email: optional<string> name: optional<string> }
  type ImportResult #17001002 = { imported: i32 matched: i32 }
  type ImportStatus #17001003 = { imported_count: i32 last_import_at: optional<i64> }
}

namespace dialogs {
  type Dialog #03000001 = {

Server model

The backend is responsible for authentication, sessions, dialogs, messages, media metadata, delivery/read acknowledgements, SDUI banner payloads, and protocol compatibility. Infrastructure routing is kept behind the stable public entrypoint rather than pushed into clients.

Rust backend

Core HTTP/WSS engine and binary codec live server-side.

PostgreSQL

Persistent accounts, devices, dialogs, messages, sessions, and metadata.

Media storage

Server-managed media paths and metadata with client-safe references.

Clients

Clients should implement Type Benty commands and events, keep transport abstract, and preserve protocol layer compatibility. Mobile, desktop, and web clients can share the same schema while using platform-native UI.

Security and privacy

Benty documentation will describe the security model at a level that helps developers and auditors: auth flows, sessions, device trust, encrypted payload concepts, media access, abuse prevention, and responsible disclosure.

Forking and self-hosting

The long-term goal is to make it possible for qualified developers to inspect the protocol, build compatible clients, and run independent forks where technically and legally appropriate.

Compatibility rule: forks should preserve protocol IDs, layer negotiation, and schema evolution discipline to avoid breaking clients.

Transparency

We publish what helps users and developers verify Benty: protocol shape, compatibility rules, public schemas, and high-level architecture. We do not publish production secrets or internal operational routes.