Skip to content
TraceFast Docs

Transfers of a token

Open USDC on its entity page →

The transfer events of one token contract, newest first. Each row gives the parties, the raw amount or the token id, the kind of event, and the transaction that emitted it. The row also names who sent that transaction — for a transfer made through a router or a batch disburser, another party than from. The method covers ERC-20, ERC-721 and ERC-1155 tokens.

GET https://tracefast.xyz/api/v1/chains/1/tokens/{token}/transfers
ParameterInTypeNotes
tokenpathstringthe token contract, 0x-prefixed, 40 hex characters, any case
limitqueryinteger, optional1..100, default 25
cursorquerystring, optionalnextCursor of the previous page, unchanged
fromquerystring, optionalonly transfers sent by this address
toquerystring, optionalonly transfers received by this address
eventTypequerystring, optionalone event kind: transfer, transfer_single, transfer_batch, sent, minted, burned, deposit, withdraw
fromBlockqueryinteger, optionalinclusive lower block bound
toBlockqueryinteger, optionalinclusive upper block bound

Access — an API key on the Enriched Data plan or higher (plans), or no key at all: pay per call with x402 at the same path on https://mpp.tracefast.xyz/api/v1, at the price its 402 states. As a tool for AI agents: get_token_transfers on the MCP server. Stable — see stability.

chains/1 is a literal: the method serves Ethereum mainnet data. Other chain ids answer 404 chain_not_supported. An unknown parameter is refused rather than ignored.

What it covers, and what it does not

  • Amounts are raw. value is in the token's smallest unit, not divided by decimals. Read decimals from one token contract.
  • from is not always the sender of the transaction. When a router, an aggregator or a batch disburser moves tokens, from is the balance that decreased and txSender is who signed the transaction. Where txSender could not be resolved it is absent — from never stands in for it.
  • Filters on a very active token need a block window. Paging without filters always works. A filter (from, to, eventType) searches the token's transfers, so on a token with a very large history it is answered only inside a fromBlock/toBlock window. The refusal names the widest window it accepts — see Errors.

Response

200 application/json, here with ?limit=2:

{
  "data": {
    "chainId": 1,
    "token": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
    "transfers": [
      {
        "blockNumber": 25925128,
        "txIndex": 237,
        "logIndex": 716,
        "batchIndex": 0,
        "txHash": "0x0c953a577624be925991571d9f0adf7f5bba9e1ae5fc5d9a60c738792f33cecd",
        "timestamp": 1788779879,
        "eventType": "transfer",
        "from": "0xe33fb59786b0e8adf5972759c787a156c694d2a8",
        "to": "0xff0f50fa7016e4390cb6b069347c635cfd035c6b",
        "value": "200000000",
        "txSender": "0x619dffb5c59b092b8d868efa25c1d0b0b1bccd19",
        "txTo": "0xe33fb59786b0e8adf5972759c787a156c694d2a8"
      },
      {
        "blockNumber": 25925128,
        "txIndex": 235,
        "logIndex": 714,
        "batchIndex": 0,
        "txHash": "0xb01e9fa0beaf5bca62a95315ce80de2d7ff33c2a689229a9a5e02a3a310825cc",
        "timestamp": 1788779879,
        "eventType": "transfer",
        "from": "0x743472aa513a7c050a862963acec7e06ce113d63",
        "to": "0x70cc38630e50dbac20de11cb4213db8a5946a4df",
        "value": "79793301",
        "txSender": "0x3791087aeb5f774dd99bc0433dab386c407ab4a0",
        "txTo": "0x743472aa513a7c050a862963acec7e06ce113d63"
      }
    ],
    "nextCursor": "AVsyNTkyNTEyOCwyMzUsMCwwXew1M9499CrgCiFPrF6cASE"
  },
  "meta": {
    "chain": "ethereum",
    "timestamp": 1789047647633,
    "cached": false,
    "docs": "https://docs.tracefast.xyz/api/token-transfers"
  }
}

In the first row, from is a contract that the transaction called (txTo), and txSender is the account that signed the transaction.

data

FieldMeaning
chainId1, Ethereum mainnet
tokenthe token contract, lowercase
transfers[]at most limit rows, newest first
nextCursorpass it back as cursor for the next page. Absent on the last page

A transfer

FieldMeaning
blockNumberthe block the transfer was emitted in
txIndexthe transaction's position in the block
logIndexthe log's position in the block
batchIndexposition inside an ERC-1155 TransferBatch; 0 for every other event
txHashthe transaction that emitted the transfer. Absent when it could not be resolved for this page
timestampblock time, Unix seconds. Absent when it could not be resolved
eventTypetransfer, transfer_single, transfer_batch, sent, minted, burned, deposit or withdraw. deposit and withdraw are the events of ERC-4626 vaults; wrapping ether into WETH is not among the transfers
fromthe sender of the transfer. Absent on a mint
tothe receiver of the transfer. Absent on a burn
valuethe amount in the token's smallest unit, a decimal string. Absent on an ERC-721 transfer
tokenIdthe token id of an ERC-721 or ERC-1155 transfer, a decimal string
operatorthe operator of an ERC-1155 transfer
txSenderwho sent the transaction that emitted the transfer. Absent when it could not be resolved
txTothe contract the transaction called at the top level. Absent when it could not be resolved, or on a contract creation

Pagination

The feed pages by keyset. Pass nextCursor back as cursor, with the same filters, until nextCursor is absent. A cursor is valid only for this method, this token and these filters; any other use answers 400 invalid_cursor, and the recovery is to restart from the first page. A page can hold fewer than limit rows while nextCursor is still present. See pagination.

Errors

Every error is JSON: { "error": { "code": "...", "message": "...", "details": { … } } }

StatuscodeWhendetails
400bad_requesta filter on a token this active, without a narrow enough block windowreason: filter_needs_block_window, filters, rowCount, maxUnboundedRowCount, spanBlocks, maxSpanBlocks
400bad_requesteventType outside the list abovereason: event_type_invalid, eventType
400bad_requestfromBlock above toBlockreason: block_window_inverted, fromBlock, toBlock
400bad_requestlimit outside 1..100reason: limit_out_of_range, maxLimit: 100
400invalid_cursorthe cursor is not valid for this request — restart from the first page—

A refused filter looks like this. Pass a fromBlock/toBlock window no wider than maxSpanBlocks, or drop the filter:

{
  "error": {
    "code": "bad_request",
    "message": "filtering this token by from needs a block window of at most 50400 blocks (requested span 25925128). Pass fromBlock/toBlock. Paging without filters is unaffected.",
    "details": {
      "reason": "filter_needs_block_window",
      "filters": "from",
      "rowCount": "…",
      "maxUnboundedRowCount": "…",
      "spanBlocks": 25925128,
      "maxSpanBlocks": 50400
    }
  }
}

Read the bounds from details, not from message; they can change.

Malformed input, unknown parameters and the key check's 401/403/429 are the same for every method — see conventions and API keys.


Last updated 22 Oct 2026, 08:06 UTC · verified against TraceFast v1.0.261 · Markdown