blob: 5a9687c61c8530910bfb5879a08fa71ee0876f67 [file]
---
title: Commands
---
## Catalog
The u32 command codes. Replicated commands are identified on the wire by their `operation` byte (see [Operation discriminants](/docs/binary-protocol/framing#operation-discriminants)). The code column below is the protocol-level registry and, for non-replicated commands, the value carried in header bytes 196..200.
```bash
# System
PING = 1 # non-replicated; works without login
GET_STATS = 10 # non-replicated
GET_SNAPSHOT = 11 # non-replicated
GET_CLUSTER_METADATA = 12 # non-replicated
DESCRIBE_OPTIONS = 13 # non-replicated
GET_ME = 20 # non-replicated
GET_CLIENT = 21 # non-replicated
GET_CLIENTS = 22 # non-replicated
# Users
GET_USER = 31 # non-replicated
GET_USERS = 32 # non-replicated
CREATE_USER = 33 # operation 141
DELETE_USER = 34 # operation 143
UPDATE_USER = 35 # operation 142
UPDATE_PERMISSIONS = 36 # operation 145
CHANGE_PASSWORD = 37 # operation 144
LOGIN_USER = 38 # legacy; server rejects with MalformedLogin eviction
LOGOUT_USER = 39 # operation 3 (Logout)
LOGIN_REGISTER = 40 # operation 1 (Register)
LOGIN_REGISTER_WITH_PAT = 45 # operation 1 (Register)
# Personal access tokens
GET_PERSONAL_ACCESS_TOKENS = 41 # non-replicated
CREATE_PERSONAL_ACCESS_TOKEN = 42 # operation 146
DELETE_PERSONAL_ACCESS_TOKEN = 43 # operation 147
LOGIN_WITH_PERSONAL_ACCESS_TOKEN = 44 # legacy; server rejects with MalformedLogin eviction
# Messages
POLL_MESSAGES = 100 # non-replicated
SEND_MESSAGES = 101 # operation 160
FLUSH_UNSAVED_BUFFER = 102 # parses, but always fails with FeatureUnavailable
# Consumer offsets
GET_CONSUMER_OFFSET = 120 # non-replicated
STORE_CONSUMER_OFFSET = 121 # operation 161
DELETE_CONSUMER_OFFSET = 122 # operation 162
# Streams
GET_STREAM = 200 # non-replicated
GET_STREAMS = 201 # non-replicated
CREATE_STREAM = 202 # operation 128
DELETE_STREAM = 203 # operation 130
UPDATE_STREAM = 204 # operation 129
PURGE_STREAM = 205 # operation 131
# Topics
GET_TOPIC = 300 # non-replicated
GET_TOPICS = 301 # non-replicated
CREATE_TOPIC = 302 # operation 132
DELETE_TOPIC = 303 # operation 134
UPDATE_TOPIC = 304 # operation 133
PURGE_TOPIC = 305 # operation 135
# Partitions
CREATE_PARTITIONS = 402 # operation 136
DELETE_PARTITIONS = 403 # operation 137
# Segments
DELETE_SEGMENTS = 503 # operation 138
# Consumer groups
GET_CONSUMER_GROUP = 600 # non-replicated
GET_CONSUMER_GROUPS = 601 # non-replicated
CREATE_CONSUMER_GROUP = 602 # operation 139
DELETE_CONSUMER_GROUP = 603 # operation 140
JOIN_CONSUMER_GROUP = 604 # operation 148
LEAVE_CONSUMER_GROUP = 605 # operation 149
SYNC_CONSUMER_GROUP = 606 # non-replicated
```
`FLUSH_UNSAVED_BUFFER` still decodes on the wire, but the server has no on-demand flush primitive and answers every call with `FeatureUnavailable`. Per-topic durability is configured with the `enforce_fsync` [topic option](/docs/server/topic-options) instead.
## Payloads
Payloads below are the request **body** (the bytes after the 256-byte header). Types reference the [shared encodings](/docs/binary-protocol/encodings). Empty payload means the body has zero bytes.
### System
**Ping. Code: 1.** Empty payload. The only command accepted before login.
**Get stats. Code: 10.** Empty payload.
**Get snapshot. Code: 11.**
```text
[compression: u8][types_count: u8][snapshot_type: u8] x types_count
```
Compression codes: 1 = Stored, 2 = Deflated, 3 = Bzip2, 4 = Zstd, 5 = Lzma, 6 = Xz. Snapshot type codes: 1 = FilesystemOverview, 2 = ProcessList, 3 = ResourceUsage, 4 = Test, 5 = ServerLogs, 6 = ServerConfig, 100 = All.
**Get cluster metadata. Code: 12.** Empty payload.
**Describe options. Code: 13.**
```text
[scope: u8]
```
Scope: 1 = topic, 2 = stream, 3 = user. Returns the option catalog for the scope: keys, value kinds, defaults, and descriptions. See [Options block](/docs/binary-protocol/encodings#options-block).
**Get me. Code: 20.** Empty payload.
**Get client. Code: 21.**
```text
[client_id: u32]
```
**Get clients. Code: 22.** Empty payload.
### Streams
**Get stream. Code: 200.**
```text
[stream_id: Identifier]
```
**Get streams. Code: 201.** Empty payload.
**Create stream. Code: 202.**
```text
[name_len: u8][name: N][options block to end]
```
The stream option catalog is empty today, so the block is normally empty (zero bytes).
**Delete stream. Code: 203.**
```text
[stream_id: Identifier]
```
**Update stream. Code: 204.**
```text
[stream_id: Identifier][name_len: u8][name: N][options block to end]
```
Patch semantics: absent option keys are left unchanged.
**Purge stream. Code: 205.**
```text
[stream_id: Identifier]
```
### Topics
**Get topic. Code: 300.**
```text
[stream_id: Identifier][topic_id: Identifier]
```
**Get topics. Code: 301.**
```text
[stream_id: Identifier]
```
**Create topic. Code: 302.**
```text
[stream_id: Identifier][partitions_count: u32][name_len: u8][name: N][options block to end]
```
The fixed fields are the shape of the operation: which stream, how many partitions, what name. Every topic setting (`compression_algorithm`, `message_expiry`, `max_topic_size`, `segment_size`, `enforce_fsync`, `messages_required_to_save`, `size_of_messages_required_to_save`, `preallocate_segments`) rides the options block. See [Topic options](/docs/server/topic-options). `partitions_count` is an argument, not a setting: it is consumed at admission and never persisted as an option.
**Delete topic. Code: 303.**
```text
[stream_id: Identifier][topic_id: Identifier]
```
**Update topic. Code: 304.**
```text
[stream_id: Identifier][topic_id: Identifier][name_len: u8][name: N][options block to end]
```
Only `compression_algorithm`, `message_expiry`, and `max_topic_size` are updatable. Absent keys are left unchanged.
**Purge topic. Code: 305.**
```text
[stream_id: Identifier][topic_id: Identifier]
```
### Partitions
**Create partitions. Code: 402.**
```text
[stream_id: Identifier][topic_id: Identifier][partitions_count: u32]
```
**Delete partitions. Code: 403.**
```text
[stream_id: Identifier][topic_id: Identifier][partitions_count: u32]
```
### Segments
**Delete segments. Code: 503.**
```text
[stream_id: Identifier][topic_id: Identifier][partition_id: u32][segments_count: u32]
```
Deletes the `segments_count` oldest sealed segments of the partition.
### Messages
**Poll messages. Code: 100.**
```text
[consumer: Consumer][stream_id: Identifier][topic_id: Identifier]
[partition_flag: u8][partition_id: u32]
[strategy: 9 bytes][count: u32][auto_commit: u8]
```
`strategy` is a [polling strategy](/docs/binary-protocol/encodings#polling-strategy). `count` is the requested number of messages. `auto_commit = 1` stores the consumer offset server-side as part of the poll.
The response body:
```text
[partition_id: u32][current_offset: u64][messages_count: u32]
[batch records to end]
```
The 16-byte prefix is followed by a stream of [batch records](/docs/binary-protocol/messages) served as stored: each record's header carries the stamped `base_offset` and `base_timestamp`, and each frame's deltas resolve against them. A record may be a server-sliced view of a larger stored batch, so the first polled offset is `base_offset + offset_delta` of the first frame, not necessarily `base_offset` itself. `current_offset` is the partition's newest offset at poll time.
**Send messages. Code: 101.**
```text
[metadata_length: u32]
[stream_id: Identifier][topic_id: Identifier][partitioning: Partitioning]
[messages_count: u32]
[batch: 256-byte batch header + frames]
```
`metadata_length` counts the bytes from `stream_id` through `messages_count` inclusive, so a reader can skip straight to the batch. The producer leaves `partition_id`, `base_offset`, and `base_timestamp` zero in the [batch header](/docs/binary-protocol/messages), and the server stamps them. Every checksum is producer-computed and verified at admission. The reserved regions must be zero.
**Flush unsaved buffer. Code: 102.**
```text
[stream_id: Identifier][topic_id: Identifier][partition_id: u32][fsync: u8]
```
Parses, but the server always answers `FeatureUnavailable`: there is no on-demand flush primitive. Use the per-topic `enforce_fsync` option for durability guarantees.
### Consumer offsets
**Get consumer offset. Code: 120.**
```text
[consumer: Consumer][stream_id: Identifier][topic_id: Identifier]
[partition_flag: u8][partition_id: u32]
```
Response body (20 bytes):
```text
[partition_id: u32][current_offset: u64][stored_offset: u64]
```
**Store consumer offset. Code: 121.**
```text
[consumer: Consumer][stream_id: Identifier][topic_id: Identifier]
[partition_flag: u8][partition_id: u32][offset: u64][ack: u8]
```
**Delete consumer offset. Code: 122.**
```text
[consumer: Consumer][stream_id: Identifier][topic_id: Identifier]
[partition_flag: u8][partition_id: u32][ack: u8]
```
The trailing `ack` byte is mandatory on both write commands. A payload without it fails to decode. Ack levels:
| Value | Level | Meaning |
|-------|-------|---------|
| 0 | `NoAck` | Leader-local write; respond as soon as local state is updated (the fast path `PollMessages` auto-commit uses) |
| 1 | `Quorum` | Replicate through partition consensus; respond after a quorum commit (default for explicit writes) |
### Consumer groups
**Get consumer group. Code: 600.**
```text
[stream_id: Identifier][topic_id: Identifier][group_id: Identifier]
```
**Get consumer groups. Code: 601.**
```text
[stream_id: Identifier][topic_id: Identifier]
```
**Create consumer group. Code: 602.**
```text
[stream_id: Identifier][topic_id: Identifier][name_len: u8][name: N]
```
**Delete consumer group. Code: 603.**
```text
[stream_id: Identifier][topic_id: Identifier][group_id: Identifier]
```
**Join consumer group. Code: 604.**
```text
[stream_id: Identifier][topic_id: Identifier][group_id: Identifier]
```
**Leave consumer group. Code: 605.**
```text
[stream_id: Identifier][topic_id: Identifier][group_id: Identifier]
```
**Sync consumer group. Code: 606.**
```text
[stream_id: Identifier][topic_id: Identifier][group_id: Identifier]
```
Read-only: a member asks for its current partition assignment and the group generation, so it can select partitions to poll client-side.
### Users
**Get user. Code: 31.**
```text
[user_id: Identifier]
```
**Get users. Code: 32.** Empty payload.
**Create user. Code: 33.**
```text
[username_len: u8][username: N][password_len: u8][password: N][status: u8]
[has_permissions: u8][permissions_len: u32, only when has_permissions = 1][permissions: M bytes]
[options block to end]
```
`permissions_len` and the permissions bytes are present **only** when `has_permissions = 1`. When it is 0 the options block follows immediately. The user option catalog is empty today, so the block is normally empty. `status`: 1 = active, 2 = inactive.
**Delete user. Code: 34.**
```text
[user_id: Identifier]
```
**Update user. Code: 35.**
```text
[user_id: Identifier]
[has_username: u8][username_len: u8, only when 1][username: N, only when 1]
[has_status: u8][status: u8, only when 1]
[options block to end]
```
**Update permissions. Code: 36.**
```text
[user_id: Identifier][has_permissions: u8]
[permissions_len: u32, only when has_permissions = 1][permissions: M bytes, only when 1]
```
As in `CreateUser`, the length field is conditional: with `has_permissions = 0` the payload ends at the flag.
**Change password. Code: 37.**
```text
[user_id: Identifier]
[current_password_len: u8][current_password: N]
[new_password_len: u8][new_password: N]
```
### Authentication
Login and logout are part of the [connection lifecycle](/docs/binary-protocol/connection-lifecycle):
- **Login register. Code: 40.** `Operation::Register`. The body is `ClientVersionInfo` + credentials, described in [Login-register](/docs/binary-protocol/connection-lifecycle#login-register).
- **Login register with PAT. Code: 45.** `Operation::Register`. The body is `ClientVersionInfo` + token.
- **Logout user. Code: 39.** `Operation::Logout`. Empty payload.
- Codes **38** and **44** are the pre-register login shapes. The server rejects both with a `MalformedLogin` eviction.
### Personal access tokens
**Get personal access tokens. Code: 41.** Empty payload.
**Create personal access token. Code: 42.**
```text
[name_len: u8][name: N][expiry: u64]
```
`expiry` is a duration in **microseconds**. Two sentinel values exist: `0` (server default, which currently means no expiry) and `u64::MAX` (never expires).
**Delete personal access token. Code: 43.**
```text
[name_len: u8][name: N]
```