hl_getBatchBlocks
Return fill blocks in a [from, to] range for a given stream.
When to Use This Method#
hl_getBatchBlocks is essential for:
- Backfilling — Retrieve historical fill data in bulk
- Batch Processing — Process trade events in ordered block ranges
- Analytics Pipelines — Feed fill data into downstream systems
- Reconciliation — Verify trade execution across block ranges
Request#
Endpoint#
POST https://api-hyperliquid-mainnet-jsonrpc.n.dwellir.com/<API-KEY>/hypercore
Headers#
| Header | Value | Required |
|---|---|---|
Content-Type | application/json | Yes |
Parameters#
| Field | Type | Required | Description |
|---|---|---|---|
stream | string | Yes | Data stream. Must be "trades" |
from | integer | Yes | First block number (inclusive, must be > 0) |
to | integer | Yes | Last block number (inclusive, must be >= from) |
The range is capped at 100 blocks per request by default.
Example Request#
{
"jsonrpc": "2.0",
"method": "hl_getBatchBlocks",
"params": { "stream": "trades", "from": 907626062, "to": 907626064 },
"id": 1
}
Response#
Success Response#
{
"jsonrpc": "2.0",
"result": {
"blocks": [
{
"local_time": "2026-02-27T09:58:16.738110784",
"block_time": "2026-02-27T09:58:16.410825222",
"block_number": 907626062,
"events": [
[
"0x9f9a72b449783e6a7e9afca2efa49a6b77793555",
{
"coin": "ETH",
"px": "2010.8",
"sz": "0.02",
"side": "B",
"time": 1772186296410,
"startPosition": "0.0543",
"dir": "Open Long",
"closedPnl": "0.0",
"hash": "0x92bca362a1e7aad59436043619464e0203a000483ceac9a736854eb560eb84c0",
"oid": 331832891533,
"crossed": false,
"fee": "0.005791",
"tid": 379919209298471,
"feeToken": "USDC",
"twapId": null
}
],
[
"0xf8ae6942b61c6cd0333d174244f2be138626a89e",
{
"coin": "ETH",
"px": "2010.8",
"sz": "0.02",
"side": "A",
"time": 1772186296410,
"startPosition": "0.0",
"dir": "Open Short",
"closedPnl": "0.0",
"hash": "0x92bca362a1e7aad59436043619464e0203a000483ceac9a736854eb560eb84c0",
"oid": 331834694017,
"crossed": true,
"fee": "0.017373",
"tid": 379919209298471,
"feeToken": "USDC",
"twapId": null
}
]
]
},
{
"local_time": "2026-02-27T09:58:16.935172042",
"block_time": "2026-02-27T09:58:16.511724597",
"block_number": 907626064,
"events": []
}
]
},
"id": 1
}
Response Fields#
| Field | Type | Description |
|---|---|---|
blocks | array | Array of block objects in the requested range |
Block Object#
| Field | Type | Description |
|---|---|---|
block_number | integer | Block number (height) |
block_time | string | ISO-8601 timestamp from the upstream source |
local_time | string | ISO-8601 timestamp when the block was received locally |
events | array | Array of fill events in this block (may be empty) |
Fill Event#
Each event is a two-element array: [address, fill], where address is the trader's hex address and fill is an object with the following fields:
| Field | Type | Description |
|---|---|---|
coin | string | Asset symbol (e.g. "ETH", "HYPE", "xyz:XYZ100") |
px | string | Execution price |
sz | string | Fill size |
side | string | "B" (buy) or "A" (sell/ask) |
time | integer | Unix timestamp in milliseconds |
startPosition | string | Position size before this fill |
dir | string | Trade direction (e.g. "Open Long", "Open Short", "Close Long", "Close Short") |
closedPnl | string | Realized PnL from this fill |
hash | string | Transaction hash |
oid | integer | Order ID |
crossed | boolean | Whether the order crossed the spread (taker) |
fee | string | Fee charged (negative means rebate) |
tid | integer | Trade ID |
feeToken | string | Token used for fee payment (e.g. "USDC") |
twapId | integer | null | TWAP order ID, if applicable |
cloid | string | Client order ID (optional, present when set by the trader) |
Error Response#
{
"jsonrpc": "2.0",
"error": { "code": -32602, "message": "from must be > 0" },
"id": 1
}
Code Examples#
- cURL
- JavaScript
- Python
- Go
curl -s https://api-hyperliquid-mainnet-jsonrpc.n.dwellir.com/<API-KEY>/hypercore \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"method": "hl_getBatchBlocks",
"params": { "stream": "trades", "from": 907626062, "to": 907626064 },
"id": 1
}' | jq .
const ENDPOINT = 'https://api-hyperliquid-mainnet-jsonrpc.n.dwellir.com/<API-KEY>/hypercore';
async function getBatchBlocks(from, to, stream = 'trades') {
const response = await fetch(ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
method: 'hl_getBatchBlocks',
params: { stream, from, to },
id: 1
})
});
const data = await response.json();
if (data.error) {
throw new Error(`JSON-RPC error ${data.error.code}: ${data.error.message}`);
}
return data.result.blocks;
}
// Usage
const blocks = await getBatchBlocks(907626062, 907626064);
console.log(`Received ${blocks.length} blocks`);
for (const block of blocks) {
console.log(`Block ${block.block_number}: ${block.events.length} events at ${block.block_time}`);
}
import requests
ENDPOINT = 'https://api-hyperliquid-mainnet-jsonrpc.n.dwellir.com/<API-KEY>/hypercore'
def get_batch_blocks(from_block: int, to_block: int, stream: str = 'trades') -> list:
"""Retrieve a batch of fill blocks for the given range."""
response = requests.post(
ENDPOINT,
json={
'jsonrpc': '2.0',
'method': 'hl_getBatchBlocks',
'params': {'stream': stream, 'from': from_block, 'to': to_block},
'id': 1
},
headers={'Content-Type': 'application/json'},
timeout=30
)
response.raise_for_status()
data = response.json()
if 'error' in data:
raise Exception(f"JSON-RPC error {data['error']['code']}: {data['error']['message']}")
return data['result']['blocks']
# Usage
blocks = get_batch_blocks(907626062, 907626064)
print(f"Received {len(blocks)} blocks")
for block in blocks:
print(f"Block {block['block_number']}: {len(block['events'])} events at {block['block_time']}")
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
const Endpoint = "https://api-hyperliquid-mainnet-jsonrpc.n.dwellir.com/<API-KEY>/hypercore"
type JSONRPCRequest struct {
JSONRPC string `json:"jsonrpc"`
Method string `json:"method"`
Params interface{} `json:"params"`
ID int `json:"id"`
}
type BatchBlocksParams struct {
Stream string `json:"stream"`
From int64 `json:"from"`
To int64 `json:"to"`
}
type Block struct {
BlockNumber int64 `json:"block_number"`
BlockTime string `json:"block_time"`
LocalTime string `json:"local_time"`
Events json.RawMessage `json:"events"`
}
type BatchBlocksResult struct {
Blocks []Block `json:"blocks"`
}
type JSONRPCResponse struct {
JSONRPC string `json:"jsonrpc"`
Result *BatchBlocksResult `json:"result,omitempty"`
Error *struct {
Code int `json:"code"`
Message string `json:"message"`
} `json:"error,omitempty"`
ID int `json:"id"`
}
func getBatchBlocks(from, to int64) ([]Block, error) {
reqBody, _ := json.Marshal(JSONRPCRequest{
JSONRPC: "2.0",
Method: "hl_getBatchBlocks",
Params: BatchBlocksParams{Stream: "trades", From: from, To: to},
ID: 1,
})
resp, err := http.Post(Endpoint, "application/json", bytes.NewBuffer(reqBody))
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var result JSONRPCResponse
if err := json.Unmarshal(body, &result); err != nil {
return nil, err
}
if result.Error != nil {
return nil, fmt.Errorf("JSON-RPC error %d: %s", result.Error.Code, result.Error.Message)
}
return result.Result.Blocks, nil
}
func main() {
blocks, err := getBatchBlocks(907626062, 907626064)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Received %d blocks\n", len(blocks))
for _, block := range blocks {
fmt.Printf("Block %d at %s\n", block.BlockNumber, block.BlockTime)
}
}
Common Use Cases#
1. Sequential Backfill#
Fetch all blocks from a known starting point to the latest:
async function backfill(startBlock) {
const response = await fetch(ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
method: 'hl_getLatestBlockNumber',
params: ['trades'],
id: 1
})
});
const { result: latestBlock } = await response.json();
let current = startBlock;
while (current <= latestBlock) {
const to = Math.min(current + 99, latestBlock);
const blocks = await getBatchBlocks(current, to);
console.log(`Fetched blocks ${current}–${to}: ${blocks.length} blocks`);
for (const block of blocks) {
// Process each block
}
current = to + 1;
}
}
2. Event Counting#
Count fill events across a block range:
def count_events(from_block: int, to_block: int) -> dict:
blocks = get_batch_blocks(from_block, to_block)
total_events = 0
for block in blocks:
total_events += len(block['events'])
return {
'block_range': f"{from_block}–{to_block}",
'blocks_returned': len(blocks),
'total_events': total_events
}
Error Handling#
| Error Code | Cause | Solution |
|---|---|---|
| -32602 | from must be > 0 | Ensure from is a positive integer |
| -32602 | to must be >= from | Ensure to is greater than or equal to from |
| -32602 | Range exceeds max batch size | Reduce the range to 100 blocks or fewer |
| -32602 | Unsupported stream | Use "trades" as the stream value |
| -32600 | Array-wrapped request | Send a single JSON-RPC object, not an array |
| -32700 | Malformed JSON | Validate your request JSON |
Best Practices#
- Respect the batch limit — Keep ranges at or below 100 blocks per request
- Use sequential fetching — Combine with
hl_getLatestBlockNumberto walk forward - Handle sparse ranges — Some blocks in a range may have no events
- Implement retries — Use exponential backoff for transient errors
Related Methods#
- hl_getLatestBlockNumber — Get the latest available block number
Query HyperCore fill data with Dwellir's JSON-RPC API. Get your API key →