For AI agents: the documentation index is at /llms.txt. Markdown versions of pages are available by appending .md to the URL.
Skip to main content

Solana curl Examples

Copy-paste examples against https://solana.hypersync.xyz. You'll need an API token: generate one at https://envio.dev/app/api-tokens (see API tokens) and pass it 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).

Prefer clicking over typing? The HyperSync Query Builder builds and runs these same queries visually — several of the patterns below have a one-click Quick start template (linked inline); paste in your own token before executing.

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]}'

Try it: Query Builder → Quick start → Whirlpool Swaps (d8 Anchor).

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"]
}]
}'

Try it: Query Builder → Quick start → SPL Token Transfers (d1).

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"] }
]
}'

Try it: Query Builder → Quick start → Wallet Activity (account OR owner).

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": [{}]
}'

Try it: Query Builder → Quick start → All 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"] }
]
}'

Try it: Query Builder → Quick start → Jupiter OR Orca (multi-filter OR).

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"]
}]
}'

Try it: Query Builder → Quick start → Txns by Fee Payer.

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