Websocket Events [BETA]

🚧

Try Websockets Beta For Free

Websockets are currently available for all plans however soon will only be available for Pro plan customers. Learn more about Reservoir subscription plans here.

Overview

The Reservoir websocket service allows developers to establish a connection and obtain real-time event updates, eliminating the requirement for constant polling. You can subscribe to events, and optionally provide a filter object to narrow down events based on specific tags.

Refer to the table below for a list of supported events and tags.

EventTagsEvent Description
top-bid.changedcontractTriggered on new top bid change.
ask.createdcontractTriggered on new ask creation.
ask.updatedcontractTriggered on ask update (filled, expiry, cancellation, approval, balance change).
bid.createdcontractTriggered on new bid creation.
bid.updatedcontractTriggered on bid update (filled, expiry, cancellation, approval, balance change).

📘

View event payloads here.

Authentication

The Websocket Service utilizes the same API key for authentication as our other APIs, and it does not impact the rate limits associated with your API key tier.

ChainUrl
Mainnetwss://ws.reservoir.tools
Goerliwss://ws.dev.reservoir.tools

To connect, provide your API key as a query param in the connection url:

const wss = new ws(`wss://ws.reservoir.tools?api_key=${YOUR_API_KEY}`);

Interacting with the Websocket

Before sending any messages over the Websocket, wait for a ready message back from the server. The message looks like:

{
  	// The type of operation
	"type": "connection",
   	// The status of the operation
	"status": "ready",
	"data": {
     	// Your socket id for debugging purposes
		"id": "9nqpzwmwh86"
	}
}

Subscribing

{
	"type": "subscribe",
	"event": "ask.created",
  	// Tags to filter events by, leave blank to not filter by any tags
  	"filters": {
    	"contract": "0x0000c3Caa36E2d9A8CD5269C976eDe05018f0000"
  	}
}

Subscription Response

{
	"type": "subscribe",
	"status": "success",
	"data": {
		"event": "ask.created",
    	// Blank object if no filter is passed
		"filters": {
			"contract": "0x404e739c9d383efc36d3ee85fdceed53212104b2"
		}
	}
}

Unsubscribing

{
	"type": "unsubscribe",
	"event": "ask.created",
  	// Tags to filter events by, leave blank to not filter by any tags
 	"filters": {
   		"contract": "0x0000c3Caa36E2d9A8CD5269C976eDe05018f0000"
 	 }
}

Unsubscribe Response

{
	"type": "unsubscribe",
	"status": "success",
	"data": {
		"event": "top-bid.changed"
	}
}

Connecting Examples

Javascript

npm install ws
const ws = require('ws');

// You can get your API key from https://reservoir.tools
const YOUR_API_KEY = '';

// goerli: wss://ws.dev.reservoir.tools
const wss = new ws(`wss://ws.reservoir.tools?api_key=${YOUR_API_KEY}`);

wss.on('open', function open() {
    console.log('Connected to Reservoir');

    wss.on('message', function incoming(data) {
        console.log('Message received: ', JSON.stringify(JSON.parse(data)));

        // When the connection is ready, subscribe to the top-bids event
        if (JSON.parse(data).status === 'ready') {
            console.log('Subscribing');
            wss.send(
                JSON.stringify({
                    type: 'subscribe',
                    event: 'top-bid.changed',
                }),
            );

            // To unsubscribe, send the following message
            // wss.send(
            //     JSON.stringify({
            //         type: 'unsubscribe',
            //         event: 'top-bid.changed',
            //     }),
            // );
        }
    });
});

Python

pip install websockets
import asyncio
import json
import websockets

# You can get your API key from https://reservoir.tools
api_key = ''

# goerli: wss://ws.dev.reservoir.tools
wss_url = f'wss://ws.reservoir.tools?api_key={api_key}'

async def subscribe_top_bids():
    async with websockets.connect(wss_url) as websocket:
        print('Connected to Reservoir')

        async for data in websocket:
            message = json.loads(data)
            print('Message received:', message)

            if message.get('status') == 'ready':
                print('Subscribing')
                await websocket.send(
                    json.dumps({
                        'type': 'subscribe',
                        'event': 'top-bid.changed',
                    }),
                )

                # To unsubscribe, send the following message
                # await websocket.send(
                #     json.dumps({
                #         'type': 'unsubscribe',
                #         'event': 'top-bid.changed',
                #     }),
                # )

asyncio.run(subscribe_top_bids())

Golang

go get github.com/gorilla/websocket
package main

import (
	"encoding/json"
	"fmt"
	"log"

	"github.com/gorilla/websocket"
)

// You can get your API key from https://reservoir.tools
const apiKey = ""

func main() {
	// goerli: wss://ws.dev.reservoir.tools
	url := fmt.Sprintf("wss://ws.reservoir.tools?api_key=%s", apiKey)
	conn, _, err := websocket.DefaultDialer.Dial(url, nil)
	if err != nil {
		log.Fatal("Error connecting to Reservoir: ", err)
	}
	defer conn.Close()

	fmt.Println("Connected to Reservoir")

	var message map[string]interface{}
	for {
		_, p, err := conn.ReadMessage()
		if err != nil {
			log.Println("Error reading message: ", err)
			break
		}

		err = json.Unmarshal(p, &message)
		if err != nil {
			log.Println("Error parsing message: ", err)
			continue
		}

		fmt.Println("Message received: ", message)

		// When the connection is ready, subscribe to the top-bids event
		if message["status"] == "ready" {
			fmt.Println("Subscribing")
			err = conn.WriteJSON(map[string]interface{}{
				"type":    "subscribe",
				"event": "top-bid.changed",
			})
			if err != nil {
				log.Println("Error subscribing: ", err)
				break
			}

			// To unsubscribe, send the following message
			// err = conn.WriteJSON(map[string]interface{}{
			//     "type":    "unsubscribe",
			//     "event": "top-bid.changed",
			// })
			// if err != nil {
			//     log.Println("Error unsubscribing: ", err)
			//     break
			// }
		}
	}
}

Rust

[dependencies]
serde_json = "1.0.73"
use serde_json::json;
use ws::{Builder, CloseCode, Error, Handler, Message, Result, Sender};

struct Client {
    out: Sender,
}

impl Handler for Client {
    fn on_open(&mut self, _: Handshake) -> Result<()> {
        println!("Connected to Reservoir");
        Ok(())
    }

    fn on_message(&mut self, msg: Message) -> Result<()> {
        let message: serde_json::Value = serde_json::from_str(&msg.to_string()).unwrap();
        println!("Message received: {:?}", message);

        if message["status"] == "ready" {
            println!("Subscribing");
            self.out.send(json!({
                "type": "subscribe",
                "event": "top-bid.changed",
            }))?;

            // To unsubscribe, send the following message
            // self.out.send(json!({
            //     "type": "unsubscribe",
            //     "event": "top-bid.changed",
            // }))?;
        }
        Ok(())
    }

    fn on_close(&mut self, code: CloseCode, reason: &str) {
        match code {
            CloseCode::Normal => println!("Connection closed normally"),
            CloseCode::Away => println!("Connection closed because server is going away"),
            _ => println!("Connection closed with code: {:?} for reason: {}", code, reason),
        }
    }

    fn on_error(&mut self, err: Error) {
        println!("Error: {:?}", err);
    }
}

fn main() {
    // You can get your API key from https://reservoir.tools
    let api_key = "";

    // goerli: wss://ws.dev.reservoir.tools
    let url = format!("wss://ws.reservoir.tools?api_key={}", api_key);

    Builder::new()
        .build(|out| Client { out })
        .unwrap()
        .connect(url)
        .unwrap();
}