Skip to content

What may be empty

Every documented field is always present — the shape of an event does not change with its data. What does change is whether a field carries a value, and a few of those cases are worth knowing before you build against them.

How emptiness is spelled

Kind of fieldWhen there is no value
Address (pool, lpMint, counterparty, transfer endpoints)null
List (fees, transfers, liquidity, tokens, route.hops)[]
Amount or object (priorityFee, creatorBuy)null
reservesnull, and it means something — see below

One check per field, always the same one. The single exception is reserves, where null is a statement rather than an absence: it says the transaction could not prove the pool's depth at that moment, not that the pool is empty.

Fields that are often absent

pool is not exposed by every venue. When we cannot attribute the swap to a pool account, it is null and the rest of the event is unaffected.

valueUsd needs one leg priced in SOL or a stablecoin. A token-to-token swap has no such leg, so it is null — and threshold filters let those events through rather than hiding a whole class of trades. This is deliberate: see minUsdAmount.

blockTime is null while the network has not supplied the block's time yet. We deliver the event immediately instead of holding it back.

from and to on a token transfer: a mint has no source and a burn has no destination, so one end is null for those two kinds. The same applies to counterparty on a wallet transfer.

Unnamed venues

protocol carries the slug of the venue a trade settled on. If the program it went through is not in our registry, the event still arrives in full — trade type, wallet, both legs, amounts — and only the venue name is unknown, delivered as protocol: "unknown". Behind these are usually one-off programs that market participants run for themselves, and venues with very little volume.

This is worth accounting for in two places. Do not validate protocol against a list of known values; the set is open and grows. And a platforms filter excludes these trades, so if you want the whole flow for a token, leave the filter out.

Transfer lists are filtered, not raw

transfers[] on a trade is a shortlist: movements that stand on their own, such as tips, payouts and mints. The rows that merely re-state what the event already carries — the swap's own legs, the fees — are left out, and that is most of a transaction's ledger.

So transfers[] deliberately does not add up to the transaction you would see in an explorer. When you need the complete ledger, that is what includeRaw is for.

Two details about the rows themselves:

  • from and to are owner wallets, not token accounts. Native SOL has no token account at all, so there the wallet is the only address there is.
  • memo appears only inside these rows, never on the event itself. A memo belongs to a ledger row, and there is no way to attribute it to the action the event describes — so we do not guess.

Amounts

Every amount comes as a pair of strings, and both are strings on purpose:

json
{ "mint": "So111...", "amountRaw": "14841398823", "amount": "14.841398823" }

amountRaw is an integer in the token's smallest units; amount is adjusted for decimals. Keep them as strings or parse them with an arbitrary-precision decimal type — a double cannot hold every raw token amount exactly.

Realtime Solana data API