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
| Parameter | In | Type | Notes |
|---|---|---|---|
token | path | string | the token contract, 0x-prefixed, 40 hex characters, any case |
limit | query | integer, optional | 1..100, default 25 |
cursor | query | string, optional | nextCursor of the previous page, unchanged |
from | query | string, optional | only transfers sent by this address |
to | query | string, optional | only transfers received by this address |
eventType | query | string, optional | one event kind: transfer, transfer_single, transfer_batch, sent, minted, burned, deposit, withdraw |
fromBlock | query | integer, optional | inclusive lower block bound |
toBlock | query | integer, optional | inclusive 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.
valueis in the token's smallest unit, not divided bydecimals. Readdecimalsfrom one token contract. fromis not always the sender of the transaction. When a router, an aggregator or a batch disburser moves tokens,fromis the balance that decreased andtxSenderis who signed the transaction. WheretxSendercould not be resolved it is absent —fromnever 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 afromBlock/toBlockwindow. 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
| Field | Meaning |
|---|---|
chainId | 1, Ethereum mainnet |
token | the token contract, lowercase |
transfers[] | at most limit rows, newest first |
nextCursor | pass it back as cursor for the next page. Absent on the last page |
A transfer
| Field | Meaning |
|---|---|
blockNumber | the block the transfer was emitted in |
txIndex | the transaction's position in the block |
logIndex | the log's position in the block |
batchIndex | position inside an ERC-1155 TransferBatch; 0 for every other event |
txHash | the transaction that emitted the transfer. Absent when it could not be resolved for this page |
timestamp | block time, Unix seconds. Absent when it could not be resolved |
eventType | transfer, 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 |
from | the sender of the transfer. Absent on a mint |
to | the receiver of the transfer. Absent on a burn |
value | the amount in the token's smallest unit, a decimal string. Absent on an ERC-721 transfer |
tokenId | the token id of an ERC-721 or ERC-1155 transfer, a decimal string |
operator | the operator of an ERC-1155 transfer |
txSender | who sent the transaction that emitted the transfer. Absent when it could not be resolved |
txTo | the 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": { … } } }
| Status | code | When | details |
|---|---|---|---|
| 400 | bad_request | a filter on a token this active, without a narrow enough block window | reason: filter_needs_block_window, filters, rowCount, maxUnboundedRowCount, spanBlocks, maxSpanBlocks |
| 400 | bad_request | eventType outside the list above | reason: event_type_invalid, eventType |
| 400 | bad_request | fromBlock above toBlock | reason: block_window_inverted, fromBlock, toBlock |
| 400 | bad_request | limit outside 1..100 | reason: limit_out_of_range, maxLimit: 100 |
| 400 | invalid_cursor | the 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.
Related pages
- One token contract — the token's standard, decimals and counts
- Token holders — who holds the token now
- Token transfers of an address — the other direction: every token one address moved
- Tokens & Assets — the token's entity page in the app
Last updated 22 Oct 2026, 08:06 UTC · verified against TraceFast v1.0.261 · Markdown