Skip to main content

Message Types

This document describes all message types in the RCP protocol.

Request Messages

Common Fields

All requests have these fields:

{
"type": "request",
"id": "unique-id",
"op": "OPERATION_NAME",
"params": { /* operation-specific */ }
}
FieldTypeRequiredDescription
typestringYesAlways "request"
idstringYesUnique request identifier
opstringYesOperation name (SCREAMING_SNAKE_CASE)
paramsobjectNoOperation parameters (defaults to {})

Operation List

OperationDescription
HELLOProtocol handshake
AUTHAuthenticate with token
PINGHealth check
BYEGraceful disconnect
INFOServer information
PUT_MACHINERegister machine definition
GET_MACHINEGet machine definition
LIST_MACHINESList all machines
CREATE_INSTANCECreate instance
GET_INSTANCEGet instance
LIST_INSTANCESList instances
DELETE_INSTANCEDelete instance
APPLY_EVENTApply event to instance
BATCHBatch operations
WATCH_INSTANCESubscribe to instance
WATCH_ALLSubscribe to all events
UNWATCHCancel subscription
SNAPSHOT_INSTANCECreate instance snapshot
WAL_READRead WAL entries
WAL_STATSGet WAL statistics
COMPACTTrigger compaction

Response Messages

Success Response

{
"type": "response",
"id": "matching-request-id",
"status": "ok",
"result": { /* operation result */ },
"meta": {
"server_time": "2024-01-15T10:30:00Z",
"leader": true,
"wal_offset": 12345,
"trace_id": "abc-123"
}
}
FieldTypeDescription
typestringAlways "response"
idstringMatches request id
statusstring"ok" for success
resultobjectOperation result
metaobjectResponse metadata (optional, omitted if empty)

Error Response

{
"type": "response",
"id": "matching-request-id",
"status": "error",
"error": {
"code": "ERROR_CODE",
"message": "Human-readable message",
"retryable": false,
"details": {}
}
}
FieldTypeDescription
error.codestringMachine-readable error code (SCREAMING_SNAKE_CASE)
error.messagestringHuman-readable description
error.retryablebooleanWhether retry may succeed
error.detailsobjectAdditional error context

Event Messages

Sent asynchronously for active subscriptions. Event fields are top-level (not nested inside an event object):

{
"type": "event",
"subscription_id": "sub-123",
"instance_id": "order-001",
"machine": "order",
"version": 1,
"event": "PAY",
"from_state": "pending",
"to_state": "paid",
"payload": {"amount": 99.99},
"ctx": {"customer": "alice", "amount": 99.99},
"wal_offset": 12345
}
FieldTypeDescription
typestringAlways "event"
subscription_idstringSubscription identifier
instance_idstringAffected instance
machinestringMachine name
versionintegerMachine version
eventstringEvent name that triggered the transition
from_statestringState before transition
to_statestringState after transition
payloadobjectEvent payload (null if absent)
ctxobjectInstance context after transition (only if include_ctx: true)
wal_offsetintegerWAL offset of this event

Detailed Operation Messages

HELLO

Request:

{
"type": "request",
"id": "1",
"op": "HELLO",
"params": {
"protocol_version": 1,
"client_name": "my-app",
"wire_modes": ["binary_json", "jsonl"],
"features": ["idempotency", "batch", "wal_read"]
}
}

Response:

{
"type": "response",
"id": "1",
"status": "ok",
"result": {
"protocol_version": 1,
"wire_mode": "binary_json",
"server_name": "rstmdb",
"server_version": "0.1.1",
"features": ["idempotency", "batch", "wal_read"]
}
}
  • wire_modes is a priority-ordered list; the server picks the first supported mode.
  • features are intersection-negotiated (server returns supported subset).

AUTH

Request:

{
"type": "request",
"id": "2",
"op": "AUTH",
"params": {
"method": "bearer",
"token": "secret-token"
}
}

Response:

{
"type": "response",
"id": "2",
"status": "ok",
"result": {
"authenticated": true
}
}
  • Only "bearer" method is currently supported.

PUT_MACHINE

Request:

{
"type": "request",
"id": "3",
"op": "PUT_MACHINE",
"params": {
"machine": "order",
"version": 1,
"definition": {
"states": ["pending", "paid", "shipped"],
"initial": "pending",
"transitions": [
{"from": "pending", "event": "PAY", "to": "paid"},
{"from": "paid", "event": "SHIP", "to": "shipped"}
]
},
"checksum": "optional-sha256-hex"
}
}

Response:

{
"type": "response",
"id": "3",
"status": "ok",
"result": {
"machine": "order",
"version": 1,
"stored_checksum": "a1b2c3...",
"created": true
}
}
  • created: false when re-submitting an identical definition (idempotent).

CREATE_INSTANCE

Request:

{
"type": "request",
"id": "4",
"op": "CREATE_INSTANCE",
"params": {
"instance_id": "order-001",
"machine": "order",
"version": 1,
"initial_ctx": {"customer": "alice"},
"idempotency_key": "create-order-001"
}
}

Response:

{
"type": "response",
"id": "4",
"status": "ok",
"result": {
"instance_id": "order-001",
"state": "pending",
"wal_offset": 1
}
}
  • instance_id is optional — a UUID v4 is auto-generated if omitted.
  • initial_ctx is optional (defaults to {}).

APPLY_EVENT

Request:

{
"type": "request",
"id": "5",
"op": "APPLY_EVENT",
"params": {
"instance_id": "order-001",
"event": "PAY",
"payload": {"amount": 99.99},
"expected_state": "pending",
"expected_wal_offset": 1,
"event_id": "evt-unique-id",
"idempotency_key": "pay-order-001"
}
}

Response:

{
"type": "response",
"id": "5",
"status": "ok",
"result": {
"from_state": "pending",
"to_state": "paid",
"ctx": {
"customer": "alice",
"amount": 99.99
},
"wal_offset": 5,
"applied": true,
"event_id": "evt-unique-id"
}
}
  • applied: false means the event was a duplicate idempotency key replay.
  • expected_state and expected_wal_offset enable optimistic concurrency.

WATCH_ALL

Request:

{
"type": "request",
"id": "6",
"op": "WATCH_ALL",
"params": {
"machines": ["order"],
"to_states": ["shipped", "delivered"],
"include_ctx": true,
"from_offset": 0
}
}

Response:

{
"type": "response",
"id": "6",
"status": "ok",
"result": {
"subscription_id": "sub-abc123",
"wal_offset": 42
}
}

Subsequent events (top-level fields, not nested):

{
"type": "event",
"subscription_id": "sub-abc123",
"instance_id": "order-001",
"machine": "order",
"version": 1,
"event": "SHIP",
"from_state": "paid",
"to_state": "shipped",
"payload": {},
"ctx": {"customer": "alice", "amount": 99.99},
"wal_offset": 43
}

BATCH

Request:

{
"type": "request",
"id": "7",
"op": "BATCH",
"params": {
"mode": "best_effort",
"ops": [
{
"op": "APPLY_EVENT",
"params": {"instance_id": "order-001", "event": "PAY"}
},
{
"op": "APPLY_EVENT",
"params": {"instance_id": "order-002", "event": "PAY"}
}
]
}
}

Response:

{
"type": "response",
"id": "7",
"status": "ok",
"result": {
"results": [
{"status": "ok", "result": {"from_state": "pending", "to_state": "paid", "ctx": {}, "wal_offset": 10, "applied": true}},
{"status": "ok", "result": {"from_state": "pending", "to_state": "paid", "ctx": {}, "wal_offset": 11, "applied": true}}
]
}
}
  • Batch operations array field is ops (not operations).
  • Max ops per batch: 100 (server default).

Request ID Requirements

  • Must be unique per connection
  • Maximum length: 256 bytes
  • Recommended format: sequential integers or UUIDs
  • Reusing IDs may cause undefined behavior