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.
Event | Tags | Event Description |
---|---|---|
top-bid.changed | contract | Triggered on new top bid change. |
ask.created | contract | Triggered on new ask creation. |
ask.updated | contract | Triggered on ask update (filled, expiry, cancellation, approval, balance change). |
bid.created | contract | Triggered on new bid creation. |
bid.updated | contract | Triggered 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.
Chain | Url |
---|---|
Mainnet | wss://ws.reservoir.tools |
Goerli | wss://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();
}
Updated over 1 year ago