> For the complete documentation index, see [llms.txt](https://docs.getblock.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.getblock.io/solana-market-data/api-reference/vwap-market-data.md).

# vwap - Solana Market Data

Stream the volume-weighted average price for a Solana token pair. Complete guide on how to use the vwap topic in GetBlock Solana Market Data documentation.

The `vwap` topic provides the volume-weighted average price over the selected window. Trades with more volume have proportionally more influence on the result, which makes VWAP the standard benchmark for execution quality and for liquidity-aware market monitoring.

{% hint style="warning" %}
**WebSocket-only topic.** Subscribe with `getblock_subscribe` over `wss://stream.eu-central-1.getblock.io/v1/solana-mainnet/stream`. The `limit`, `from`, and `to` query parameters are not supported by the streaming API.
{% endhint %}

## Parameters

Pass one structured request object to [`getblock_subscribe`](/solana-market-data/api-reference/getblock_subscribe-market-data.md), with `"source": "market"` and `"topic": "vwap"`. The fields below go inside the nested `params` object.

| Parameter  | Type    | Required | Description                                                                                                                                  |
| ---------- | ------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `base`     | string  | No       | Base58-encoded mint address of the base token. Omit to receive every market.                                                                 |
| `quote`    | string  | No       | Base58-encoded mint address of the quote token. Omit to receive every market.                                                                |
| `window`   | string  | Yes      | Aggregation period. One of `1s`, `10s`, `30s`, `1m`, `5m`, `30m`, `1h`, `2h`, `4h`, `6h`, `8h`, `12h`, `24h`.                                |
| `hydrate`  | integer | No       | Size of the row set to maintain, `1`–`100`. Sent as an initial snapshot, then held at this size (see [Row set behavior](#row-set-behavior)). |
| `throttle` | string  | No       | Minimum interval between pushes. A positive integer followed by `ms`, `s`, `m`, or `h` (for example `1s`).                                   |

## Request Example

{% tabs %}
{% tab title="wscat" %}
{% code overflow="wrap" %}

```bash
# WebSocket-only. Connect first:
wscat -c 'wss://stream.eu-central-1.getblock.io/v1/solana-mainnet/stream?apiKey=<API-KEY>'

# Then send:
{"jsonrpc":"2.0","id":"getblock.io","method":"getblock_subscribe","params":[{"source":"market","topic":"vwap","params":{"base":"So11111111111111111111111111111111111111112","quote":"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v","window":"5m","hydrate":5,"throttle":"1s"}}]}
```

{% endcode %}
{% endtab %}

{% tab title="JavaScript" %}

```javascript
// Node 20+ has a global WebSocket; no dependency required.
const ws = new WebSocket('wss://stream.eu-central-1.getblock.io/v1/solana-mainnet/stream?apiKey=<API-KEY>');
const rows = new Map();

ws.onopen = () => {
  ws.send(JSON.stringify({
    "jsonrpc": "2.0",
    "id": "getblock.io",
    "method": "getblock_subscribe",
    "params": [
      {
        "source": "market",
        "topic": "vwap",
        "params": {
          "base": "So11111111111111111111111111111111111111112",
          "quote": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
          "window": "5m",
          "hydrate": 5,
          "throttle": "1s"
        }
      }
    ]
  }));
};

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

  // First reply is the subscription ID
  if (typeof msg.result === 'string') {
    console.log('Subscribed:', msg.result);
    return;
  }

  // Every later message is a change set
  const { inserts = [], updates = [], deletes = [] } = msg.params.result;
  for (const row of [...inserts, ...updates]) rows.set(row.id, row);
  for (const row of deletes) rows.delete(row.id);
};
```

{% endtab %}

{% tab title="Python" %}

```python
import asyncio, json, websockets

async def main():
    async with websockets.connect('wss://stream.eu-central-1.getblock.io/v1/solana-mainnet/stream?apiKey=<API-KEY>') as ws:
        await ws.send(json.dumps({
          "jsonrpc": "2.0",
          "id": "getblock.io",
          "method": "getblock_subscribe",
          "params": [
            {
              "source": "market",
              "topic": "vwap",
              "params": {
                "base": "So11111111111111111111111111111111111111112",
                "quote": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
                "window": "5m",
                "hydrate": 5,
                "throttle": "1s"
              }
            }
          ]
        }))

        rows = {}
        async for message in ws:
            msg = json.loads(message)

            # First reply is the subscription ID
            if isinstance(msg.get('result'), str):
                print('Subscribed:', msg['result'])
                continue

            result = msg['params']['result']
            for row in result.get('inserts', []) + result.get('updates', []):
                rows[row['id']] = row
            for row in result.get('deletes', []):
                rows.pop(row['id'], None)

asyncio.run(main())
```

{% endtab %}
{% endtabs %}

## Response Example

The first reply is the subscription ID:

```json
{
  "jsonrpc": "2.0",
  "id": "getblock.io",
  "result": "0x4503d281ca474f3322ed277fde75db15"
}
```

Every later message is a change-set notification:

```json
{
  "jsonrpc": "2.0",
  "method": "getblock_subscribe",
  "params": {
    "subscription": "0x4503d281ca474f3322ed277fde75db15",
    "result": {
      "inserts": [
        {
          "base": "So11111111111111111111111111111111111111112",
          "cumulative_price_volume": "92071.1602644793",
          "cumulative_price_volume_usd": "9540623.96754882",
          "current_price": "103.624673442445",
          "current_price_usd": "103.624673442445",
          "data_points": "79",
          "id": 856191,
          "quote": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
          "slot": "445316626",
          "timestamp": "2026-09-08T10:33:37.000000000Z",
          "total_volume": "888.526767663",
          "total_volume_usd": "92071.158519",
          "vwap": "103.622269598748",
          "vwap_usd": "103.622286512013",
          "window_duration": "PT1M",
          "window_end": "2026-09-08T10:34:00.000000000Z",
          "window_start": "2026-09-08T10:33:00.000000000Z"
        }
      ],
      "updates": [],
      "deletes": []
    }
  }
}
```

## Response Parameters

Each object in `inserts`, `updates`, and `deletes` has the following shape.

| Field                         | Type   | Description                                                                                   |
| ----------------------------- | ------ | --------------------------------------------------------------------------------------------- |
| `base`                        | string | Mint address of the base token.                                                               |
| `cumulative_price_volume`     | string | Running sum of price × volume used to derive `vwap`.                                          |
| `cumulative_price_volume_usd` | string | Running sum of USD price × volume used to derive `vwap_usd`.                                  |
| `current_price`               | string | Latest observed price, for comparison with the average.                                       |
| `current_price_usd`           | string | Latest observed price expressed in USD.                                                       |
| `data_points`                 | string | Number of observations included in the row.                                                   |
| `id`                          | number | Row identifier. Stable across `updates` and `deletes` — use it as the key for local state.    |
| `quote`                       | string | Mint address of the quote token.                                                              |
| `slot`                        | string | Latest Solana slot included in the row.                                                       |
| `timestamp`                   | string | Timestamp of the latest data included in the row.                                             |
| `total_volume`                | string | Volume included in the calculation, in the base token.                                        |
| `total_volume_usd`            | string | Volume included in the calculation, expressed in USD.                                         |
| `vwap`                        | string | Volume-weighted average price in the quote token.                                             |
| `vwap_usd`                    | string | Volume-weighted average price expressed in USD.                                               |
| `window_duration`             | string | Aggregation period used to build the row, as an ISO 8601 duration (`PT1M` for a `1m` window). |
| `window_end`                  | string | End of the aggregation window.                                                                |
| `window_start`                | string | Start of the aggregation window.                                                              |

{% hint style="info" %}
Numeric and timestamp values are serialized as **strings** to preserve precision. `id` is a JSON number and boolean fields are JSON booleans. Timestamps are ISO 8601 with nanosecond precision; durations such as `window_duration` use ISO 8601 duration format (`1m` is returned as `PT1M`). Ignore unknown fields for forward compatibility.
{% endhint %}

## Row set behavior

`hydrate` sets the size of the row set the subscription maintains — not merely the size of the opening snapshot. The service sends that many rows up front, then keeps the set at that size for the lifetime of the subscription: as new rows arrive, the oldest are emitted in `deletes`.

{% hint style="warning" %}
A row in `deletes` is **not** by itself evidence of a chain reorganization. On fast-moving topics most deletes are ordinary eviction from the `hydrate` window. Reconcile by `id` and do not treat a delete as a reorg signal.
{% endhint %}

Maintain local state by upserting `inserts` and `updates` by `id`, then removing `deletes` by `id`:

```javascript
for (const row of [...(result.inserts ?? []), ...(result.updates ?? [])]) {
  rows.set(row.id, row)
}

for (const row of result.deletes ?? []) {
  rows.delete(row.id)
}
```

## Use Cases

* Measuring execution quality against a volume-weighted benchmark
* Liquidity-aware pricing for large orders
* Fair-value estimation that discounts low-volume price prints
* Comparing `current_price` against a volume-weighted baseline

## Error Handling

| Code       | Message                                                                                   | Cause                                                                                                                                                           |
| ---------- | ----------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `-32602`   | `unsupported source "…": supported sources are "market" and "priorityfee"`                | `source` is not a recognized value.                                                                                                                             |
| `-32602`   | `unsupported topic: supported topics are trades, ohlcv, block, twap, vwap, volume, token` | `topic` is not a recognized value.                                                                                                                              |
| `-32602`   | `window must be one of 1s, 10s, 30s, 1m, …`                                               | `window` is missing or not an accepted value on a windowed topic.                                                                                               |
| `-32602`   | `hydrate must be an integer from 1 to 100`                                                | `hydrate` is outside the accepted range.                                                                                                                        |
| `-32602`   | `throttle must be a positive integer followed by ms, s, m, or h`                          | `throttle` is malformed.                                                                                                                                        |
| `-32602`   | `base must be a base58-encoded 32-byte Solana public key`                                 | `base` or `quote` is not a valid mint address.                                                                                                                  |
| HTTP `401` | `authorization failed`                                                                    | API key missing, invalid, or Solana Market Data is not activated on it. WebSocket clients cannot read the handshake body and surface this as close code `1006`. |
