service SwapStream
Two RPCs. StreamLive is the MVP surface; StreamFromCursor is defined in the proto and returns UNIMPLEMENTED until v1.1.
rpc StreamLive(StreamLiveRequest) returns (stream UnifiedSwap)GRPCdexploit.v1.SwapStream is a server-streaming RPC: one .proto file, a generated client in whichever language you work in, and eleven filter fields evaluated on our side so you receive only the trades you asked for. It runs over HTTP/2, so concurrent RPCs share one connection and the protocol's own flow control.
This is swap_stream.proto as published. Field numbers and types are the wire format itself. Compile this and your client knows every field, and its type, before a byte arrives.
swap_stream.protoproto3 · dexploit.v1syntax = "proto3";package dexploit.v1; service SwapStream { // Live tail. Streams every new swap matching the filter. rpc StreamLive(StreamLiveRequest) returns (stream UnifiedSwap); // Reserved for v1.1: the handler returns UNIMPLEMENTED today. rpc StreamFromCursor(StreamFromCursorRequest) returns (stream UnifiedSwap);} message StreamLiveRequest { SwapFilter filter = 1;} message SwapFilter { repeated string tokens = 1; // mints, base58; empty = all repeated string traders = 2; repeated string pools = 3; repeated string dexes = 4; // "pumpfun", "raydium_clmm", ... optional uint64 min_sol = 5; // lamports optional uint64 max_sol = 6; optional uint64 min_token_amount = 7; optional uint64 max_token_amount = 8; optional bool is_buy = 9; optional string signature = 10; repeated string wallet_tags = 11; // Pro tier} message UnifiedSwap { string signature = 1; uint64 slot = 2; int64 timestamp = 3; // unix epoch seconds string dex = 4; string trader = 5; string token_mint = 6; string pool_address = 7; bool is_buy = 8; uint64 amount_in = 9; uint64 amount_out = 10; uint64 sol_amount = 11; // lamports uint64 token_amount = 12; // raw token units optional double price_per_token = 13; // SOL per token repeated string trader_tags = 14; uint32 ix_index = 15; // per-leg ordinal}$ grpcurl -H 'x-api-key: ohlcv_live_sk_...' \
grpc.dexploit.dev:443 list
dexploit.v1.PriceStream
dexploit.v1.SwapStreamReflection is enabled, so the service set resolves without the file. grpcurl will describe any message in it too.
wss://ws.dexploit.dev/ws/swapsconnectingA browser cannot open an HTTP/2 gRPC stream, so this tape is the JSON WebSocket feed, live. Same decoder, same trades. Over gRPC each of these rows arrives as one UnifiedSwap message instead.
A UnifiedSwap encoded to the schema above, beside the WebSocket frame for the same fill. Both figures are measurements: the frame length as the upstream socket sent it, and the protobuf length produced in your browser. Toggle a field to see what it costs on each wire.
the 15 selected fields serialised as JSON
encoded to the published proto3 schema in this browser, just now
fewer bytes on the wire for this swap, computed from the two measurements above
Protobuf omits a field at its default (a false is_buy, a zero ix_index, an empty tag list), which is why a sell costs fewer bytes than a buy. Decoding is not free on either side; what changes is how many bytes cross the wire, and whether your client learns the field types from a schema or from the payload.
SwapStream.StreamLiveLive UnifiedSwap tail, filtered server-sideSwapStream.StreamFromCursorReserved for v1.1: returns UNIMPLEMENTEDPriceStream.SubscribeDexTransaction price updates, per protocoltokens / traders / poolsrepeated stringBase58 addresses. An empty list means every one of them, not none
dexesrepeated stringVenue ids in snake_case: pumpfun, pumpswap, raydium_clmm, orca
min_sol / max_soloptional uint64Lamports, not SOL. 1 SOL is 1000000000
min_token_amount / max_token_amountoptional uint64Raw base units, before any decimals adjustment
is_buyoptional boolOmit the field entirely to receive both directions
signatureoptional stringExact match, for pinning one transaction while debugging
wallet_tagsrepeated stringsmart_money, sniper, whale, insider. Pro tier; below it the server drops the filter and says so in initial metadata
signaturestringBase58 transaction signature, not unique on its own
slotuint64Solana slot the trade landed in
timestampint64Unix epoch seconds, signed so it round-trips the internal i64
dexstringVenue id, snake_case, same vocabulary the filter takes
traderstringSigner wallet
token_mintstringThe non-SOL side of the trade
pool_addressstringPool or bonding-curve account
is_buyboolTrue when the token was bought
amount_in / amount_outuint64Raw atomic units as the instruction carried them
sol_amountuint64Lamports: divide by 1e9 for SOL
token_amountuint64Base units: divide by 10^decimals
price_per_tokenoptional doubleSOL per token, already decimal-adjusted. Absent when pool reserves were unavailable
trader_tagsrepeated stringWallet tags carried on the trader, same vocabulary as the filter
ix_indexuint32Per-leg ordinal inside the transaction; 0 means legacy or unknown
signatureOne transaction can carry several swaps. Router and aggregator trades emit a UnifiedSwap per leg, all sharing a signature and a slot. ix_index is the per-leg ordinal, so key on the pair. Dedupe on the signature alone and you drop legs silently.
uint64sol_amount is lamports and token_amount is raw base units; only price_per_token is decimal-adjusted. A uint64 also does not fit a JavaScript number, so generated clients hand it back as a string or a Long depending on your loader options.
backpressureEvery stream gets a 1024-event server-side buffer. Fall further behind and the server cancels the stream: RESOURCE_EXHAUSTED: client too slow; buffer overflow. A tab left in the background for a few seconds during a busy window is enough, so treat reconnecting as normal operation.
keepaliveSet keepalive_time_ms, keepalive_timeout_ms and keepalive_permit_without_calls on the channel. Without them a half-open TCP connection is indistinguishable from a quiet market: the stream looks alive and delivers nothing.
Take gRPC for indexers, bots and backend services, where a typed client and flow control matter. Everything else reads the same decoded record off one key.
wss://ws.dexploit.dev/ws/swapsThe same events as JSON, browser-nativeapi.dexploit.dev/api/v1Candles and history, no connection to hold openapi.dexploit.dev/graphqlOne query, exactly the fields you asked fordecoded order flowWhat the records mean, and what to build on themCodegen against this and the names will match. SwapFilter is where the eleven server-side filters live.
Two RPCs. StreamLive is the MVP surface; StreamFromCursor is defined in the proto and returns UNIMPLEMENTED until v1.1.
rpc StreamLive(StreamLiveRequest) returns (stream UnifiedSwap)Tokens, traders, pools and venues as repeated strings; size and amount bounds; direction; a signature lookup; and wallet tags. Applied before the bytes are sent.
tokens=1 traders=2 pools=3 dexes=4 min_sol=5 max_sol=6
min_token_amount=7 max_token_amount=8 is_buy=9
signature=10 wallet_tags=11One record shape for every venue, with trader tags attached and a per-leg ordinal so multi-leg transactions keep their execution order.
signature slot timestamp dex trader token_mint
pool_address is_buy amount_in amount_out sol_amount
token_amount price_per_token trader_tags ix_indexThis transport starts on Pro ($199/mo). Not included on Starter or Developer.
Limits are per second. The plans have no monthly request quota, so none is quoted here.