Solana curl Examples
Solana HyperSync is early, but the query shape used here is stable enough to build against. Only recent slots are retained (rolling window, see Overview); use GET /height instead of hard-coding how far back you can query.
Copy-paste examples against https://solana.hypersync.xyz. Pass the same API token as EVM HyperSync via Authorization: Bearer <token>; GET /height and /height/sse work without one.
curl is great for testing; for production, prefer the Solana client, which uses Arrow and handles pagination, retries, and rate limits for you.
export URL=https://solana.hypersync.xyz
export TOKEN="your-api-token"
# Only a rolling window of recent slots is served, so anchor ranges to the head
HEAD=$(curl -sS "$URL/height")
FROM=$((HEAD - 2000))
TO=$((HEAD - 1900))
# JSON POST helper (adds auth + content-type)
curl_query() {
curl -sS "$URL/query" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "$1"
}
The examples splice $FROM / $TO into single-quoted JSON with '$FROM'; a range below the retention floor returns empty tables with next_slot not advancing.
Discriminator filters accept hex with or without a 0x prefix. Every response table is an array of row batches, so the jq below flattens with [.table[][]] before indexing or counting (see Response).
Quick checks
curl -sS "$URL/height"
curl -sS -H "Authorization: Bearer $TOKEN" "$URL/health"
Head slot (SSE)
curl -sSN -H "Accept: text/event-stream" "$URL/height/sse"
Orca Whirlpool (swap discriminator)
8-byte Anchor discriminator. Example response shape (truncated):
curl_query '{
"from_slot": '$FROM',
"to_slot": '$TO',
"field_selection": {
"instruction_call": ["slot", "transaction_index", "executing_account", "account_arguments", "data", "d8"],
"transaction": ["slot", "signatures", "fee_payer", "success", "fee"]
},
"instruction_calls": [{
"executing_account": ["whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc"],
"d8": ["0xf8c69e91e17587c8"]
}]
}' | jq '{next_slot, sample_instruction: [.instruction_calls[][]][0], sample_tx: [.transactions[][]][0]}'
SPL Token Transfer (d1)
1-byte discriminator: 0x03 = Transfer (hex with or without 0x). Token movements come from the unified account_activity table (pre_token_balance / post_token_balance are raw base-unit decimal strings).
curl_query '{
"from_slot": '$FROM',
"to_slot": '$TO',
"field_selection": {
"instruction_call": ["slot", "executing_account", "account_arguments", "data", "d1"],
"account_activity": ["slot", "transaction_index", "account", "mint", "pre_owner", "post_owner", "token_state", "pre_token_balance", "post_token_balance"]
},
"instruction_calls": [{
"executing_account": ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"],
"d1": ["0x03"]
}]
}'
Wallet activity (native SOL + tokens)
account is the wallet on a native row and the token account on a token row, and fields within one selection are AND-ed, so "everything for wallet W" is two selections.
curl_query '{
"from_slot": '$FROM',
"to_slot": '$TO',
"field_selection": {
"account_activity": ["slot", "transaction_id", "account", "pre_balance", "post_balance", "mint", "pre_owner", "post_owner", "token_state", "pre_token_balance", "post_token_balance"]
},
"account_activity": [
{ "account": ["MfDuWeqSHEqTFVYZ7LoexgAK9dxk7cy4DFJWjWMGVWa"] },
{ "owner": ["MfDuWeqSHEqTFVYZ7LoexgAK9dxk7cy4DFJWjWMGVWa"] }
]
}'
To pull every activity row in a range (the replacement for the removed include_account_activity flag), use one empty selection:
curl_query '{
"from_slot": '$FROM',
"to_slot": '$TO',
"field_selection": { "account_activity": ["slot", "account", "pre_balance", "post_balance"] },
"account_activity": [{}]
}'
Successful transactions only
tx_success filters instruction calls by the success of their parent transaction, server-side.
curl_query '{
"from_slot": '$FROM',
"to_slot": '$TO',
"field_selection": {
"instruction_call": ["slot", "executing_account", "d8", "tx_success", "error", "compute_units_consumed"]
},
"instruction_calls": [{
"executing_account": ["whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc"],
"tx_success": true
}]
}'
Jupiter or Orca (program-only OR)
Each object in instruction_calls is OR-ed; this is the "match by program only" pattern (no discriminator).
curl_query '{
"from_slot": '$FROM',
"to_slot": '$TO',
"field_selection": {
"instruction_call": ["slot", "executing_account", "data", "d8"]
},
"instruction_calls": [
{ "executing_account": ["JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"] },
{ "executing_account": ["whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc"] }
]
}'
Transactions by fee payer
curl_query '{
"from_slot": '$FROM',
"to_slot": '$TO',
"field_selection": {
"transaction": ["slot", "signatures", "fee_payer", "success", "fee", "compute_units_consumed"],
"instruction_call": ["slot", "executing_account", "data", "account_arguments"]
},
"transactions": [{
"fee_payer": ["MfDuWeqSHEqTFVYZ7LoexgAK9dxk7cy4DFJWjWMGVWa"]
}]
}'
Pump.fun bonding-curve trades (account index)
a2 matches the third account in the instruction's account metas (a0 = first). For Pump.fun's buy/sell instructions the mint is account index 2 per that program's IDL, not a Solana-wide rule.
curl_query '{
"from_slot": '$FROM',
"to_slot": '$TO',
"field_selection": {
"instruction_call": ["slot", "executing_account", "account_arguments", "data", "d8", "a2"],
"transaction": ["slot", "fee_payer", "success"]
},
"instruction_calls": [{
"executing_account": ["6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"]
}]
}'
Raydium AMM logs
curl_query '{
"from_slot": '$FROM',
"to_slot": '$TO',
"field_selection": {
"log": ["slot", "program_id", "kind", "message"],
"transaction": ["slot", "fee_payer", "success"]
},
"logs": [{
"program_id": ["675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"]
}]
}'
Paginating a bounded scan
Use the same termination rule as Query & Response: stop when next_slot >= to_slot, or when next_slot does not advance (stuck at head).
SLOT=$FROM
while [ "$SLOT" -lt "$TO" ]; do
RESP=$(curl_query "{
\"from_slot\": $SLOT,
\"to_slot\": $TO,
\"field_selection\": { \"instruction_call\": [\"slot\", \"executing_account\", \"d8\"] },
\"instruction_calls\": [{ \"executing_account\": [\"whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc\"] }]
}")
echo "$RESP" | jq '([.instruction_calls[][]] | length), .next_slot'
NEXT=$(echo "$RESP" | jq -r .next_slot)
if [ "$NEXT" -ge "$TO" ] || [ "$NEXT" -le "$SLOT" ]; then
break
fi
SLOT=$NEXT
done