Summary
A Base NFT API is the set of RPC methods and indexed data services you use to read NFT ownership, metadata, and transfer history on the Base network. Standard JSON-RPC calls like eth_call, eth_getLogs, and eth_getBalance cover on-chain reads, while indexer-style APIs add pre-aggregated ownership and collection data. This article explains which approach fits which workload and how to connect reliably.
You will see how to query ERC-721 and ERC-1155 contracts directly over Base RPC, when an indexer is the better tool, and how to configure a production endpoint. OnFinality provides Base RPC API access and dedicated node infrastructure if you need consistent throughput for NFT-heavy read traffic.
If you searched for a Base NFT API, you probably need to read NFT data on Base: who owns a token, what a collection contains, or how a token moved between wallets. There is no single "NFT API" on Base. Instead you combine standard JSON-RPC calls to the Base network with optional indexer services that pre-aggregate ownership and metadata. This page shows what each layer does, how to connect, and how to keep NFT read traffic stable in production.
Which approach fits your NFT workload
Before writing code, decide whether you need raw on-chain reads or pre-indexed data. The right choice depends on how much aggregation you want to do yourself and how fresh the data must be.
| Workload | Best fit | Why |
|---|---|---|
| Read one token's owner or balance | Base RPC (eth_call) | Direct contract read, always current at the queried block |
| List all tokens owned by a wallet | Indexer API or your own indexer | RPC alone cannot enumerate holdings without scanning logs |
| Fetch collection metadata and images | Indexer API or tokenURI + off-chain fetch | Metadata often lives on IPFS or HTTP, not fully on-chain |
| Track transfers in real time | Base RPC (eth_getLogs or WebSocket) | Logs give you the raw Transfer events as they happen |
| Backfill full transfer history | Archive-capable RPC or indexer | Historical log queries need archive state and careful paging |
| Verify a mint or sale on-chain | Base RPC (eth_getTransactionReceipt) | Receipts confirm what actually executed |
A practical pattern is to use Base RPC for authoritative, point-in-time reads and an indexer for list-style queries. Many teams run both: RPC for correctness and indexer for speed on aggregated views.
Base chain settings at a glance
Use these values when adding Base to a wallet, backend config, or test harness. They match the network configuration OnFinality publishes for Base.
| Setting | Base mainnet | Base Sepolia testnet |
|---|---|---|
| Chain ID | 8453 | 84532 |
| Native currency | ETH (18 decimals) | ETH (18 decimals) |
| Block explorer | https://basescan.org | https://sepolia.basescan.org |
| Public RPC (OnFinality) | https://base.api.onfinality.io/public | https://base-sepolia.api.onfinality.io/public |
| Transport | HTTP | HTTP |
For a managed endpoint and network details, see the Base RPC network page and the Base Sepolia RPC network page.
Reading NFT data with JSON-RPC
Most ERC-721 and ERC-1155 reads go through eth_call with an encoded function selector. The three calls you will use most are ownerOf, balanceOf, and tokenURI for ERC-721, and balanceOf plus uri for ERC-1155.
Here is a minimal curl example that calls ownerOf(uint256) on an ERC-721 contract. The selector for ownerOf is 0x6352211e, followed by the token ID padded to 32 bytes.
curl -s https://base.api.onfinality.io/public \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_call",
"params": [
{
"to": "0xYOUR_NFT_CONTRACT",
"data": "0x6352211e0000000000000000000000000000000000000000000000000000000000000001"
},
"latest"
]
}'
The response is ABI-encoded. Decode it as an address. If the token does not exist, the call reverts and you get an error object instead of a value, so handle both cases.
In JavaScript, viem and ethers handle encoding for you. This example reads the owner and token URI of an ERC-721 token:
import { createPublicClient, http, parseAbi } from "viem";
import { base } from "viem/chains";
const client = createPublicClient({
chain: base,
transport: http("https://base.api.onfinality.io/public"),
});
const abi = parseAbi([
"function ownerOf(uint256) view returns (address)",
"function tokenURI(uint256) view returns (string)",
]);
const owner = await client.readContract({
address: "0xYOUR_NFT_CONTRACT",
abi,
functionName: "ownerOf",
args: [1n],
});
const uri = await client.readContract({
address: "0xYOUR_NFT_CONTRACT",
abi,
functionName: "tokenURI",
args: [1n],
});
console.log(owner, uri);
tokenURI usually returns an ipfs:// or https:// link. Resolving it is an off-chain fetch, not an RPC call, so plan for caching and timeouts there.
Enumerating transfers and ownership with logs
To find transfers, query eth_getLogs filtered by the ERC-721 or ERC-1155 Transfer event topic and the contract address. This is how most indexers build ownership tables.
const logs = await client.getLogs({
address: "0xYOUR_NFT_CONTRACT",
fromBlock: 0n,
toBlock: "latest",
});
Two constraints matter. First, providers cap the block range per eth_getLogs request, so you must page through history in chunks. Second, deep historical queries need archive state; a non-archive node may reject or fail them. If you are backfilling a large collection, chunk by block range and persist your progress so a failed request does not force a full restart.
For live transfer feeds, a WebSocket subscription to logs avoids polling. Not every endpoint exposes WebSocket transport, so confirm transport support before designing around it. If you need persistent subscriptions, dedicated node infrastructure is often a better fit than a shared public endpoint.
When a raw RPC endpoint is not enough
RPC gives you correctness but not convenience. It cannot answer "list every NFT this wallet owns" without you scanning logs and reconstructing state. That is the job of an indexer or an NFT data API.
Common reasons teams add an indexer layer on top of Base RPC:
- Wallet portfolio views that must return quickly for many collections.
- Marketplace or gallery pages that need collection-level metadata and counts.
- Analytics that aggregate transfers across thousands of contracts.
- Metadata caching so you are not resolving
tokenURIon every page load.
You can run your own indexer against a Base RPC endpoint, or use a hosted NFT data service. Either way, the RPC endpoint underneath still needs to handle your indexing load, which is usually far heavier than a single user request.
Production readiness checklist for NFT read traffic
NFT workloads are read-heavy and bursty. A drop or a new collection can multiply request volume in minutes. Before you ship, check these items.
| Check | What to verify |
|---|---|
| Endpoint capacity | Your provider can absorb burst reads from wallets, galleries, and indexers |
| Archive access | Historical log and state queries are supported if you backfill |
| Transport | HTTP for reads, WebSocket if you subscribe to live logs |
| Failover | A second endpoint or provider is configured for automatic retry |
| Caching | Metadata and tokenURI responses are cached with sensible TTLs |
| Batching | Multiple reads are batched with JSON-RPC batch requests where possible |
| Monitoring | You track error rates, latency, and rate-limit responses |
If you expect steady or high NFT read volume, compare a shared public endpoint against a managed plan and dedicated nodes. OnFinality offers Base RPC API access and dedicated nodes; see RPC pricing and the full list of supported RPC networks to plan capacity.
Common failure modes and how to debug them
Most Base NFT API problems fall into a few repeatable categories.
| Symptom | Likely cause | Fix |
|---|---|---|
eth_call reverts | Token does not exist or wrong contract | Confirm token ID and contract address |
| Empty log results | Wrong topic or block range | Check the Transfer topic hash and widen the range |
| Request rejected on old blocks | Non-archive node | Use an archive-capable endpoint |
| Rate-limit errors under load | Shared endpoint limits | Batch requests, cache, or move to a managed plan |
| Metadata fails to load | IPFS gateway or HTTP timeout | Add a fallback gateway and cache results |
| Inconsistent ownership | Reading at different blocks | Pin a block number for consistent snapshots |
A quick diagnostic is to replay the failing call against a known-good block and compare. If it succeeds there, the issue is usually state depth or range, not your ABI encoding.
Testing on Base Sepolia
Build and test against Base Sepolia before mainnet. The chain ID is 84532, and the OnFinality public endpoint is https://base-sepolia.api.onfinality.io/public. Deploy a test ERC-721, mint a few tokens, and run your ownerOf, balanceOf, and eth_getLogs paths against it. Test your paging logic here, where mistakes are cheap, rather than on mainnet where a bad backfill can be expensive.
Key Takeaways
- A Base NFT API is a combination of Base JSON-RPC calls and, optionally, an indexer for aggregated data.
- Use
eth_callforownerOf,balanceOf, andtokenURI; useeth_getLogsfor transfers. - RPC cannot enumerate a wallet's holdings on its own; that needs an indexer or your own indexing job.
- Historical log queries need archive state and block-range paging.
- Confirm transport support before relying on WebSocket subscriptions.
- Plan for bursty read traffic with caching, batching, and failover.
- Test on Base Sepolia (chain ID 84532) before mainnet.
Frequently Asked Questions
Is there a single Base NFT API?
No. Base exposes standard Ethereum JSON-RPC, so NFT reads use the same methods as any EVM chain. Aggregated NFT data comes from indexers or hosted data services layered on top.
Can I list all NFTs owned by a wallet using only RPC?
Not directly. You would have to scan Transfer logs and reconstruct ownership yourself. An indexer is the practical choice for portfolio-style queries.
Do I need an archive node for NFT history?
If you query old blocks or backfill transfer history, yes. Archive-capable endpoints serve historical state that a pruned node cannot.
Does Base RPC support WebSocket subscriptions?
Transport support varies by endpoint. Check your provider's documentation before designing around live log subscriptions.
How do I avoid rate limits during a backfill?
Batch requests, page through logs in chunks, cache metadata, and consider a managed or dedicated endpoint for sustained indexing load.
Where can I find Base endpoint and chain details?
See the Base RPC network page and Base Sepolia RPC network page for chain settings and endpoints.