SINAI STANDARD

Real-Time Monitoring

Stream compliance events in real time over WebSocket

Real-Time Monitoring

The Oracle provides a WebSocket endpoint for streaming compliance events in real time. Use it for dashboards, alerting, and live monitoring.

Connection

Connect to the WebSocket server at ws://host:port/ws:

const ws = new WebSocket("ws://localhost:3000/ws");
 
ws.onopen = () => {
  // Subscribe to specific event patterns
  ws.send(JSON.stringify({
    subscribe: ["transfer.*", "wallet.*"],
  }));
};
 
ws.onmessage = (msg) => {
  const event = JSON.parse(msg.data);
  console.log(event.type, event.mint, event.data);
};

Subscription Filters

Send a subscribe message to filter which events you receive:

ws.send(JSON.stringify({
  subscribe: ["transfer.executed", "wallet.*", "*"],
}));
 
// Server confirms:
// { "subscribed": ["transfer.executed", "wallet.*", "*"] }
PatternMatches
"transfer.executed"Exact match only
"transfer.*"All transfer events (transfer.executed, transfer.blocked)
"wallet.*"All wallet events (wallet.verified, wallet.removed)
"*"All events

Multiple filters are OR'd together. An empty filters array receives all events.

Event Format

{
  "type": "transfer.blocked",
  "timestamp": "2026-03-04T12:00:00.000Z",
  "mint": "VXQL8u4NVUYG1zaejujwh5gr21iinmk4yYCXn1g9TXr",
  "data": {
    "program": "Bo3Rd8qZeuxU1cmtCqKEFPRe5Uumx9tusjZ7B1hXtPgc",
    "signature": "5KtP...",
    "reason": "WalletNotAllowed"
  }
}

Event types are the same as Webhooks: transfer.executed, transfer.blocked, wallet.verified, wallet.removed, compliance.violation, token.paused, token.resumed, config.updated.

Heartbeat

The server sends a WebSocket ping every 30 seconds. Clients must respond with pong (handled automatically by most WebSocket libraries). Clients that fail to respond are disconnected.

Node.js Client

import WebSocket from "ws";
 
const ws = new WebSocket("ws://localhost:3000/ws");
 
ws.on("open", () => {
  ws.send(JSON.stringify({ subscribe: ["*"] }));
  console.log("Connected to Oracle WebSocket");
});
 
ws.on("message", (data) => {
  const event = JSON.parse(data.toString());
  switch (event.type) {
    case "transfer.blocked":
      console.error("Blocked transfer:", event.data.reason);
      break;
    case "wallet.verified":
      console.log("Wallet added:", event.data);
      break;
    case "config.updated":
      console.log("Config changed:", event.data.detail);
      break;
  }
});
 
ws.on("close", () => {
  console.log("Disconnected — implement reconnection logic");
});

Browser Client

const ws = new WebSocket("ws://localhost:3000/ws");
 
ws.addEventListener("open", () => {
  ws.send(JSON.stringify({
    subscribe: ["transfer.*", "wallet.*"],
  }));
});
 
ws.addEventListener("message", (event) => {
  const data = JSON.parse(event.data);
  // Update your UI
  document.getElementById("events")!.innerHTML += `
    <div>${data.type}: ${JSON.stringify(data.data)}</div>
  `;
});

Dashboard Integration

The Dashboard package uses a useRealtimeEvents hook that wraps the WebSocket connection:

import { useRealtimeEvents } from "@sinai-standard/dashboard";
 
function ComplianceMonitor() {
  const events = useRealtimeEvents({
    url: "ws://localhost:3000/ws",
    filters: ["transfer.*", "compliance.*"],
  });
 
  return (
    <div>
      {events.map((e) => (
        <div key={e.timestamp}>
          {e.type}: {JSON.stringify(e.data)}
        </div>
      ))}
    </div>
  );
}

Error Handling

Invalid JSON messages receive an error response:

// Send invalid JSON
ws.send("not json");
 
// Server responds:
// { "error": "Invalid JSON" }

The connection is not closed on error — only malformed messages are rejected.

On this page