# Strategy Server API

The **Strategy Server** exposes two HTTP-based APIs: a **REST API** for
managing strategies and reading metrics, and a **WebSocket API** for
real-time access to message channels. The CryptoStruct Backend uses both,
and external automation can use them too.

## REST API

The REST API supports:

- Creating and deleting strategy instances.
- Starting and stopping strategy instances.
- Retrieving information about installed strategies.
- Retrieving information about running instances.
- Publishing messages to message channels.
- Reading metrics about strategies, market data, and the JVM.

It's used by the CryptoStruct Backend; custom automation tooling can use
it directly.

### Interactive API explorer

The Strategy Server serves an interactive API explorer in the browser:

```
http://<strategy-server>:8000
```

The explorer shows:

- All endpoints with full documentation.
- Request and response schemas.
- An in-browser request tester.
- Example payloads.

### Common endpoints

{.compact}

| Method                                | Endpoint                                       | Description                  |
|---------------------------------------|------------------------------------------------|------------------------------|
| [!badge variant="success" text="GET"] | `/api/v1/strategy`                             | List installed strategies    |
| [!badge variant="success" text="GET"] | `/api/v1/strategy/instance`                    | List created instances       |
| [!badge variant="success" text="GET"] | `/api/v1/strategy/instance/status`             | Status of all instances      |
| [!badge variant="base" text="POST"]   | `/api/v1/strategy/instance`                    | Create strategy instance     |
| [!badge variant="base" text="POST"]   | `/api/v1/strategy/instance/{instanceId}/start` | Start instance               |
| [!badge variant="base" text="POST"]   | `/api/v1/strategy/instance/{instanceId}/stop`  | Stop instance                |
| [!badge variant="base" text="POST"]   | `/api/v1/strategy/instance/{instanceId}/delete`| Delete instance              |

The full set of endpoints, including bulk operations and reconfigure
operations, is documented in the in-process API explorer.

### Message-channel REST endpoint

REST exposes a single endpoint for broadcasting a message on a channel
from outside:

```bash
curl -X POST "http://localhost:8000/api/v1/channel/testchannel/send?origin=myapplication" \
  -H "accept: application/json" \
  -H "Content-Type: text/plain" \
  -d '{"value":"7.3"}'
```

| Parameter     | Location     | Type   | Description                       |
|---------------|--------------|--------|-----------------------------------|
| `channelName` | URL path     | string | Name of the target channel        |
| `origin`      | Query string | string | Identifier for the message sender |
| Request body  | Body         | string | Plain text message content        |

Use cases:

- Parameter updates to running strategies.
- External signals or alerts.
- Configuration changes.
- Infrequent data feeds.

> [!NOTE]
> REST is not appropriate for high-frequency messaging, and it can't
> deliver messages to an external receiver. For higher rates or to
> consume messages from outside the trading system, use the WebSocket
> API.

## Message-channel WebSocket API

The WebSocket API gives bidirectional, real-time access to message
channels. External applications can:

- Subscribe to channels and receive every message published on them.
- Publish high-frequency data to channels.
- Build custom integrations and monitoring tools.

### Connecting

WebSocket endpoint:

```
ws://<strategy-server>:8000/ws/v1
```

Default port `8000` (shared with REST).

### Requests

Messages from client to server are JSON objects.

#### Login

Required before any other operation.

+++ Request

```json
{
  "op": "login",
  "origin": "my_client"
}
```

{.compact}

| Field    | Type   | Description                                                        |
|----------|--------|--------------------------------------------------------------------|
| `op`     | string | Operation: `"login"`                                               |
| `origin` | string | Unique identifier for this client (will be used as message origin) |

+++ Response (Success)

```json
{
  "op": "login",
  "origin": "my_client",
  "result": "succeed"
}
```

+++ Response (Failure)

```json
{
  "op": "login",
  "origin": "my_client",
  "error": "already logged in"
}
```

+++

#### Subscribe to channel

Subscribe to receive messages published on a channel.

+++ Request

```json
{
  "op": "subscribe",
  "channel": "signal_channel"
}
```

{.compact}

| Field     | Type   | Description              |
|-----------|--------|--------------------------|
| `op`      | string | Operation: `"subscribe"` |
| `channel` | string | Channel name             |

+++ Response (Success)

```json
{
  "op": "subscribe",
  "channel": "signal_channel",
  "result": "succeed"
}
```

+++ Response (Failure)

```json
{
  "op": "subscribe",
  "channel": "signal_channel",
  "error": "not logged in"
}
```

+++

> [!NOTE]
> Subscription succeeds even if the channel doesn't exist yet. Messages
> arrive once a strategy opens it.

#### Unsubscribe from channel

Stop receiving messages from a channel.

+++ Request

```json
{
  "op": "unsubscribe",
  "channel": "signal_channel"
}
```

{.compact}

| Field     | Type   | Description                |
|-----------|--------|----------------------------|
| `op`      | string | Operation: `"unsubscribe"` |
| `channel` | string | Channel name               |

+++ Response (Success)

```json
{
  "op": "unsubscribe",
  "channel": "signal_channel",
  "result": "succeed"
}
```

+++

#### Publish message

Broadcast a message on a channel.

+++ Request

```json
{
  "op": "publish",
  "channel": "signal_channel",
  "message": "Hello, strategies!"
}
```

{.compact}

| Field     | Type   | Description                  |
|-----------|--------|------------------------------|
| `op`      | string | Operation: `"publish"`       |
| `channel` | string | Channel name                 |
| `message` | string | Message content (any string) |

+++ Response (Failure)

```json
{
  "op": "publish",
  "channel": "signal_channel",
  "error": "not logged in"
}
```

+++

> [!NOTE]
> Publishing succeeds even when no strategies are listening. Successful
> publishes do not produce a response.

### Events

Messages from server to client.

#### Event message

Sent when a message is published on a subscribed channel.

```json
{
  "op": "event",
  "channel": "signal_channel",
  "origin": "strategy_instance_1",
  "message": "Signal data here"
}
```

{.compact}

| Field     | Type   | Description                                              |
|-----------|--------|----------------------------------------------------------|
| `op`      | string | Operation: `"event"`                                     |
| `channel` | string | Channel name                                             |
| `origin`  | string | Message sender (strategy instance name or client origin) |
| `message` | string | Message content                                          |

> [!NOTE]
> Clients never receive their own published messages.

#### Error message

Sent when the client sends an invalid message.

```json
{
  "op": "error",
  "channel": "signal_channel",
  "error": "invalid json"
}
```

{.compact}

| Field     | Type   | Description                  |
|-----------|--------|------------------------------|
| `op`      | string | Operation: `"error"`         |
| `channel` | string | Channel name (if applicable) |
| `error`   | string | Error description            |

## Kafka integration

Channels can be wired to Kafka topics for advanced use cases.

### Configuration

Configure Kafka in the Strategy Server config file:

```json
{
  "kafka_servers": [
    "broker1:9092",
    "broker2:9092"
  ],
  "kafka_stop_on_error": true,
  "kafka_topics": [
    "readOnlyTopic:r",
    "writeOnlyTopic:w",
    "readWriteTopic:rw",
    "defaultTopic"
  ]
}
```

Configuration fields:

{.compact}

| Field                 | Description                                     |
|-----------------------|-------------------------------------------------|
| `kafka_servers`       | List of Kafka broker addresses                  |
| `kafka_stop_on_error` | If true, stop strategies on Kafka write failure |
| `kafka_topics`        | List of topics with permissions                 |

Topic permissions:

- `r`: read-only (consume from Kafka).
- `w`: write-only (produce to Kafka, default).
- `rw`: read and write.

### Channel data types

For writing to Kafka:

- Channel type must be `String` or `KafkaMessage`.
- `String` channels: record key is the process ID (or `null` if
  disabled).
- `KafkaMessage` channels: key and value are specified explicitly.

For reading from Kafka:

- Channel type must be `KafkaMessage`.

### Kafka record headers

Every record written to Kafka carries:

| Header          | Description                                           |
|-----------------|-------------------------------------------------------|
| `CS_ORIGIN`     | Message origin (strategy instance name or API client) |
| `CS_PROCESS_ID` | Strategy Server process ID                            |

### KafkaMessage type

For programmatic access from a strategy, see
[SDK - Message Channels](../strategy-development/message-channels.md).

## See also

- [Strategy Server Overview](strategy-server). Architecture and
  deployment.
- [SDK - Message Channels](../strategy-development/message-channels.md).
  Using message channels from strategies.
- [System Architecture](../getting-started/system.md). Understanding the
  trading system.
