Make your first Portal request to access raw Solana blockchain data in under 5 minutes. No setup required—just HTTP requests.
What You’ll Build
In this quickstart, you’ll:
Make a simple Portal request using curl (no installation required)
Query recent Solana slots
Filter instructions from a specific program
This guide uses the Public Portal endpoint, which is free and
rate-limited. Perfect for getting started.
Step 1: Your First Request
Let’s query 200 slots from Solana mainnet and get block data with transaction counts. Copy and paste this command:
curl --compressed -X POST 'https://portal.sqd.dev/datasets/solana-mainnet/stream' \
-H 'Content-Type: application/json' \
-d '{
"type": "solana",
"fromBlock": 259984800,
"toBlock": 259984801,
"fields": {
"block": {
"number": true,
"timestamp": true
},
"transaction": {
"signatures": true,
"feePayer": true,
"err": true
}
},
"transactions": [{}]
}'
You should see a stream of JSON objects, one per block, showing slot numbers,
timestamps, and transaction data including signatures, fee payers, and success
status.
Try it yourself with the interactive query interface below:
First, install the client: npm install @subsquid/portal-client
Then run this code: import { DataSource } from "@subsquid/portal-client" ;
const dataSource = new DataSource ({
network: "solana-mainnet" ,
});
const blocks = await dataSource . getBlocks ({
from: 259984800 ,
to: 259985000 ,
fields: {
block: {
number: true ,
timestamp: true ,
},
transaction: {
signatures: true ,
feePayer: true ,
err: true ,
},
},
transactions: [{}],
});
console . log ( `Retrieved ${ blocks . length } blocks` );
blocks . forEach (( block ) => {
const successCount = block . transactions . filter (
( tx ) => tx . err === null
). length ;
const failedCount = block . transactions . length - successCount ;
console . log (
`Slot ${ block . header . number } : ${ block . transactions . length } transactions ( ${ successCount } succeeded, ${ failedCount } failed)`
);
});
First, install requests: Then run this code: import requests
import json
url = "https://portal.sqd.dev/datasets/solana-mainnet/stream"
headers = { "Content-Type" : "application/json" }
payload = {
"type" : "solana" ,
"fromBlock" : 259984800 ,
"toBlock" : 259985000 ,
"fields" : {
"block" : {
"number" : True ,
"timestamp" : True
},
"transaction" : {
"signatures" : True ,
"feePayer" : True ,
"err" : True
}
},
"transactions" : [{}]
}
response = requests.post(url, headers = headers, json = payload)
# Response is newline-delimited JSON
for line in response.text.strip().split( ' \n ' ):
if line.strip(): # Skip empty lines
block = json.loads(line)
tx_count = len (block.get( 'transactions' , []))
success_count = sum ( 1 for tx in block.get( 'transactions' , []) if tx.get( 'err' ) is None )
failed_count = tx_count - success_count
print ( f "Slot { block[ 'header' ][ 'number' ] } : { tx_count } transactions ( { success_count } succeeded, { failed_count } failed)" )
Step 2: Understanding the Request
Let’s break down what you just sent:
{
"type" : "solana" , // Chain type (Solana)
"fromBlock" : 259984800 , // Starting slot number (inclusive, field name: fromBlock)
"toBlock" : 259985000 , // Ending slot number (inclusive, field name: toBlock)
"fields" : { // What data to return
"block" : {
"number" : true , // Slot number (field name: number)
"timestamp" : true // Block timestamp
},
"transaction" : {
"signatures" : true , // Transaction signatures
"feePayer" : true , // Fee payer address
"err" : true // Error status (null if successful)
}
},
"transactions" : [{}] // Include transactions filter (empty object = all transactions)
}
Portal only returns the fields you request. This keeps responses fast and
bandwidth-efficient.
Step 3: Understanding the Response
Portal returns JSON lines (JSONL) . Each line is a complete JSON object representing one block. Note that not every slot produces a block, so you’ll see gaps in the slot numbers:
{
"header" : {
"number" : 259984800 ,
"timestamp" : 1713053593
},
"transactions" : [
{
"signatures" : [ "5j7s8K9LmN2pQrS3tUvW4xYz5aB6cD7eF8gH9iJ0kL1mN2oP3qR4sT5uV6wX" ],
"feePayer" : "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM" ,
"err" : null
}
]
}
{
"header" : {
"number" : 259984837 ,
"timestamp" : 1713053611
},
"transactions" : [
{
"signatures" : [ "3kL4mN5oP6qR7sT8uV9wX0yZ1aB2cD3eF4gH5iJ6kL7mN8oP9qR0sT" ],
"feePayer" : "7qbRF6YsyGuLUVs6Y1q64bdVrfe4ZcUUz1JRdoVNUJnm" ,
"err" : null
}
]
}
{
"header" : {
"number" : 259984838 ,
"timestamp" : 1713053612
},
"transactions" : []
}
This format enables constant-memory streaming of massive ranges. You can
process millions of slots without loading everything into RAM.
Step 4: Filter Instructions
Track instructions from the Orca Whirlpool program. This example queries a larger range to find actual instructions:
curl --compressed -X POST 'https://portal.sqd.dev/datasets/solana-mainnet/stream' \
-H 'Content-Type: application/json' \
-d '{
"type": "solana",
"fromBlock": 259984800,
"toBlock": 259985000,
"fields": {
"block": {
"number": true,
"timestamp": true
},
"instruction": {
"programId": true,
"accounts": true,
"data": true,
"transactionIndex": true
}
},
"instructions": [{
"programId": ["whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc"]
}]
}'
You should see instructions from the Orca Whirlpool program. Portal filtered
the data before sending, saving bandwidth.
What You Learned
In 5 minutes, you:
✓ Made HTTP requests to Portal
✓ Queried arbitrary slot ranges
✓ Filtered program instructions
✓ Processed newline-delimited JSON responses
Rate Limits
The Public Portal is rate-limited:
20 requests per 10 seconds
Perfect for development and testing
Cloud Portal Production-ready managed access with higher limits
Self-Host Portal Run your own Portal instance with no rate limits
Next Steps
API Reference Complete reference with all fields and filters
View Examples Practical examples for common use cases
Use with SDK Build type-safe indexers with Portal as the data source
Popular Examples
Query Instructions Track program instructions
Query Transactions Monitor wallet activity
Track Token Transfers Index SPL token activity
Index DEX Swaps Build DEX analytics