---
title: "API types"
description: "The messages and enums the Sblurp community server API shares between calls, with every field."
nav: "Types"
doc_version: 1
last_updated: 2026-10-18
---

<!-- Generated by auth/cmd/apidocs from proto/sblurp/v1/sblurp.proto. Do not edit; run go generate in auth/cmd/auth. -->

# Types

The messages and enums that calls and events share. In JSON (protojson) field names are lowerCamelCase, 64-bit numbers are strings, and enums are their names. Tools can read the same types from [schema.json](/docs/api/schema.json).

## MemberKind

| Value | Number | Notes |
|---|---|---|
| `MEMBER_KIND_UNSPECIFIED` | 0 |  |
| `MEMBER_KIND_HUMAN` | 1 |  |
| `MEMBER_KIND_BOT` | 2 |  |

## MemberRole

| Value | Number | Notes |
|---|---|---|
| `MEMBER_ROLE_UNSPECIFIED` | 0 |  |
| `MEMBER_ROLE_MEMBER` | 1 |  |
| `MEMBER_ROLE_MODERATOR` | 2 |  |
| `MEMBER_ROLE_ADMIN` | 3 |  |
| `MEMBER_ROLE_OWNER` | 4 |  |

## Presence

| Value | Number | Notes |
|---|---|---|
| `PRESENCE_UNSPECIFIED` | 0 |  |
| `PRESENCE_ONLINE` | 1 |  |
| `PRESENCE_AWAY` | 2 |  |
| `PRESENCE_OFFLINE` | 3 |  |

## Member

| Field | Type | Notes |
|---|---|---|
| `id` | `string` | UUIDv7, local to this server |
| `kind` | [MemberKind](/docs/api/types#memberkind) |  |
| `role` | [MemberRole](/docs/api/types#memberrole) |  |
| `username` | `string` | unique on this server |
| `display_name` | `string` |  |
| `avatar_url` | `string` | may be empty |
| `bio` | `string` |  |
| `presence` | [Presence](/docs/api/types#presence) |  |
| `joined_at_ms` | `int64` |  |
| `status_text` | `string` | short custom status, may be empty |
| `status_emoji` | `string` |  |
| `role_ids` | repeated `string` | custom roles (visibility only), see Role |

## Role

A custom role, made by admins. Roles only decide which text channels a member can see (Channel.role_ids). MemberRole still decides permissions; call that one "Permission" in the UI and these "Roles".

| Field | Type | Notes |
|---|---|---|
| `id` | `string` |  |
| `name` | `string` | unique, case-insensitive |
| `color` | `string` | "#rrggbb" or empty |
| `position` | `int32` | sort order, low first |

## ChannelMode

How members get into text channels. Private channels and DMs keep their explicit member lists in both modes.

| Value | Number | Notes |
|---|---|---|
| `CHANNEL_MODE_UNSPECIFIED` | 0 |  |
| `CHANNEL_MODE_ROLES` | 1 | Discord-like: you are in every text channel you can see |
| `CHANNEL_MODE_OPT_IN` | 2 | Slack-like: browse the channels you can see, join and leave them |

## ChannelKind

| Value | Number | Notes |
|---|---|---|
| `CHANNEL_KIND_UNSPECIFIED` | 0 |  |
| `CHANNEL_KIND_TEXT` | 1 | every member can see it, unless role_ids limits it |
| `CHANNEL_KIND_PRIVATE` | 2 | invite only |
| `CHANNEL_KIND_DM` | 3 | direct message, 2+ members |

## Channel

| Field | Type | Notes |
|---|---|---|
| `id` | `string` |  |
| `kind` | [ChannelKind](/docs/api/types#channelkind) |  |
| `name` | `string` | empty for DMs |
| `topic` | `string` |  |
| `category` | `string` | sidebar section, e.g. "General"; empty = none |
| `position` | `int32` | sort order inside the category |
| `member_ids` | repeated `string` | set for DM and PRIVATE channels |
| `created_at_ms` | `int64` |  |
| `last_message_seq` | `int64` | seq of the newest message, 0 if none |
| `role_ids` | repeated `string` | TEXT only. Empty: every member can see the channel. Otherwise only members with one of these roles (and admins and the owner) can. |
| `is_default` | `bool` | TEXT only: OPT_IN mode joins new members to it |
| `member_count` | `int32` | set by BrowseChannels only; 0 elsewhere |
| `header_image` | [Attachment](/docs/api/types#attachment) | optional image behind the channel header |

## Attachment

| Field | Type | Notes |
|---|---|---|
| `id` | `string` |  |
| `name` | `string` |  |
| `content_type` | `string` |  |
| `size` | `int64` |  |
| `url` | `string` | relative to the server base URL |
| `width` | `int32` | images only |
| `height` | `int32` |  |

## Reaction

| Field | Type | Notes |
|---|---|---|
| `emoji` | `string` | unicode emoji or ":shortcode:" |
| `member_ids` | repeated `string` |  |

## Message

| Field | Type | Notes |
|---|---|---|
| `id` | `string` |  |
| `channel_id` | `string` |  |
| `author_id` | `string` |  |
| `text` | `string` | markdown subset: bold, italic, code, links, mentions <@member_id> |
| `created_at_ms` | `int64` |  |
| `edited_at_ms` | `int64` | 0 if never edited |
| `deleted` | `bool` |  |
| `thread_root_id` | `string` | set when this message is a thread reply |
| `reply_count` | `int32` | on a thread root |
| `last_reply_at_ms` | `int64` |  |
| `reactions` | repeated [Reaction](/docs/api/types#reaction) |  |
| `attachments` | repeated [Attachment](/docs/api/types#attachment) |  |
| `client_id` | `string` | echo of SendMessageRequest.client_id, for optimistic UI |
| `seq` | `int64` | event seq that last changed this message (edits, reactions, replies bump it) |
| `created_seq` | `int64` | seq of message_created; never changes. Compare this with last_read_seq. |

## ReadState

| Field | Type | Notes |
|---|---|---|
| `channel_id` | `string` |  |
| `last_read_seq` | `int64` |  |
| `unread_count` | `int32` |  |
| `mention_count` | `int32` |  |

## TypingEvent

| Field | Type | Notes |
|---|---|---|
| `channel_id` | `string` |  |
| `member_id` | `string` |  |
| `thread_root_id` | `string` |  |

## PresenceEvent

| Field | Type | Notes |
|---|---|---|
| `member_id` | `string` |  |
| `presence` | [Presence](/docs/api/types#presence) |  |

## PresenceBatch

Many presence changes at once, the latest per member. The server sends this instead of single presence events when several are waiting (a reconnect burst after a restart).

| Field | Type | Notes |
|---|---|---|
| `changes` | repeated [PresenceEvent](/docs/api/types#presenceevent) |  |

## Event

| Field | Type | Notes |
|---|---|---|
| `seq` | `int64` | 0 for ephemeral events (typing, presence, heartbeat) |
| `at_ms` | `int64` |  |
| `message_created` | [Message](/docs/api/types#message) | One of `kind`. |
| `message_updated` | [Message](/docs/api/types#message) | One of `kind`. edits, reactions, reply counts |
| `message_deleted` | [Message](/docs/api/types#message) | One of `kind`. |
| `channel_created` | [Channel](/docs/api/types#channel) | One of `kind`. |
| `channel_updated` | [Channel](/docs/api/types#channel) | One of `kind`. |
| `channel_deleted` | `string` | One of `kind`. channel id |
| `member_joined` | [Member](/docs/api/types#member) | One of `kind`. |
| `member_updated` | [Member](/docs/api/types#member) | One of `kind`. |
| `member_left` | `string` | One of `kind`. member id |
| `read_state` | [ReadState](/docs/api/types#readstate) | One of `kind`. my own read state, from another device |
| `typing` | [TypingEvent](/docs/api/types#typingevent) | One of `kind`. ephemeral |
| `presence` | [PresenceEvent](/docs/api/types#presenceevent) | One of `kind`. ephemeral |
| `heartbeat` | `bool` | One of `kind`. ephemeral, every 25s keeps proxies open |
| `resync` | `bool` | One of `kind`. client must call GetState |
| `role_updated` | [Role](/docs/api/types#role) | One of `kind`. created or changed |
| `role_deleted` | `string` | One of `kind`. role id; drop it from members and channels |
| `channel_mode_changed` | [ChannelMode](/docs/api/types#channelmode) | One of `kind`. |
| `server_updated` | `bool` | One of `kind`. description, banner or icon changed; call GetServerInfo |
| `emoji_changed` | `bool` | One of `kind`. custom emoji added or deleted; refetch GET /emoji |
| `presence_batch` | [PresenceBatch](/docs/api/types#presencebatch) | One of `kind`. ephemeral; apply each change like presence |
| `plugins_changed` | `bool` | One of `kind`. a plugin was installed, enabled, disabled or deleted; admins call ListPlugins |
| `member_blocked` | `string` | One of `kind`. member id; I blocked them (from any of my devices) |
| `member_unblocked` | `string` | One of `kind`. member id; I unblocked them |
| `member_muted` | `string` | One of `kind`. member id; I muted them (from any of my devices) |
| `member_unmuted` | `string` | One of `kind`. member id; I unmuted them |

## LinkPreview

| Field | Type | Notes |
|---|---|---|
| `url` | `string` | the link as written in the message |
| `title` | `string` |  |
| `description` | `string` |  |
| `site_name` | `string` |  |
| `image_url` | `string` | relative to the server base URL; "" if none |

## Ban

A banned login. The member row stays, so member.id keeps working.

| Field | Type | Notes |
|---|---|---|
| `member` | [Member](/docs/api/types#member) | the profile they had when banned |
| `banned_by` | `string` | member id |
| `banned_at_ms` | `int64` |  |

## Report

| Field | Type | Notes |
|---|---|---|
| `id` | `string` |  |
| `message` | [Message](/docs/api/types#message) | copy at report time: id, channel_id, author_id, text, created_at_ms, thread_root_id |
| `dm` | `bool` | the message is in a DM; moderators cannot open it |
| `author` | [Member](/docs/api/types#member) | who wrote the message (may have left) |
| `reporter` | [Member](/docs/api/types#member) |  |
| `note` | `string` |  |
| `reported_at_ms` | `int64` |  |

## Invite

| Field | Type | Notes |
|---|---|---|
| `code` | `string` | 10 characters, A-Z and 2-7 |
| `created_by` | `string` | member id |
| `created_at_ms` | `int64` |  |
| `expires_at_ms` | `int64` | 0 = never |
| `max_uses` | `int32` | 0 = no limit |
| `uses` | `int32` | joins it allowed so far |

## CustomEmoji

| Field | Type | Notes |
|---|---|---|
| `name` | `string` | 1 to 62 of a-z, 0-9, - and _; unique on this server |
| `url` | `string` | relative to the server base URL; never changes, cache forever |

## ListEmojiResponse

| Field | Type | Notes |
|---|---|---|
| `emoji` | repeated [CustomEmoji](/docs/api/types#customemoji) | sorted by name |

## EmojiUploadStatus

| Value | Number | Notes |
|---|---|---|
| `EMOJI_UPLOAD_STATUS_UNSPECIFIED` | 0 |  |
| `EMOJI_UPLOAD_STATUS_ADDED` | 1 |  |
| `EMOJI_UPLOAD_STATUS_EXISTS` | 2 | skipped: the name is taken |
| `EMOJI_UPLOAD_STATUS_REJECTED` | 3 | see error |

## EmojiUploadResult

| Field | Type | Notes |
|---|---|---|
| `file` | `string` | the file name, or its path inside a zip |
| `name` | `string` | emoji name made from the file name |
| `status` | [EmojiUploadStatus](/docs/api/types#emojiuploadstatus) |  |
| `error` | `string` | why it was rejected |

## UploadEmojiResponse

| Field | Type | Notes |
|---|---|---|
| `results` | repeated [EmojiUploadResult](/docs/api/types#emojiuploadresult) |  |

## Plugin

A JavaScript plugin in the plugins folder of the data directory. name is also its bot's username.

| Field | Type | Notes |
|---|---|---|
| `name` | `string` |  |
| `enabled` | `bool` |  |
| `running` | `bool` | loaded and taking hooks |
| `error` | `string` | why it did not load, or its last hook failure |
| `bot_id` | `string` | "" until it has loaded once |

## Sitemap

- [Sblurp: chat for communities](https://sblurp.chat/index.md): Sblurp is group chat with channels, threads and roles. Each community runs on its own server, and one Sblurp account signs you in to all of them.
- [About Sblurp](https://sblurp.chat/about.md): Why Sblurp exists: chat for communities that each run their own server, with no ads, no unasked-for AI and an honest word on encryption.
- [Privacy at Sblurp](https://sblurp.chat/privacy.md): What sblurp.chat stores about you, what it never stores, what it shares with communities you join, and how to get a copy or delete it.
- [Terms of use](https://sblurp.chat/terms.md): The terms for a sblurp.chat account: who can sign up, what you must not do, and what we do and do not promise. A first draft.
- [Create your Sblurp account](https://sblurp.chat/signup.md): Create a Sblurp account: one account for every Sblurp community you join. You need an email, a username, a password and to be 13 or older.
- [Sign in to Sblurp](https://sblurp.chat/login.md): Sign in to your Sblurp account with your email or username and password, or with a passkey. One account works in every Sblurp community.
- [Reset your password](https://sblurp.chat/forgot.md): Forgot your Sblurp password? Type the email you signed up with and we send a link to choose a new one. The link works once, for one hour.
- [Sblurp docs](https://sblurp.chat/docs.md): Sblurp documentation: how accounts and communities work, how to run a community server, how to add bots, and the full API reference.
- [Accounts and communities](https://sblurp.chat/docs/accounts.md): How a Sblurp account relates to the communities you join: what sblurp.chat keeps, what each community server sees, and what stays private.
- [Join a community](https://sblurp.chat/docs/join.md): Join a Sblurp community: add it by address or invite link, answer its questions, choose what to share, and join.
- [Sblurp glossary](https://sblurp.chat/docs/glossary.md): The words the Sblurp docs use, from account and community to issuer, track, bot token and seq, each with a link to the page that explains it.
- [Run a Sblurp community](https://sblurp.chat/docs/self-host.md): Run a Sblurp community on your own server: one small program and one data folder. What you need, how to start it, and what it stores.
- [Run a server](https://sblurp.chat/docs/create.md): For developers: start your own Sblurp community. Run the open-source server, join it first to become the owner, then set it up and invite people.
- [Set up a server with AI](https://sblurp.chat/docs/ai.md): Not a developer? Ask an AI assistant such as Claude to set up your Sblurp community server.
- [Sblurp server sizes and costs](https://sblurp.chat/docs/hosting.md): Which server size to rent for a Sblurp community and what it costs each month: measured limits per size and prices at Fly.io, DigitalOcean, Hetzner, OVHcloud and AWS Lightsail.
- [Run Sblurp on Render](https://sblurp.chat/docs/render.md): Run a Sblurp community server on Render: one Starter web service with a persistent disk, the released image, and optional backups to Cloudflare R2.
- [Run Sblurp on Railway](https://sblurp.chat/docs/railway.md): Run a Sblurp community server on Railway: one service from the released image, a volume for /data, and optional backups to Cloudflare R2.
- [Run Sblurp on Fly.io](https://sblurp.chat/docs/fly.md): Run a Sblurp community server on Fly.io: one always-on machine with a volume, h2c streaming, and optional backups to Cloudflare R2.
- [Run Sblurp on any VPS](https://sblurp.chat/docs/vps.md): Run a Sblurp community server on a small virtual server from Hetzner, OVHcloud, Akamai Linode, Vultr, DigitalOcean or any other host, with Docker Compose.
- [Run Sblurp with Docker and Compose](https://sblurp.chat/docs/docker.md): Run a Sblurp community server with Docker Compose and Caddy: the files, the settings, where the data lives, and how to run it behind your own proxy.
- [Run Sblurp with Podman](https://sblurp.chat/docs/podman.md): Run a Sblurp community server with a Podman Quadlet file, with daily automatic updates that roll back when a new image does not start.
- [Sblurp server configuration](https://sblurp.chat/docs/configuration.md): Every flag and environment variable of the Sblurp community server, with defaults, plus the backup variables of the container image and the built-in limits.
- [TLS and reverse proxies for Sblurp](https://sblurp.chat/docs/proxies.md): Put Caddy, nginx or Cloudflare in front of a Sblurp community server without breaking live streams: h2c, no buffering, no compression.
- [Back up a Sblurp server](https://sblurp.chat/docs/backups.md): Back up a Sblurp community server: Litestream copies the database to Cloudflare R2 within 10 seconds, an encrypted backup tool copies the files, or make a plain copy. How to restore.
- [Update a Sblurp server](https://sblurp.chat/docs/updates.md): Release tracks for the Sblurp server image, the daily update check, manual and automatic updates, and how to roll back.
- [Verify a Sblurp release](https://sblurp.chat/docs/provenance.md): Check that a Sblurp server image was built by the public release workflow, with GitHub attestations or cosign.
- [Troubleshooting a Sblurp server](https://sblurp.chat/docs/troubleshooting.md): Fix common problems with a Sblurp community server: sign-in fails, messages arrive late, certificates, file links, and where the logs are.
- [Invites in Sblurp](https://sblurp.chat/docs/invites.md): Make a Sblurp community invite only, create invite links with an expiry and a use limit, and revoke them.
- [Moderation and roles in Sblurp](https://sblurp.chat/docs/moderation.md): Permissions in a Sblurp community (owner, admin, moderator, member), custom roles that limit channels, channel modes, kicks and bans.
- [Safety in Sblurp](https://sblurp.chat/docs/safety.md): Who can read your messages, how to protect your account, what to do about unwanted messages, how to report a message, what moderators can do, age rules, and how to reach sblurp.chat.
- [Your data in Sblurp](https://sblurp.chat/docs/data.md): What sblurp.chat stores about your account, what a community server stores, who controls each, how long data is kept, backups, export and deletion.
- [Sblurp bots](https://sblurp.chat/docs/bots.md): Two ways to add a bot to a Sblurp community: a JavaScript plugin on the server, or a program anywhere that uses the API with a bot token.
- [Sblurp bot tokens](https://sblurp.chat/docs/bot-tokens.md): Make a Sblurp bot with a token, run the example bot, and call the API from any language: subscribe to events and reply to mentions.
- [Connect an AI agent to Sblurp](https://sblurp.chat/docs/agents.md): How to connect a self-hosted AI agent, such as OpenClaw, NanoClaw or Hermes Agent, to a Sblurp community with a bot token. No built-in connector exists yet.
- [Use Sblurp from Claude Code and other MCP clients](https://sblurp.chat/docs/mcp.md): Add a Sblurp community to Claude Code, Claude Desktop, VS Code or another MCP client by URL, sign in with your sblurp.chat account, and let the agent read and post as you.
- [Sblurp plugins](https://sblurp.chat/docs/plugins.md): Write a Sblurp bot as one JavaScript file and install it in the app, with the API or in the plugins folder: hooks for joins, messages, slash commands and timers, replies, limits and the dice example.
- [Sblurp API: protocol and transport](https://sblurp.chat/docs/api.md): How clients and bots talk to a Sblurp community server: Connect RPC over HTTP, the proto contract, JSON and binary bodies, auth, streaming and versioning.
- [Sblurp API explorer](https://sblurp.chat/docs/api/explorer.md): Browse and try every call of the Sblurp community server API in your browser, from the OpenAPI 3.1 description in openapi.json.
- [Sblurp API: sign-in and tokens](https://sblurp.chat/docs/api/auth.md): How sign-in works across Sblurp: OAuth 2.0 with PKCE at sblurp.chat, per-server access tokens, JWT claims, refresh token rotation, JWKS, and bot tokens.
- [Sblurp API: events](https://sblurp.chat/docs/api/events.md): The Sblurp live event stream: Subscribe, sequence numbers, replay and resync, heartbeats, every event kind, who receives it, and unread counts.
- [Sblurp API: uploads and files](https://sblurp.chat/docs/api/files.md): The plain HTTP endpoints of a Sblurp community server: uploads, signed file URLs, custom emoji, invite links and the health check.
- [Sblurp API: errors and rate limits](https://sblurp.chat/docs/api/errors.md): Error codes the Sblurp community server returns, what each one means for a client, and the rate limits for people and bots.
- [ServerService API reference](https://sblurp.chat/docs/api/server-service.md): Every ServerService call of the Sblurp community server: what it does, who may call it, and its request and response fields.
- [ChatService API reference](https://sblurp.chat/docs/api/chat-service.md): Every ChatService call of the Sblurp community server: what it does, who may call it, and its request and response fields.
- [BotService API reference](https://sblurp.chat/docs/api/bot-service.md): Every BotService call of the Sblurp community server: what it does, who may call it, and its request and response fields.
- [API types](https://sblurp.chat/docs/api/types.md): The messages and enums the Sblurp community server API shares between calls, with every field.
