Swaps & Trade Tape
Every non-vote, non-failed swap is parsed directly from the transaction across 25+ DEXes and routers, normalized into a single trade shape, and priced in USD and SOL at trade time (Price derived via on-chain oracles at exact execution time). Query recent trades over REST, or subscribe to the trade tape for every swap the moment it lands.
The trade object
Each trade carries identity, both sides of the swap (raw and UI-normalized), pricing, fees, and a classification fingerprint.
Identity & context
| Field | Type | Description |
|---|---|---|
trade_id | string | Stable unique id, {signature}:{event_index} |
signature | string | Transaction signature |
event_index | number | Swap leg index within the transaction |
slot | number | Solana slot |
timestamp | number | Trade time, unix ms |
wallet_address | string | The trader |
pool_address | string | Pool the swap routed through |
dex_name | string | Venue — Raydium, PumpFun, Meteora_DLMM, Whirlpool, … |
direction | string | buy · sell · swap · flash_swap |
Amounts
| Field | Type | Description |
|---|---|---|
token_mint | string | The traded token |
token_decimals | number | Token decimals |
token_amount | string | UI-normalized token amount (raw / 10^decimals) |
token_amount_raw | string | Raw on-chain amount |
base_mint | string | Quote side — WSOL, USDC, … |
base_decimals | number | Base decimals |
base_amount | string | UI-normalized base amount |
base_amount_raw | string | Raw on-chain base amount |
Pricing & fees
| Field | Type | Description |
|---|---|---|
usd_price | string | Unit price, USD per token |
usd_notional | string | Total USD value of the trade |
sol_price_usd | string | SOL/USD at trade time |
total_fees_usd | string | All-in fees (network + priority + router/terminal/Jito) |
fees_bps | string | Fees as basis points of notional |
network_fee_lamports | number | Base Solana network fee |
total_fees_lamports | number | All-in fees in lamports |
Classification
| Field | Type | Description |
|---|---|---|
is_arbitrage | 0 | 1 | Whether this leg is part of an arbitrage cycle |
bundle_id | string | Links to a coordinated bundle; empty when none |
labels | string[] | Tool, bot, and MEV fingerprint (see below) |
Amounts and prices are sent as decimal strings, not JSON numbers, so you never lose precision on large raw amounts or tiny unit prices. Parse them with a decimal library, not parseFloat.
Label fingerprint
labels is the per-trade fingerprint — how the trade was placed and what kind of actor placed it.
| Prefix | Values |
|---|---|
TERMINAL: | BLOOM AXIOM TROJAN PHOTON BULLX GMGN |
BOT: | HFT MEV WASH FLASH ARB MULTISELL MULTIBUY MULTIWALLET MALICIOUS |
MEV: | FRONTRUN BACKRUN SANDWICHED |
BUNDLE: | EXEC_CLUSTER |
| other | ORGANIC, DUST:POSITION_AUGMENT, DUST:SELL_PASSTHROUGH |
REST — recent trades
L1 GET /v1/token/{mint}/trades — recent trades for a token, newest first.
L2 GET /v1/wallet/{address}/trades — recent trades for a wallet.
| Parameter | In | Type | Default | Description |
|---|---|---|---|---|
mint / address | path | string | — | Token mint or wallet address |
limit | query | integer | 50 | Max rows (max 200) |
curl -H "Authorization: Bearer $API_KEY" \
"https://api.conyr.ai/v1/token/EPjFWd.../trades?limit=50"{
"trades": [
{
"signature": "5vGk...",
"slot": 271544901,
"event_index": 0,
"timestamp": 1709654400123,
"wallet_address": "7xKXtg...",
"pool_address": "8sLbNZ...",
"direction": "buy",
"dex_name": "Raydium",
"base_mint": "So11111111111111111111111111111111111111112",
"token_amount": 1250.0,
"base_amount": 0.85,
"base_price_usd": 182.4,
"total_fees_usd": 0.41,
"is_arbitrage": 0,
"bundle_id": "",
"labels": ["TERMINAL:PHOTON", "ORGANIC"]
}
]
}REST returns the classification fields too — labels, bundle_id, is_arbitrage, pool_address, base_mint, and event_index. The trade tape below adds the UI-normalized amounts (token_amount/base_amount plus _raw), the unit usd_price, fees_bps, token/base decimals, and per-trade FIFO position context.
Stream — trade tape
L1 Channel token:{mint}:trades
Every swap on the token, pushed sub-second as it lands, carrying the full trade object. On subscribe you also receive the last ~50 trades for the mint, so you can backfill and go live in one step.
const ws = new WebSocket("wss://api.conyr.ai/ws");
ws.onopen = () =>
ws.send(JSON.stringify({ op: "subscribe", channels: ["token:EPjFWd...:trades"] }));
ws.onmessage = (e) => {
const { channel, data } = JSON.parse(e.data);
if (channel?.endsWith(":trades")) console.log(data.direction, data.usd_notional, data.labels);
};flash_swap legs and arbitrage hops are tagged (direction, is_arbitrage, labels) rather than hidden — filter them client-side if you only want organic retail flow. The Chart Ticks stream carries a pre-computed organic/full flag per trade if that’s all you need.