SENDY

Trade stream

Subscribe once and receive every trade your wallet participates in across all tokens—a single chronological feed suited to portfolio-wide alerts, journaling, or mirroring activity into your own infra. Billing and wallet eligibility match REST (see Authentication).

When this mode fits

  • You want one connection that covers the whole wallet, without maintaining per-mint channels.
  • Downstream logic deduplicates tokens itself or persists everything into a datastore.
  • You intentionally avoid client-side filtering so you cannot miss ancillary fills on related assets.

If you only care about swaps on one mint, use Token stream instead—less traffic and simpler consumers.

Official TypeScript SDK

Highest-level API: omit tokenMint so handshake auth is only apiKey + walletAddress.

import { SendyClient, type WalletTradeStreamReady } from '@mvritz/sendy-sdk';

const client = new SendyClient({ apiKey: process.env.SENDY_API_KEY! });
const socket = client.connectWalletTradeStream('YOUR_WALLET');

socket.on('ready', (p: WalletTradeStreamReady) => {
  console.assert(p.filter === 'all' && p.tokenMint === null);
});
socket.on('trade', () => {});
socket.on('disconnect', () => socket.close());

Socket.IO handshake (all mints)

  • URL: https://api.sendy.lol
  • Namespace: /sdk/wallet
  • Socket.IO HTTP path: /socket.io

Auth JSON

{
  "apiKey": "sendy_…",
  "walletAddress": "<eligible solana pubkey>"
}

Signals

  • ready — includes filter: "all", tokenMint: null
  • trade — full fill payload for any SPL involved
  • error — API key / wallet / quota issues

Implementations

Same behavior across languages: websocket transport, authenticated namespace handshake, then listen for trade. Rust snippet expects rust_socketio with the async feature plus tokio + serde_json.

connect — all trades
import { io } from 'socket.io-client';

const socket = io('https://api.sendy.lol/sdk/wallet', {
  path: '/socket.io',
  transports: ['websocket'],
  auth: {
    apiKey: process.env.SENDY_API_KEY!,
    walletAddress: 'YOUR_WALLET',
  },
});

socket.on('ready', (p) => {
  console.log('filter', p.filter);
});

socket.on('trade', (trade) => {
  console.log(trade.tokenAddress, trade.side);
});

socket.on('error', (err) => console.error(err));

socket.io.on('close', () => socket.close());

Reading wscat output

Socket.IO rides on Engine.IO framing; raw lines mix engine metadata with JSON payloads. The wscat flow is primarily for inspecting live bytes or proving connectivity—in production rely on socket.io-client, python-socketio, or rust_socketio which negotiate auth and namespaces for you.