---
title: "List an address's token transfers"
method: GET
path: "/{chain}/addresses/{address}/transfers"
tags: ["Addresses"]
---

# List an address's token transfers

`GET /{chain}/addresses/{address}/transfers`

## Request

- Base URL: `https://api.blockvectra.com/v1/data`
- URL: `https://api.blockvectra.com/v1/data/{chain}/addresses/{address}/transfers`
- Auth: API key in header `x-api-key`

Keyset-paginated list of token transfers involving an address within a mandatory block window (`from_block` and `to_block` are both required). Ordered by `(block_number, log_index)` descending.

`direction=in|out|any` (defaults to `any`) filters by transfer direction relative to `{address}`. `token` optionally filters transfers for a specific token contract. `standard` must be `erc20` or `erc721`; `erc1155` returns `422 no_coverage`. Opaque pagination token from the previous response's `next_cursor`; pass it back unchanged.

**Window and head clamping**: `to_block` above `as_of_block` is `409 not_indexed_yet` unless `clamp=true`, which truncates `to_block` down to `as_of_block` (never possible when `from_block` is *itself* already past it — that stays a hard 409 regardless of `clamp`). `meta.finalized_block` is a marker and never bounds a window. A window wider than 100,000 blocks is `409 window_too_large` unless `clamp=true`, which truncates from the older end (raises `from_block`, keeps `to_block` fixed). The window's lower bound is computed per dataset, not from the chain's start alone: the per-address ERC-20 / ERC-721 transfer index is a derived dataset, and while its backfill is still filling older blocks its data starts above `GET /chains` `coverage.from_block`. The dataset's start only counts when it is higher than the start of the token-transfer data it is derived from (a chain with no transfer at its beginning is not a gap). A window entirely before that start is `422 no_coverage`; one that starts before it is partial, and `clamp=true` raises `from_block` to that start before the 100,000-block limit is applied. Limitation: during an *ascending* backfill the hole between the backfilled tail and the live start is not detected (the dataset's start is its lowest covered block), so a window inside that hole is still `200` with an empty list. When clamped or partial, `meta.coverage = "partial"` (`"full"` otherwise).

## Path parameters

- `chain` string, required
- `address` string, required: 20-byte address. `0x`/`0X` prefix optional; either hex digit case is accepted.

## Query parameters

- `standard` 'erc20' | 'erc721' | 'erc1155', required
- `token` string: 20-byte address. `0x`/`0X` prefix optional; either hex digit case is accepted.
- `from_block` integer, required
- `to_block` integer, required
- `direction` 'in' | 'out' | 'any'
- `clamp` string
- `limit` integer
- `cursor` string

## Response `200`

This address's token transfers.

- AddressTransferListEnvelope: `next_cursor` is present only when the page returned exactly `limit` rows (optimistic pagination: it may turn out to be the last page anyway).
  - `data` union[], required
    - union
      - Erc20Transfer
        - `token` string, required: 20-byte address, canonical form always `0x` + 40 lowercase hex digits.
        - `standard` 'erc20', required
        - `from` string, required: 20-byte address, canonical form always `0x` + 40 lowercase hex digits.
        - `to` string, required: 20-byte address, canonical form always `0x` + 40 lowercase hex digits.
        - `amount` string, required: Non-negative integer that may exceed 2^53, rendered as a plain decimal string — never a JSON number, never scientific or hex notation.
        - `block_number` integer, required
        - `block_timestamp` string, date-time, required: `YYYY-MM-DDTHH:MM:SSZ`, UTC, second precision.
        - `tx_hash` string, required: 32-byte hash/topic, canonical form always `0x` + 64 lowercase hex digits.
        - `tx_index` integer, required
        - `log_index` integer, required
      - Erc721Transfer
        - `token` string, required: 20-byte address, canonical form always `0x` + 40 lowercase hex digits.
        - `standard` 'erc721', required
        - `from` string, required: 20-byte address, canonical form always `0x` + 40 lowercase hex digits.
        - `to` string, required: 20-byte address, canonical form always `0x` + 40 lowercase hex digits.
        - `token_id` string, required: Non-negative integer that may exceed 2^53, rendered as a plain decimal string — never a JSON number, never scientific or hex notation.
        - `block_number` integer, required
        - `block_timestamp` string, date-time, required: `YYYY-MM-DDTHH:MM:SSZ`, UTC, second precision.
        - `tx_hash` string, required: 32-byte hash/topic, canonical form always `0x` + 64 lowercase hex digits.
        - `tx_index` integer, required
        - `log_index` integer, required
  - `next_cursor` string: Opaque pagination token from the previous response's `next_cursor`; pass it back unchanged.
  - `meta` Meta, required: Metadata present on every success response.
    - `chain` string, required: Chain identifier; the value of the `{chain}` path parameter.
    - `chain_slug` string, required: Canonical uppercase chain slug; `chain` is always its lowercase form.
    - `chain_external_id` string, required: CAIP-2 formatted external chain identifier (`eip155:{chain_id}`).
    - `as_of_block` integer, required: The newest fully written block (the `blocks` table's maximum height); the only serving bound for block-scoped endpoints. For snapshot endpoints (balances, holders, nfts, dex prices, stocks) it is the service's current indexed head, not the block height of the snapshot: read the snapshot time from `meta.refreshed_at`, and treat the data as stale when `refreshed_at` is `null`.
    - `safe_block` integer, nullable, required: A marker only: the node's consensus `safe` block. Always present; `null` while no value is known (the node has no such tag, or the indexer has not read one yet). Only grows, never below `finalized_block`, and may be above or below `as_of_block`. It never truncates, rejects or bounds a response; see Finality in the API description.
    - `finalized_block` integer, nullable, required: A marker only: the node's consensus `finalized` block. Always present; `null` while no value is known (the node has no such tag, or the indexer has not read one yet). Only grows, and may be above or below `as_of_block`. It never truncates, rejects or bounds a response; see Finality in the API description.
    - `coverage` 'full' | 'partial', required: `"partial"` appears only from `GET /{chain}/addresses/{address}/transactions` and `GET /{chain}/addresses/{address}/transfers`, when `clamp=true` narrowed the served window, and from those two, `GET /{chain}/tokens/{token}/transfers` and `GET /{chain}/dex/swaps` when the block window starts before the lower bound of the dataset the endpoint reads -- the chain's first indexed block, or higher while that dataset is still being backfilled (see Coverage in the API description and each endpoint's window description). Every other endpoint reports `"full"`.
    - `refreshed_at` string, date-time, required: `YYYY-MM-DDTHH:MM:SSZ`, UTC, second precision.

## Other responses

- `400`: `error.code = "bad_request"`: invalid `{address}`; missing or invalid `standard`; invalid `token`; missing `from_block`/`to_block`; either is not a non-negative integer; `from_block > to_block`; invalid `direction`; invalid `limit`; or an invalid `cursor`.
- `401`: HTTP 401: a missing API key returns missing_api_key; an unknown, disabled, or revoked key returns the same invalid_api_key error envelope. error.code and error.data.reason contain the reason. Rejected requests are not billed.
- `402`: Payment required: the paid balance or the free grant is exhausted. The response body is `{"error":{"code":"insufficient_balance"}}`. Rejected requests are not billed.
- `404`: `error.code = "not_found"`: the target object was not found, or `{chain}` is not a registered or public chain (returns HTTP 404 with `error.code = "not_found"`, not billed).
- `409`: One of two codes: `error.code = "not_indexed_yet"` when `to_block` (or, with `clamp=true`, `from_block` itself) is above `as_of_block`; or `error.code = "window_too_large"` when `[from_block, to_block]` spans more than 100,000 blocks and `clamp` was not `true`.
- `422`: `error.code = "no_coverage"`: returned when `standard=erc1155`, as ERC-1155 transfers cannot be listed by address; when the chain does not have the `transfers` capability; or when the window is entirely before the lower bound of the dataset this endpoint reads (the chain's first indexed block, or higher while that dataset is still being backfilled; the numbers in the examples are illustrative; read `GET /chains` `coverage.from_block` at runtime).
- `429`: Rate limited. `{"error":{"code":"rate_limited"}}` when the key CU rate limit is exceeded (the response includes `Retry-After`) or the account call rate limit is exceeded (no `Retry-After`). `{"error":{"code":"cost_exceeds_burst"}}` when a single request exceeds the key burst capacity; split the request, retrying as sent never succeeds. Rejected requests are not billed.
- `503`: `error.code = "unavailable"`: the service is temporarily unavailable, timed out, busy on this chain (no query slot freed up in time, see `limits.max_concurrent_queries` in `GET /chains`), or shutting down (see "Errors" above). Always carries an HTTP `Retry-After` header (seconds); wait at least that long before retrying.

---

[API](https://skmtc.dev/blockvectra/apis/blockvectra-data-api.md) · [All operations](https://skmtc.dev/blockvectra/apis/blockvectra-data-api/llms.txt) · [OpenAPI document](https://skmtc.dev/blockvectra/apis/blockvectra-data-api/revisions/c5b949e955b5?raw)
