pagina iniziale

API

WebSocket

Dati di Seeryx in tempo reale su un solo WebSocket: iscriviti a un round (i due libri ordini, operazioni, volume) e al tuo conto; formati e riconnessioni.

Connessione

URL
wss://seeryx.com/ws
Iscrizioni
Un round e un conto per connessione. Una nuova iscrizione dello stesso tipo sostituisce quella precedente; per seguire più round usa più connessioni.
Consegna
Il primo messaggio dopo un’iscrizione è lo stato completo. In seguito arriva un messaggio solo quando il suo contenuto è cambiato, non appena cambia.

Iscrizione

Invii
{ "subscribe": "round", "slug": "btc-updown-5m-1791916200" }
{ "subscribe": "account", "token": "eyJ0eXAiOiJKV1Qi..." }
Uno slug di round o di mercato su un evento; il conto richiede il tuo token di accesso.

Messaggi

Ricevi
{ "type": "round", "slug": "btc-updown-5m-1791916200",
  "up":   { "bids": [[13, 10], [12, 100]], "asks": [[16, 100], [17, 100]] },
  "down": { "bids": [[84, 100], [83, 100]], "asks": [[87, 10], [88, 100]] },
  "trades": [{ "id": 13, "side": "down", "action": "buy", "shares": 10, "price": 53, "time": 1791916330063 }, ...],
  "volume": { "volume": 55.845724, "trades": 13 } }

{ "type": "account",
  "positions": [{ "slug": "btc-updown-5m-1791916200", "side": "down", "shares": 50.3462, "cost": 18.126554 }],
  "orders": [{ "id": 25538, "slug": "btc-updown-5m-1791916200", "side": "down", "action": "buy", "shares": 10, "limit": 48, "createdAt": 1791916330045 }],
  "balance": { "available": 474.097965, "locked": 0, "total": 474.097965, "currency": "USDC" },
  "heads": { "activity": 116, "settled": null } }

{ "type": "error", "error": "Invalid subscription or authentication" }
  • round: entrambi i libri ordini completi (come GET /api/orderbook), le ultime 100 operazioni e il volume.
  • account: esattamente GET /api/account. Quando heads cambia, leggi /api/activity o /api/settled per le nuove righe.
  • error lascia aperto il socket; può seguire un’altra iscrizione.

Segnali di attività

Il server invia un ping WebSocket ogni 30 secondi; le librerie WebSocket rispondono da sole con un pong. Una connessione da cui non arriva nulla per 120 secondi viene chiusa. Invia la prima iscrizione entro 10 secondi dalla connessione.

Riconnessione

  • Riconnettiti con un ritardo crescente (1, 2, 4… fino a 30 secondi) e iscriviti di nuovo: il primo messaggio porta lo stato completo, quindi non perdi nulla.
  • Una chiusura con motivo "Token expired" significa che devi accedere di nuovo prima di iscriverti al conto.
  • Quando un round finisce, iscriviti al successivo sulla stessa connessione.

Limiti e codici di chiusura

LimiteValoreOltre il limite
Dimensione del messaggio4 KBLa connessione si chiude
Messaggi da una connessione60 al minutoChiusura 1008 "Rate limit"
Messaggi di iscrizione600 al minuto per indirizzo IP, 60 per conto{ "type": "error", "error": "Too many subscriptions" }
Connessioni aperte50 per indirizzo IPHTTP 429 prima dell’upgrade, con Retry-After
Prima iscrizioneEntro 10 secondiChiusura 1008 "Handshake timeout"
Silenzio120 secondi senza alcun frameChiusura 1008 "Idle timeout"
Messaggi non letti256 in codaChiusura 1013 "Slow consumer"
Token di accessoFino alla scadenza o alla revocaChiusura 1008 "Token expired" o "Token revoked"

Codice

live.ts
// live.ts: a WebSocket client that reconnects by itself. Node 22+ (WebSocket is built in) or any browser.
import { ACCESS, BASE } from './seeryx';

export type Message = { type: 'round' | 'account' | 'error' } & Record<string, unknown>;

export function live(options: { slug?: string; token?: string; onMessage: (message: Message) => void }) {
  let socket: WebSocket | null = null;
  let attempt = 0;
  let stopped = false;
  let { slug, token } = options;
  const gate = ACCESS ? { access: ACCESS } : {};
  const send = (message: object) => {
    if (socket?.readyState === WebSocket.OPEN) socket.send(JSON.stringify({ ...message, ...gate }));
  };

  function connect() {
    socket = new WebSocket(`${BASE.replace(/^http/, 'ws')}/ws`);
    socket.onopen = () => {
      attempt = 0;
      if (slug) send({ subscribe: 'round', slug });
      if (token) send({ subscribe: 'account', token });
    };
    socket.onmessage = (event) => options.onMessage(JSON.parse(String(event.data)));
    socket.onclose = (event) => {
      if (stopped) return;
      if (event.reason === 'Access code required') { stopped = true; return; } // get a new access token
      if (event.reason === 'Token expired') token = undefined;                   // sign in again for it
      setTimeout(connect, Math.min(30_000, 1000 * 2 ** attempt++));              // 1 s, 2 s, 4 s ... 30 s
    };
  }
  connect();

  return {
    // one round per connection: subscribing to the next round replaces the previous one
    follow(next: string) { slug = next; send({ subscribe: 'round', slug }); },
    close() { stopped = true; socket?.close(); },
  };
}
Un client che si riconnette da solo.
watch.ts
import { api, loadWallet, signIn } from './seeryx';
import { live } from './live';

const token = await signIn(await loadWallet());
const { slug } = await api<{ slug: string }>('/markets/BTC/5m/current');
live({
  slug, token, onMessage: (m) => {
    if (m.type === 'round') console.log('Up book', m.up);
    if (m.type === 'account') console.log('cash', m.balance);
  },
});