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
paramsobjectNoOperation parameters

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",
"wal_offset": 12345
}
}
FieldTypeDescription
typestringAlways "response"
idstringMatches request id
statusstring"ok" for success
resultobjectOperation result
metaobjectResponse metadata

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
error.messagestringHuman-readable description
error.retryablebooleanWhether retry may succeed
error.detailsobjectAdditional error context

Event Messages

Sent asynchronously for active subscriptions:

{
"type": "event",
"subscription_id": "sub-123",
"event": {
"instance_id": "order-001",
"machine": "order",
"version": 1,
"event": "PAY",
"from_state": "pending",
"to_state": "paid",
"payload": {"amount": 99.99},
"timestamp": "2024-01-15T10:30:00Z",
"wal_offset": 12345
}
}
FieldTypeDescription
typestringAlways "event"
subscription_idstringSubscription identifier
eventobjectEvent details

Detailed Operation Messages

HELLO

Request:

{
"type": "request",
"id": "1",
"op": "HELLO",
"params": {
"protocol_version": 1,
"client_name": "my-app",
"client_version": "1.0.0"
}
}

Response:

{
"type": "response",
"id": "1",
"status": "ok",
"result": {
"protocol_version": 1,
"server_version": "0.1.0",
"auth_required": false,
"features": ["subscriptions", "batch"]
}
}

AUTH

Request:

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

Response:

{
"type": "response",
"id": "2",
"status": "ok",
"result": {
"authenticated": true
}
}

PUT_MACHINE

Request:

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

Response:

{
"type": "response",
"id": "3",
"status": "ok",
"result": {
"name": "order",
"version": 1,
"created": true
}
}

CREATE_INSTANCE

Request:

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

Response:

{
"type": "response",
"id": "4",
"status": "ok",
"result": {
"id": "order-001",
"machine": "order",
"version": 1,
"state": "pending",
"context": {"customer": "alice"},
"created": true
}
}

APPLY_EVENT

Request:

{
"type": "request",
"id": "5",
"op": "APPLY_EVENT",
"params": {
"instance_id": "order-001",
"event": "PAY",
"payload": {"amount": 99.99},
"idempotency_key": "pay-order-001"
}
}

Response:

{
"type": "response",
"id": "5",
"status": "ok",
"result": {
"previous_state": "pending",
"current_state": "paid",
"transition": {
"from": "pending",
"event": "PAY",
"to": "paid"
}
},
"meta": {
"wal_offset": 12345
}
}

WATCH_ALL

Request:

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

Response:

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

Subsequent events:

{
"type": "event",
"subscription_id": "sub-abc123",
"event": {
"instance_id": "order-001",
"event": "SHIP",
"from_state": "paid",
"to_state": "shipped",
"timestamp": "2024-01-15T10:30:00Z"
}
}

BATCH

Request:

{
"type": "request",
"id": "7",
"op": "BATCH",
"params": {
"mode": "atomic",
"operations": [
{
"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": {"current_state": "paid"}},
{"status": "ok", "result": {"current_state": "paid"}}
]
}
}

Request ID Requirements

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