Skip to content

SSE Price Stream

GET /v2/updates/price/stream

Subscribe to real-time price updates via Server-Sent Events (SSE). This is the primary way to get live execution prices.

Request

bash
curl -N "https://mainnet.proxy.ryze.pro/v2/updates/price/stream?ids[]=ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace&ids[]=eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a"

Query Parameters

ParameterTypeRequiredDescription
ids[]stringYesPyth hex feed ID (repeatable for multiple feeds)

Response

The response is an SSE stream (text/event-stream). Each event contains a JSON payload:

data: {"parsed":[{"id":"ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace","price":{"price":"160025000000","conf":"0","expo":-8,"publish_time":1713200000},"ema_price":{"price":"160025000000","conf":"0","expo":-8,"publish_time":1713200000},"blend":{"token":"0x4200000000000000000000000000000000000006","pythPrice":"1600250000000000000000","cexPrice":"1600300000000000000000","blendFactor":"500000000000000000","blendedPrice":"1600275000000000000000"}}]}

Behavior

  1. Initial snapshot: Immediately sends cached prices for all requested feeds
  2. Live updates: Sends new prices as they arrive (~200ms cadence from Pyth Pro)
  3. Heartbeat: Comment lines (: keepalive) every 15 seconds to keep the connection alive
  4. Filtering: Only sends updates for the feed IDs you subscribed to

JavaScript Example

javascript
const feedIds = [
  'ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace', // ETH
  'eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a', // USDC
  '2817d7bfe5c64b8ebd8cb2cb5f4f59c640453faa953a0f2f8067e0e83f4db8c9', // cbBTC
];

const params = feedIds.map(id => `ids[]=${id}`).join('&');
const url = `https://mainnet.proxy.ryze.pro/v2/updates/price/stream?${params}`;

const eventSource = new EventSource(url);

eventSource.onmessage = (event) => {
  const data = JSON.parse(event.data);

  for (const update of data.parsed) {
    const price = Number(update.price.price) * Math.pow(10, update.price.expo);
    console.log(`${update.id.slice(0, 8)}...: $${price.toFixed(2)}`);

    // If blending is active, the execution price is in blend.blendedPrice (WAD)
    if (update.blend) {
      const execPrice = Number(BigInt(update.blend.blendedPrice)) / 1e18;
      console.log(`  Execution price: $${execPrice.toFixed(2)}`);
    }
  }
};

eventSource.onerror = (err) => {
  console.error('SSE error, will auto-reconnect:', err);
};

React Example

tsx
import { useEffect, useRef, useState } from 'react';

function usePriceStream(feedIds: string[]) {
  const [prices, setPrices] = useState<Record<string, number>>({});
  const esRef = useRef<EventSource | null>(null);

  useEffect(() => {
    const params = feedIds.map(id => `ids[]=${id}`).join('&');
    const es = new EventSource(
      `https://mainnet.proxy.ryze.pro/v2/updates/price/stream?${params}`
    );

    es.onmessage = (event) => {
      const data = JSON.parse(event.data);
      setPrices(prev => {
        const next = { ...prev };
        for (const update of data.parsed) {
          next[update.id] = Number(update.price.price) * Math.pow(10, update.price.expo);
        }
        return next;
      });
    };

    esRef.current = es;
    return () => es.close();
  }, [feedIds.join(',')]);

  return prices;
}

Response Headers

HeaderValue
Content-Typetext/event-stream
Cache-Controlno-cache, no-transform
Connectionkeep-alive
Access-Control-Allow-Origin*

Notes

  • The stream sends padding comments on initial connection to flush through reverse proxies (Cloudflare)
  • If a client falls behind, updates are dropped (non-blocking) to prevent backpressure
  • The EventSource API auto-reconnects on network errors
  • Updates arrive at ~500ms broadcast cadence (coalesced from ~200ms Pyth Pro updates)