Walos
Docs
Streaming

Event Streaming (SSE)

Subscribe to real-time Sui events via Server-Sent Events. Events are pushed to your client as they are indexed — no polling required.

SSE vs REST polling

Use GET /v1/events for batch queries, historical lookups, and pagination. Use GET /v1/events/stream for live dashboards, real-time alerts, and continuous processing where low latency matters.

Endpoint

GET http://127.0.0.1:3001/v1/events/stream?package=<PACKAGE_ID>

Query Parameters

ParameterRequiredDescription
packageYesSui package ID or MVR name
event_typeNoFilter by event type
senderNoFilter by sender address
tokenNoShort-lived JWT for browser auth (see Token Exchange below)

Authentication

Two authentication methods are supported. Use whichever fits your environment.

API Key (server-side)

Pass your API key in the x-api-key header. Works with curl, SDKs, and any HTTP client that supports custom headers.

curl -H "x-api-key: YOUR_API_KEY" \
  "http://127.0.0.1:3001/v1/events/stream?package=0xYOUR_PACKAGE_ID"

Stream Token (browser)

The browser EventSource API cannot set custom headers. Exchange your dashboard session for a short-lived token and pass it as a query parameter.

Token Exchange

Authenticated dashboard users can request a 60-second stream token.

// 1. Get a stream token (requires the admin session cookie)
const res = await fetch('/api/stream/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ package: '0xYOUR_PACKAGE_ID' }) // optional scope
});
const { token } = await res.json();

// 2. Connect to the SSE stream
const source = new EventSource(
  `http://127.0.0.1:3001/v1/events/stream?package=0xYOUR_PACKAGE_ID&token=${token}`
);

source.addEventListener('sui.event', (e) => {
  const event = JSON.parse(e.data);
  console.log('New event:', event);
});

Tokens expire after 60 seconds. Reconnection after expiry requires a fresh token exchange.

Event Types

The SSE stream sends typed events. Listen for specific event names using addEventListener.

EventDescription
sui.eventA new indexed Sui event. The data field contains the full event JSON.
timeoutConnection closed after reaching the maximum duration (30 minutes). Reconnect to resume.
limitConnection closed after delivering the maximum number of events (10,000). Reconnect to resume.
errorA server-side error occurred. The data field contains { error: { code, message } }.

Reconnection

The stream includes a retry: field that tells the client the recommended reconnection interval. Each event carries an id: field. On reconnection, the browser automatically sends Last-Event-ID so the server resumes from where you left off — no duplicate events.

# Manual reconnection with curl:
curl -H "x-api-key: YOUR_API_KEY" \
  -H "Last-Event-ID: <cursor from last received event>" \
  "http://127.0.0.1:3001/v1/events/stream?package=0xYOUR_PACKAGE_ID"

Limits

LimitDefault
Max connection duration30 minutes
Max events per connection10,000
Concurrent connections per API key5
Heartbeat interval15 seconds
Stream token TTL60 seconds

Node.js Example

import { EventSource } from 'eventsource'; // npm install eventsource

// EventSourceInit only exposes withCredentials and a custom fetch.
// Pass a fetch wrapper to inject the x-api-key header on every request,
// including reconnects.
const es = new EventSource(
  'http://127.0.0.1:3001/v1/events/stream?package=0xYOUR_PACKAGE_ID',
  {
    fetch: (input, init) =>
      fetch(input, {
        ...init,
        headers: { ...init.headers, 'x-api-key': 'YOUR_API_KEY' }
      })
  }
);

es.addEventListener('sui.event', (e) => {
  const event = JSON.parse(e.data);
  console.log(`[${event.checkpoint}] ${event.eventType}`, event.data);
});

es.addEventListener('error', (e) => {
  console.error('SSE error:', e.data);
});

// Graceful shutdown
process.on('SIGINT', () => es.close());
Next steps
  • • Start with the Quickstart if you haven't registered a package yet
  • • Set up Webhooks for push-based delivery to your own endpoints