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

Early access

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