What you’ll do
- Connect to
wss://api.blockdb.io/v1/evm/ - Authenticate with
Authorization: Bearer <API_KEY>(or?api_key=fallback) - Subscribe to a dataset (example: Blocks
dataset_id: "0101") - Receive
updatemessages - Unsubscribe cleanly without closing the socket
Prerequisites
- A valid BlockDB API key (set as
BLOCKDB_API_KEY) - A WebSocket client (CLI or SDK)
1) Connect
# CLI: connect (wscat)
export BLOCKDB_API_KEY="..."
wscat -c wss://api.blockdb.io/v1/evm/ \
-H "Authorization: Bearer $BLOCKDB_API_KEY"
#include <libwebsockets.h>
#include <string.h>
#include <stdio.h>
static int callback_blockdb(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len) {
switch (reason) {
case LWS_CALLBACK_CLIENT_ESTABLISHED:
printf("connected\n");
break;
case LWS_CALLBACK_CLIENT_RECEIVE:
printf("Received: %.*s\n", (int)len, (const char *)in);
break;
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
printf("connection error\n");
break;
default:
break;
}
return 0;
}
static struct lws_protocols protocols[] = {
{ "blockdb", callback_blockdb, 0, 4096, 0, NULL, 0 },
{ NULL, NULL, 0, 0, 0, NULL, 0 }
};
int main(void) {
struct lws_context_creation_info info;
memset(&info, 0, sizeof(info));
info.port = CONTEXT_PORT_NO_LISTEN;
info.protocols = protocols;
struct lws_context *context = lws_create_context(&info);
if (!context) return 1;
struct lws_client_connect_info ccinfo;
memset(&ccinfo, 0, sizeof(ccinfo));
ccinfo.context = context;
ccinfo.address = "api.blockdb.io";
ccinfo.port = 443;
ccinfo.path = "/v1/evm/?api_key=YOUR_API_KEY"; // fallback for clients without custom headers
ccinfo.host = ccinfo.address;
ccinfo.origin = ccinfo.address;
ccinfo.ssl_connection = LCCSCF_USE_SSL;
if (!lws_client_connect_via_info(&ccinfo)) return 1;
while (lws_service(context, 0) >= 0) {}
lws_context_destroy(context);
return 0;
}
using System;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
class Program {
static async Task Main() {
using var ws = new ClientWebSocket();
ws.Options.SetRequestHeader("Authorization", $"Bearer {Environment.GetEnvironmentVariable("BLOCKDB_API_KEY")}");
await ws.ConnectAsync(new Uri("wss://api.blockdb.io/v1/evm/"), CancellationToken.None);
Console.WriteLine("connected");
}
}
# pip install websocket-client
import os
import websocket
def on_open(ws):
print("connected")
ws = websocket.WebSocketApp(
"wss://api.blockdb.io/v1/evm/",
header={"Authorization": f"Bearer {os.getenv('BLOCKDB_API_KEY')}"},
on_open=on_open,
)
ws.run_forever()
// npm i ws
const WebSocket = require('ws');
const ws = new WebSocket('wss://api.blockdb.io/v1/evm/', {
headers: { Authorization: `Bearer ${process.env.BLOCKDB_API_KEY}` }
});
ws.on('open', () => console.log('connected'));
ws.on('close', (code, reason) => console.log('closed', code, reason?.toString?.()));
ws.on('error', (err) => console.error('error', err));
package main
import (
"log"
"net/http"
"os"
"github.com/gorilla/websocket"
)
func main() {
header := http.Header{"Authorization": []string{"Bearer " + os.Getenv("BLOCKDB_API_KEY")}}
c, _, err := websocket.DefaultDialer.Dial("wss://api.blockdb.io/v1/evm/", header)
if err != nil {
log.Fatal("dial:", err)
}
defer c.Close()
log.Println("connected")
}
If your client cannot send headers during the handshake, use the query parameter fallback:
wss://api.blockdb.io/v1/evm/?api_key=YOUR_API_KEY2) Subscribe (client → server)
This starts a stream. You must provide:action: "subscribe"chain_id(EVM chain)dataset_id(stream dataset)params(stream-specific filters; use{}if none)
# Subscribe to Blocks (dataset_id 0101) on Ethereum mainnet (chain_id 1)
wscat -c wss://api.blockdb.io/v1/evm/ \
-H "Authorization: Bearer $BLOCKDB_API_KEY" \
-x '{"action":"subscribe","chain_id":1,"dataset_id":"0101","params":{}}'
#include <libwebsockets.h>
#include <string.h>
#include <stdio.h>
static int callback_blockdb(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len) {
switch (reason) {
case LWS_CALLBACK_CLIENT_ESTABLISHED:
lws_callback_on_writable(wsi);
break;
case LWS_CALLBACK_CLIENT_WRITEABLE: {
unsigned char buf[LWS_PRE + 256];
unsigned char *p = &buf[LWS_PRE];
size_t n = sprintf((char *)p, "{\"action\":\"subscribe\",\"chain_id\":1,\"dataset_id\":\"0101\",\"params\":{}}");
lws_write(wsi, p, n, LWS_WRITE_TEXT);
break;
}
case LWS_CALLBACK_CLIENT_RECEIVE:
printf("Received: %.*s\n", (int)len, (const char *)in);
break;
default:
break;
}
return 0;
}
using System;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
class Program {
static async Task Main() {
using var ws = new ClientWebSocket();
ws.Options.SetRequestHeader("Authorization", $"Bearer {Environment.GetEnvironmentVariable("BLOCKDB_API_KEY")}");
await ws.ConnectAsync(new Uri("wss://api.blockdb.io/v1/evm/"), CancellationToken.None);
var subMsg = "{\"action\":\"subscribe\",\"chain_id\":1,\"dataset_id\":\"0101\",\"params\":{}}";
await ws.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(subMsg)), WebSocketMessageType.Text, true, CancellationToken.None);
}
}
import json
def on_open(ws):
ws.send(json.dumps({
"action": "subscribe",
"chain_id": 1,
"dataset_id": "0101",
"params": {}
}))
ws.on('open', () => {
ws.send(JSON.stringify({
action: 'subscribe',
chain_id: 1,
dataset_id: '0101',
params: {}
}));
});
package main
import (
"log"
"net/http"
"os"
"github.com/gorilla/websocket"
)
func main() {
header := http.Header{"Authorization": []string{"Bearer " + os.Getenv("BLOCKDB_API_KEY")}}
c, _, err := websocket.DefaultDialer.Dial("wss://api.blockdb.io/v1/evm/", header)
if err != nil {
log.Fatal("dial:", err)
}
defer c.Close()
sub := `{"action":"subscribe","chain_id":1,"dataset_id":"0101","params":{}}`
if err := c.WriteMessage(websocket.TextMessage, []byte(sub)); err != nil {
log.Fatal("write:", err)
}
}
3) Handle messages (server → client)
After subscribing you will receive:subscribe_response(ack, success or error)updatemessages (the live data)
subscribe_response (success)
{
"action": "subscribe",
"chain_id": 1,
"dataset_id": "0101",
"status": "success"
}
update
{
"chain_id": 1,
"dataset_id": "0101",
"is_reorg": false,
"data": {
"block_number": 12345678,
"block_hash": "7b5c0972efb6a0b5be4a4d4a0de5d1abd922478a53f32b2c717a800c862ba9e0",
"timestamp_utc": "2025-11-11T18:42:15.123Z",
"_tracing_id": "010100000000000000000000000000000000"
}
}
4) Unsubscribe (client → server)
Unsubscribe stops a stream without closing the WebSocket.wscat -c wss://api.blockdb.io/v1/evm/ \
-H "Authorization: Bearer $BLOCKDB_API_KEY" \
-x '{"action":"unsubscribe","chain_id":1,"dataset_id":"0101"}'
#include <libwebsockets.h>
#include <string.h>
#include <stdio.h>
static int callback_blockdb(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len) {
switch (reason) {
case LWS_CALLBACK_CLIENT_ESTABLISHED:
lws_callback_on_writable(wsi);
break;
case LWS_CALLBACK_CLIENT_WRITEABLE: {
unsigned char buf[LWS_PRE + 256];
unsigned char *p = &buf[LWS_PRE];
size_t n = sprintf((char *)p, "{\"action\":\"unsubscribe\",\"chain_id\":1,\"dataset_id\":\"0101\"}");
lws_write(wsi, p, n, LWS_WRITE_TEXT);
break;
}
default:
break;
}
return 0;
}
using System;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
class Program {
static async Task Main() {
using var ws = new ClientWebSocket();
ws.Options.SetRequestHeader("Authorization", $"Bearer {Environment.GetEnvironmentVariable("BLOCKDB_API_KEY")}");
await ws.ConnectAsync(new Uri("wss://api.blockdb.io/v1/evm/"), CancellationToken.None);
var msg = "{\"action\":\"unsubscribe\",\"chain_id\":1,\"dataset_id\":\"0101\"}";
await ws.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(msg)), WebSocketMessageType.Text, true, CancellationToken.None);
}
}
import json
def unsubscribe(ws):
ws.send(json.dumps({
"action": "unsubscribe",
"chain_id": 1,
"dataset_id": "0101"
}))
ws.send(JSON.stringify({
action: 'unsubscribe',
chain_id: 1,
dataset_id: '0101'
}));
package main
import (
"log"
"net/http"
"os"
"github.com/gorilla/websocket"
)
func main() {
header := http.Header{"Authorization": []string{"Bearer " + os.Getenv("BLOCKDB_API_KEY")}}
c, _, err := websocket.DefaultDialer.Dial("wss://api.blockdb.io/v1/evm/", header)
if err != nil {
log.Fatal("dial:", err)
}
defer c.Close()
unsub := `{"action":"unsubscribe","chain_id":1,"dataset_id":"0101"}`
if err := c.WriteMessage(websocket.TextMessage, []byte(unsub)); err != nil {
log.Fatal("write:", err)
}
}
{
"action": "unsubscribe",
"chain_id": 1,
"dataset_id": "0101",
"status": "success"
}
Next steps
- Browse available streams: EVM Streams Overview
- Common error patterns and payload shape: Errors
- Reconnect strategy and timeouts: Connection Management