API ReferenceSwaps & Trade Tape
Live

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

FieldTypeDescription
trade_idstringStable unique id, {signature}:{event_index}
signaturestringTransaction signature
event_indexnumberSwap leg index within the transaction
slotnumberSolana slot
timestampnumberTrade time, unix ms
wallet_addressstringThe trader
pool_addressstringPool the swap routed through
dex_namestringVenue — Raydium, PumpFun, Meteora_DLMM, Whirlpool, …
directionstringbuy · sell · swap · flash_swap

Amounts

FieldTypeDescription
token_mintstringThe traded token
token_decimalsnumberToken decimals
token_amountstringUI-normalized token amount (raw / 10^decimals)
token_amount_rawstringRaw on-chain amount
base_mintstringQuote side — WSOL, USDC, …
base_decimalsnumberBase decimals
base_amountstringUI-normalized base amount
base_amount_rawstringRaw on-chain base amount

Pricing & fees

FieldTypeDescription
usd_pricestringUnit price, USD per token
usd_notionalstringTotal USD value of the trade
sol_price_usdstringSOL/USD at trade time
total_fees_usdstringAll-in fees (network + priority + router/terminal/Jito)
fees_bpsstringFees as basis points of notional
network_fee_lamportsnumberBase Solana network fee
total_fees_lamportsnumberAll-in fees in lamports

Classification

FieldTypeDescription
is_arbitrage0 | 1Whether this leg is part of an arbitrage cycle
bundle_idstringLinks to a coordinated bundle; empty when none
labelsstring[]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.

PrefixValues
TERMINAL:BLOOM AXIOM TROJAN PHOTON BULLX GMGN
BOT:HFT MEV WASH FLASH ARB MULTISELL MULTIBUY MULTIWALLET MALICIOUS
MEV:FRONTRUN BACKRUN SANDWICHED
BUNDLE:EXEC_CLUSTER
otherORGANIC, 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.

ParameterInTypeDefaultDescription
mint / addresspathstringToken mint or wallet address
limitqueryinteger50Max 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.