API
Everything the app does goes through one endpoint: api.php?action=<name>. Answers are JSON: {"ok": true, ...}, or {"ok": false, "error": "a readable reason"} with an HTTP error status.
Signing in
- The app uses a session cookie (
login/register), and sends its CSRF token in anX-CSRF-Tokenheader on every POST. Actions that change something must be POSTed with a JSON body. - Bots send
Authorization: Bot vlb_…instead and can use a smaller set of actions: see Bots. - Presence helpers send
Authorization: Bearer vlp_…topresenceonly (Settings → Activity makes the key).
Keeping up to date: sync
The app calls sync every 1.5 seconds (every 4 when the tab is hidden) with since (the now from the previous answer), the open server_id and channel_id, and voice_peer while in a call. It returns: your profile, your spaces, DMs, unread counts, everyone's voice states, the open space's channels, members and roles, the open channel's new or changed messages and who's typing, alerts (mentions, DMs, friend requests) and the current version.
Actions
| Area | Actions |
|---|---|
| Account | register, login, logout, me, profile_update, avatar_upload, banner_upload, sessions_revoke, account_delete, data_export, user_profile |
| Friends | friend_request, friend_accept, friend_remove, block, unblock |
| Spaces | server_create, server_join, server_leave, server_update, server_delete, server_kick, server_media_upload, discord_template, discord_import |
| Roles and badges | role_create, role_update, role_icon_upload, role_delete, role_move, member_roles_set, badge_update, badge_icon_upload, dev_tag_set |
| Channels | channel_create, channel_update, channel_delete, channel_move, category_create, category_update, category_delete, category_move |
| Messages | messages, message_send, message_edit, message_delete, message_pin, pins, react, typing, read, search, upload, dm_open |
| Voice | voice_join, voice_update, voice_leave, voice_move, voice_disconnect |
| Encryption | e2ee_key_register, e2ee_keys, e2ee_key_remove |
| GIFs and stickers | gif_search, gif_favorites, gif_favorite, stickers_list, sticker_search, sticker_upload, sticker_delete |
| Activity and parties | activity_set, presence_token, presence_token_revoke, presence, party_create, party_join, party_leave |
| Bots | bots_list, bot_create, bot_update, bot_avatar_upload, bot_token_reset, bot_delete, space_bot_add, space_bot_remove, bot_events |
| Plugins and themes | plugins, plugin_shop, plugin_install, plugin_uninstall, themes |
| Plugin registry (public) | shop_catalog, shop_download |
| Patch notes | patch_notes, patch_notes_seen, egg_found |
Encrypted direct messages
A message in a direct message can carry enc instead of content: an envelope {v: 1, sd, iv, ct, k} where ct is the AES-256-GCM ciphertext of {t: text, a: attachments, s: sticker}, and k holds the message key wrapped for each device ("<user id>:<device id>": "<iv>.<wrapped key>"). The server checks the envelope's shape only; it can't read it. Files in encrypted messages are uploaded already encrypted, with their keys inside the envelope. assets/e2ee.js is the reference implementation.
Errors and limits
- 401 means the session ended (or the bot token is wrong); 403 a missing permission; 429 too fast.
- Bots can send 5 messages every 5 seconds. Uploads are limited by
MAX_UPLOAD_BYTESinconfig.php.