> ## Documentation Index
> Fetch the complete documentation index at: https://docs.roxom.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Account Updates

> Subscribe to authenticated WebSocket channels for real-time order, balance, and position updates.

## Overview

Receive real-time updates for your account activity through authenticated WebSocket connections. After connecting with valid API credentials, subscribe to the private channels you need (`orders`, `balance`, `positions`).

<Warning>
  Account update streams require authentication and explicit subscription. Include valid API credentials in the WebSocket connection headers (`X-API-Key` and `X-API-Signature`).
</Warning>

## Available private streams

<CardGroup cols={2}>
  <Card title="Order Updates" icon="list-check" href="/websockets/account-updates/orders">
    Real-time order status changes and fills
  </Card>

  <Card title="Balance Updates" icon="wallet" href="/websockets/account-updates/balance">
    Account balance changes from trades and transfers
  </Card>

  <Card title="Position Updates" icon="chart-area" href="/websockets/account-updates/positions">
    Position changes and profit/loss updates
  </Card>
</CardGroup>

## Stream types overview

| Channel     | Description                    | Auto-Enabled     | Authentication |
| ----------- | ------------------------------ | ---------------- | -------------- |
| `orders`    | Order status changes and fills | ❌ No (subscribe) | Required       |
| `balance`   | Account balance updates        | ❌ No (subscribe) | Required       |
| `positions` | Position changes and PnL       | ❌ No (subscribe) | Required       |
| `account`   | Account-level notifications    | ❌ No (subscribe) | Required       |

<Warning>
  **Important Account Event Behavior**: When authenticated, account-related events (`orders`, `positions`, `balance`) are delivered to **all WebSocket connections for your account** regardless of individual channel subscriptions.

  For example, if you subscribe only to `orders` but place a trade that affects your position and balance, you will receive:

  * Order update events (subscribed)
  * Position update events (auto-delivered)
  * Balance update events (auto-delivered)

  This ensures you don't miss critical account changes. Filter events client-side using the `"type"` field if you need specific event types only.

  **Example**: Subscribing only to `orders` but placing a trade will generate:

  ```json theme={null}
  // Order event (subscribed)
  {"type": "order", "data": {"orderId": "...", "status": "filled", ...}}

  // Position event (auto-delivered) 
  {"type": "position", "data": [{"id": "...", "size": "22.00", ...}]}

  // Balance event (auto-delivered)
  {"type": "balance", "data": {"amount": "-0.00004905", ...}}
  ```
</Warning>

## Quick start

### Authenticated connection setup

```javascript theme={null}
// Generate RSA signature for WebSocket connection
// Payload for WebSocket connection is always: "GET:/ws"
const signature = generateRSASignature(privateKey, 'GET:/ws');

const ws = new WebSocket('wss://ws.roxom.com/ws', [], {
  headers: {
    'X-API-Key': 'your-api-key',
    'X-API-Signature': signature
  }
});

ws.onopen = () => {
  ws.send(JSON.stringify({
    op: 'subscribe',
    args: [ { channel: 'orders' }, { channel: 'positions' }, { channel: 'balance' } ]
  }));
};

ws.onmessage = (event) => {
      const data = JSON.parse(event.data);
  
  if (data.event === 'subscribe') return; // subscription ack
  if (data.data && data.data.type === 'order') handleOrderUpdate(data.data);
  if (data.data && data.data.type === 'position') handlePositionUpdate(data.data);
  if (data.data && data.data.type === 'balance') handleBalanceUpdate(data.data);
};
```

### RSA signature generation

The WebSocket connection requires an RSA signature of the payload `GET:/ws` using your private key:

```javascript theme={null}
function generateRSASignature(privateKey, payload = 'GET:/ws') {
  const crypto = require('crypto');
  const sign = crypto.createSign('SHA256');
  sign.update(payload);
  return sign.sign(privateKey, 'base64');
}

// Example usage
const fs = require('fs');
const privateKey = fs.readFileSync('path/to/your/private-key.pem', 'utf8');
const signature = generateRSASignature(privateKey);
```

### Python RSA signature generation

```python theme={null}
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
import base64

def generate_rsa_signature(private_key_path: str, payload: str = 'GET:/ws') -> str:
    # Load private key
    with open(private_key_path, 'rb') as key_file:
        private_key = serialization.load_pem_private_key(
            key_file.read(),
            password=None
        )
    
    # Sign the payload
    signature = private_key.sign(
        payload.encode('utf-8'),
        padding.PKCS1v15(),
        hashes.SHA256()
    )
    
    # Return base64 encoded signature
    return base64.b64encode(signature).decode('utf-8')

# Example usage
signature = generate_rsa_signature('path/to/your/private-key.pem')
```

### Go RSA signature generation

```go theme={null}
package main

import (
    "crypto"
    "crypto/rand"
    "crypto/rsa"
    "crypto/sha256"
    "crypto/x509"
    "encoding/base64"
    "encoding/pem"
    "io/ioutil"
)

func generateRSASignature(privateKeyPath string, payload string) (string, error) {
    // Default payload for WebSocket connection
    if payload == "" {
        payload = "GET:/ws"
    }
    
    // Load private key
    keyData, err := ioutil.ReadFile(privateKeyPath)
    if err != nil {
        return "", err
    }
    
    block, _ := pem.Decode(keyData)
    privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
    if err != nil {
        return "", err
    }
    
    // Hash the payload
    hash := sha256.Sum256([]byte(payload))
    
    // Sign the hash
    signature, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, hash[:])
    if err != nil {
        return "", err
    }
    
    // Return base64 encoded signature
    return base64.StdEncoding.EncodeToString(signature), nil
}
```

## Message format

All account update messages follow a consistent structure:

```json theme={null}
{
  "type": "order|balance|position|account",
  "data": {
    "accountId": "01234567-89ab-7def-8123-456789abcdef",
    // Type-specific data fields
    "timestamp": 1640995200000000000
  }
}
```

## Common use cases

<AccordionGroup>
  <Accordion title="Order Management Systems">
    Monitor order fills, cancellations, and rejections in real-time to maintain accurate order state and trigger appropriate business logic.
  </Accordion>

  <Accordion title="Risk Management">
    Track position changes and unrealized P\&L to implement stop-loss mechanisms and position size limits.
  </Accordion>

  <Accordion title="Portfolio Monitoring">
    Real-time balance updates enable dynamic portfolio rebalancing and cash management strategies.
  </Accordion>

  <Accordion title="Algorithmic Trading">
    Use order and position updates to trigger next steps in multi-leg trading strategies and complex order workflows.
  </Accordion>
</AccordionGroup>

## Error handling

<AccordionGroup>
  <Accordion title="Authentication Failed">
    **Cause**: Invalid API credentials or signature

    **Solution**:

    * Verify API key is correct and active
    * Check RSA signature generation using correct payload ("GET:/ws")
    * Ensure private key matches the public key associated with your API key
  </Accordion>

  <Accordion title="Connection Timeout">
    **Cause**: Network or server connectivity issues

    **Solution**:

    * Implement reconnection logic with exponential backoff
    * Monitor connection health with heartbeat
    * Handle reconnection state recovery
  </Accordion>

  <Accordion title="Rate Limiting">
    **Cause**: Too many connection attempts

    **Solution**:

    * Use single connection per application
    * Implement connection pooling
    * Add delays between reconnection attempts
  </Accordion>
</AccordionGroup>

## Best practices

<AccordionGroup>
  <Accordion title="State Management">
    * Maintain local copies of order and position state
    * Handle message ordering and potential duplicates
    * Implement proper state reconciliation on reconnection
    * Use message timestamps for event sequencing
  </Accordion>

  <Accordion title="Performance Optimization">
    * Process updates asynchronously to avoid blocking
    * Batch UI updates for high-frequency streams
    * Implement efficient data structures for tracking
    * Monitor memory usage for long-running connections
  </Accordion>

  <Accordion title="Reliability">
    * Implement comprehensive error handling
    * Log all account events for audit trails
    * Use heartbeat monitoring for connection health
    * Plan for graceful degradation during outages
  </Accordion>
</AccordionGroup>

## Authentication requirements

To access private account streams, you need:

1. **Valid API Credentials**: Active API key with appropriate permissions
2. **Proper Signature**: RSA signature of the payload "GET:/ws" using your private key
3. **Correct Headers**: Both `X-API-Key` and `X-API-Signature` headers included

See the [Authentication Guide](/api-reference/authentication) for detailed setup instructions.

## Next steps

* Set up [Connection Authentication](/websockets/connection) for private streams
* Learn about specific [Order Update](/websockets/account-updates/orders) message formats
* Explore [Balance Update](/websockets/account-updates/balance) tracking strategies
* Review [Position Update](/websockets/account-updates/positions) monitoring techniques
