> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dexpaprika.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Quick Start: Your First Stream

> Stream live token prices and pool reserves in under 10 minutes. Two feeds, one SSE transport, no API key.

<Info>
  **See it in action:** Check out our [Live Streaming Dashboard](https://dexpaprika.com/streaming/solana) to see real-time updates flow across multiple chains before you build your own.
</Info>

## Tutorial overview

In this tutorial, you'll learn how to:

* Connect to the DexPaprika streaming API
* Receive real-time **token price** updates
* Receive real-time **pool reserve** updates (the DexPaprika differentiator)
* Handle connection errors gracefully
* Build a simple live display

**Time to complete**: 5 to 10 minutes
**Prerequisites**: Basic JavaScript or Python knowledge

***

## Step 1: Choose Your Asset

For this tutorial, we'll stream the price of Ethereum (WETH).

### Finding Token Addresses

Use the REST API to find token addresses:

1. **Search by name or symbol** using the [Search Endpoint](/api-reference/search/search-for-tokens-pools-and-dexes):

```bash theme={null}
curl "https://api.dexpaprika.com/search?query=WETH"
```

2. **Get network list** using the [Networks Endpoint](/api-reference/networks/get-a-list-of-available-blockchain-networks):

```bash theme={null}
curl "https://api.dexpaprika.com/networks"
```

### Common Token Addresses

Or use these verified addresses for popular tokens:

<Tabs>
  <Tab title="Ethereum">
    ```
    Chain: ethereum
    WETH: 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
    USDC: 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
    ```
  </Tab>

  <Tab title="Solana">
    ```
    Chain: solana
    SOL: So11111111111111111111111111111111111111112
    USDC: EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
    ```
  </Tab>

  <Tab title="BSC">
    ```
    Chain: bsc
    BNB: 0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c
    USDT: 0x55d398326f99059ff775485246999027b3197955
    ```
  </Tab>
</Tabs>

***

## Step 2: Test with cURL

First, verify the stream works with a simple cURL command:

```bash theme={null}
curl -N "https://streaming.dexpaprika.com/sse/prices?method=token_price&chain=ethereum&address=0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2&limit=3"
```

Live capture from production, three events back-to-back:

```
data: {"address":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","chain":"ethereum","price":"2255.213769366838","timestamp":1778847591,"timestamp_price":1778847590,"token_price":1778847590}
event: token_price

data: {"address":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","chain":"ethereum","price":"2255.5995720362835","timestamp":1778847592,"timestamp_price":1778847592,"token_price":1778847592}
event: token_price

data: {"address":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","chain":"ethereum","price":"2255.5995720362835","timestamp":1778847593,"timestamp_price":1778847593,"token_price":1778847593}
event: token_price
```

<Tip>
  The `limit=3` parameter closes the stream after three events, perfect for smoke tests. Drop it for a continuous feed.
</Tip>

<Note>
  Both orderings of `event:` and `data:` lines within a single SSE message are valid per the [SSE specification](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events), and the server has used both during rollout. Only the blank-line boundary between messages is significant. `EventSource` handles either order natively. Custom parsers should buffer one message at a time and dispatch on the parsed event type, not on field order.
</Note>

***

## Step 3: JavaScript Implementation

Here's how to connect to the streaming API using JavaScript:

```javascript theme={null}
// Connect to streaming API
const url = new URL('https://streaming.dexpaprika.com/sse/prices');
url.searchParams.set('method', 'token_price');
url.searchParams.set('chain', 'ethereum');
url.searchParams.set('address', '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2');

const eventSource = new EventSource(url.toString());

// Handle price updates
eventSource.addEventListener('token_price', (event) => {
    const data = JSON.parse(event.data);
    const price = parseFloat(data.price);
    console.log(`WETH Price: $${price.toFixed(2)}`);
});

// Surface server-side notices (deprecations, etc.)
eventSource.addEventListener('warning', (event) => {
    const { message } = JSON.parse(event.data);
    console.warn('[stream warning]', message);
});

// Handle errors with reconnection
eventSource.onerror = () => {
    console.log('Connection lost, reconnecting...');
    eventSource.close();
    // Implement reconnection logic here
};
```

<Note>
  **🎯 Live Example:** See this code in action in our [Interactive Streaming Dashboard](https://dexpaprika.com/streaming/solana) - watch 6 tokens stream live across Ethereum, Solana, and BSC with real-time updates, connection status, and latency monitoring.
</Note>

***

## Step 4: Customize Your Stream

### Stream Different Tokens

Modify the URL parameters to stream any token:

```javascript theme={null}
// Bitcoin on Ethereum
url.searchParams.set('chain', 'ethereum');
url.searchParams.set('address', '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599');

// SOL on Solana
url.searchParams.set('chain', 'solana');
url.searchParams.set('address', 'So11111111111111111111111111111111111111112');

// BNB on BSC
url.searchParams.set('chain', 'bsc');
url.searchParams.set('address', '0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c');
```

### Add Multiple Assets

To stream multiple assets, switch to the POST method:

<Expandable title="View implementation">
  ```javascript theme={null}
  async function streamMultipleAssets() {
      const assets = [
          { chain: 'ethereum', address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', method: 'token_price' },
          { chain: 'solana',   address: 'So11111111111111111111111111111111111111112',  method: 'token_price' }
      ];

      const response = await fetch('https://streaming.dexpaprika.com/sse/prices', {
          method: 'POST',
          headers: {
              'Accept': 'text/event-stream',
              'Content-Type': 'application/json'
          },
          body: JSON.stringify(assets)
      });

      const decoder = new TextDecoder();
      let buffer = '';

      for await (const chunk of response.body) {
          buffer += decoder.decode(chunk, { stream: true });

          const messages = buffer.split('\n\n');
          buffer = messages.pop() ?? '';

          for (const message of messages) {
              const lines = message.split('\n');
              const eventLine = lines.find(l => l.startsWith('event:'));
              const dataLine  = lines.find(l => l.startsWith('data:'));
              if (!dataLine) continue;

              const eventType = eventLine ? eventLine.slice(6).trim() : 'message';
              if (eventType !== 'token_price') continue; // skip ping/warning/etc

              const update = JSON.parse(dataLine.slice(5).trim());
              console.log(`${update.chain} ${update.address}: $${parseFloat(update.price).toFixed(4)}`);
          }
      }
  }
  ```

  Pass up to 25 entries per connection. `POST /sse/prices` rejects larger arrays with `{"message":"too many assets, max 25 allowed"}` (the sibling `POST /sse/reserves` endpoint uses different wording: `"too many subscriptions"`). Open additional connections in parallel if you need more, up to the **10 concurrent SSE streams per IP** limit.
</Expandable>

***

## Understanding the Code

### Key Components

<AccordionGroup>
  <Accordion title="EventSource API">
    The `EventSource` API is the browser's built-in way to handle SSE:

    ```javascript theme={null}
    const eventSource = new EventSource(url);
    eventSource.addEventListener('token_price', handler);
    ```

    It automatically handles:

    * Persistent connections
    * Automatic reconnection
    * Event parsing
  </Accordion>

  <Accordion title="Error Handling">
    The `onerror` callback handles disconnections:

    ```javascript theme={null}
    eventSource.onerror = () => {
        // Implement exponential backoff
        const delay = baseDelay * Math.pow(2, attempts);
        setTimeout(reconnect, delay);
    };
    ```
  </Accordion>

  <Accordion title="Price Updates">
    Each `token_price` event contains:

    ```javascript theme={null}
    {
        "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
        "chain": "ethereum",
        "price": "2255.5995720362835",   // USD, string to preserve precision
        "timestamp": 1778847592,         // server send time (unix)
        "timestamp_price": 1778847592,   // price observation time
        "token_price": 1778847592        // alias of timestamp_price
    }
    ```

    The legacy `t_p` method emits a compact `{a, c, p, t, t_p}` shape and is **deprecated**.
  </Accordion>

  <Accordion title="Other event types">
    Beyond `token_price` and `reserve_update`, the server may push:

    * `ping` every \~15s (keep-alive). Payload: `{"time": <unix>}`.
    * `warning` for non-fatal notices, including deprecation messages. Payload: `{"message": "..."}`.
    * `error` for stream-terminating problems (invalid asset, etc.).

    Always filter on the `event:` line. Treat unknown event names as no-ops so future server-side additions cannot break your handler.
  </Accordion>
</AccordionGroup>

***

## Now stream pool reserves

Token prices are useful. Block-level pool reserves are the killer feature. Instead of `/sse/prices`, point at `/sse/reserves` and pick one of two methods:

* `method=pool_reserves`: subscribe to a specific pool. You receive events when that pool's reserves change.
* `method=token_reserves`: subscribe to a specific token. You receive events for every pool the token sits in.

### Try it with cURL

Subscribe to a Uniswap V3 USDC/WETH pool on Ethereum:

```bash theme={null}
curl -N "https://streaming.dexpaprika.com/sse/reserves?method=pool_reserves&chain=ethereum&address=0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640"
```

Each `reserve_update` event tells you the pool, the block it was observed in, both tokens' raw reserves, the block's delta, current USD prices, and the dollar value of the change. A live capture from production (block 25,100,507):

```
data: {"chain":"ethereum","pool_id":"0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640","block":"25100507","tokens":[{"token_id":"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48","reserve":"70835095690418","delta":"12018780248","price_usd":1.0000312133558542,"reserve_usd":70837306.69,"delta_usd":12019.15},{"token_id":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","reserve":"14194377792871748830512","delta":"-5325593173019115725","price_usd":2255.213769366838,"reserve_usd":32011356.24,"delta_usd":-12010.35}],"total_reserve_usd":102848662.93,"total_delta_usd":8.80}
event: reserve_update
```

That is a single swap: \~$12,019 of USDC came in, ~$12,010 of WETH went out, net dollar delta to the pool was +\$8.80 (the trader paid the trading fee). The whole picture, in one event, no log decoding required.

<Note>
  The `reserve`, `delta`, `block`, and `previous_block` fields all arrive as JSON strings (note the quotes in the example above). The server encodes them that way because they routinely exceed `Number.MAX_SAFE_INTEGER`: the WETH `delta` above is a 19-digit integer. Use `BigInt(reserve)` for exact arithmetic, or `Number(block)` when you just want a quick block-height comparison. The pre-computed USD fields (`reserve_usd`, `delta_usd`, `total_reserve_usd`, `total_delta_usd`) and `price_usd` are regular JSON numbers, safe for floating-point math.
</Note>

### Same thing in JavaScript

```javascript theme={null}
async function subscribeReserves() {
  const url = new URL("https://streaming.dexpaprika.com/sse/reserves");
  url.searchParams.set("method", "pool_reserves");
  url.searchParams.set("chain", "ethereum");
  url.searchParams.set("address", "0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640");

  const response = await fetch(url.toString(), { headers: { Accept: "text/event-stream" } });
  const decoder = new TextDecoder();
  let buffer = "";

  // Async-iterate the response body. This pattern handles gzip/transfer encodings
  // transparently in both Node and modern browsers, and never blocks on partial
  // chunks the way `getReader().read()` can.
  for await (const chunk of response.body) {
    buffer += decoder.decode(chunk, { stream: true });

    // SSE messages are separated by a blank line.
    const messages = buffer.split("\n\n");
    buffer = messages.pop() ?? "";

    for (const message of messages) {
      const lines = message.split("\n");
      const eventLine = lines.find((l) => l.startsWith("event:"));
      const dataLine = lines.find((l) => l.startsWith("data:"));
      if (!dataLine) continue;

      // The stream emits: `reserve_update`, `ping`, `warning`, `error`.
      // Filter for the one we care about so keep-alives and notices
      // never reach the reserve handler.
      const eventType = eventLine ? eventLine.slice(6).trim() : "message";
      if (eventType !== "reserve_update") continue;

      const update = JSON.parse(dataLine.slice(5).trim());
      console.log(`block ${update.block}  pool delta ${update.total_delta_usd.toFixed(2)} USD`);
    }
  }
}

subscribeReserves();
```

<Tip>
  Want the deep dive on what reserves streaming unlocks (impermanent loss tracking, MEV detection, real-time TVL, slippage estimation)? See the [Reserves Streaming page](/streaming/reserves-streaming) for the annotated wire example and use cases broken out by audience.
</Tip>

***

## Implementation Notes

### Browser Support

* EventSource API works in all modern browsers
* For direct browser connections, you'll need to handle CORS (use a backend proxy)
* No issues when streaming from server-side (Node.js, Python, etc.)

### Best Practices

* Implement exponential backoff for reconnection
* Handle both connection errors and SSE error events
* Parse prices as floats to maintain precision
* Close connections properly on page unload

***

## See It Live

<Card title="🚀 Live Streaming Dashboard" icon="rocket" href="https://dexpaprika.com/streaming/solana">
  **Try the API without writing code.** The interactive streaming demo lets you pick a chain, pick tokens (or paste a custom contract address), and watch SSE events flow in real time. You can also copy the generated subscription payload to use in your own code.

  **What you'll see:**

  * Real-time price updates, sub-second latency
  * Multi-chain support (switch chains in the UI)
  * Connection status, latency, and update counts
  * The exact JSON the server pushes, line by line
</Card>

***

## Next Steps

Congratulations! You've built your first streaming application. Here's what to explore next:

<CardGroup cols={2}>
  <Card title="Reserves Streaming Deep Dive" icon="droplet" href="/streaming/reserves-streaming">
    What block-level reserve updates contain, both subscription methods, annotated wire example, and use cases for LPs, MEV builders, and analytics teams.
  </Card>

  <Card title="React Integration" icon="react" href="/streaming/guides/react-integration">
    Build streaming components for React and Next.js applications.
  </Card>

  <Card title="Stream Multiple Assets" icon="signal-stream" href="/streaming/subscribe-to-multiple-assets-streaming">
    The POST /sse/prices endpoint for multi-token price subscriptions.
  </Card>

  <Card title="Subscribe to Multiple Reserves" icon="layer-group" href="/streaming/subscribe-to-multiple-reserves-streaming">
    The POST /sse/reserves endpoint for multi-pool and multi-token subscriptions.
  </Card>
</CardGroup>

***

## Get Help

<CardGroup cols={2}>
  <Card title="Join Discord" icon="discord" href="https://discord.gg/DhJge5TUGM">
    Get help from our community.
  </Card>

  <Card title="API Reference" icon="book" href="/streaming/streaming-token-prices">
    Read the complete API documentation.
  </Card>
</CardGroup>
