Moralis NFT Endpoints: The Complete Developer Guide
Learn how to use Moralis NFT API endpoints to fetch NFT data, ownership, metadata, and transfers with real code examples for crypto developers.
Learn how to use Moralis NFT API endpoints to fetch NFT data, ownership, metadata, and transfers with real code examples for crypto developers.
If you've ever tried to build an NFT tracker, portfolio tool, or trading bot that needs on-chain NFT data, you've probably hit the same wall: querying NFT ownership and metadata directly from an RPC node is slow, expensive, and painful. Moralis solves this by indexing the blockchain and exposing clean REST and SDK endpoints so you can pull NFT data in milliseconds instead of hours. This guide walks through the most important Moralis NFT endpoints with real code you can copy and run today.
Moralis NFT API is a suite of endpoints built on top of their multi-chain indexer. Instead of subscribing to raw node events and parsing logs yourself, you hit a single HTTPS endpoint and get structured JSON back. The API covers Ethereum, Polygon, BNB Chain, Avalanche, Solana, and a dozen other networks. For a trader or developer building tools around NFT markets — whether that's tracking floor prices, watching whale wallets, or building a collection analytics dashboard — this saves weeks of infrastructure work.
Every request to Moralis requires an API key. Get yours free at moralis.io — the free tier allows 40,000 compute units per day, which is plenty for development and small projects. You can call endpoints directly via REST or use their Python and JavaScript SDKs. The SDK is cleaner for complex workflows; raw REST is better if you're integrating into an existing system.
# Install SDK
# pip install moralis
from moralis import evm_api
import os
# Set your API key — store this in an environment variable, never hardcode
API_KEY = os.environ.get("MORALIS_API_KEY")
# Quick connectivity check — get native balance to confirm key works
def check_auth():
params = {
"address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", # vitalik.eth
"chain": "eth"
}
try:
result = evm_api.balance.get_native_balance(api_key=API_KEY, params=params)
print(f"Auth OK — balance: {result['balance']} wei")
return True
except Exception as e:
print(f"Auth failed: {e}")
return False
check_auth()
// npm install moralis
import Moralis from 'moralis';
const API_KEY = process.env.MORALIS_API_KEY;
async function initMoralis() {
await Moralis.start({ apiKey: API_KEY });
console.log('Moralis initialized');
}
initMoralis();
Never commit your Moralis API key to Git. Use environment variables or a secrets manager. A leaked key means someone else burns through your compute units — or worse, your paid quota.
The two most commonly used endpoints are wallet NFT lookup and token metadata fetch. The wallet endpoint tells you every NFT a given address holds — useful if you're building a portfolio tracker or monitoring a whale wallet for positions. The metadata endpoint gives you the token's image URI, traits, description, and any custom attributes defined by the collection.
from moralis import evm_api
import os
import json
API_KEY = os.environ.get("MORALIS_API_KEY")
def get_wallet_nfts(wallet_address: str, chain: str = "eth", limit: int = 10):
"""
Fetch all NFTs owned by a wallet.
Returns list of NFT objects with metadata.
"""
params = {
"address": wallet_address,
"chain": chain,
"limit": limit,
"media_items": False # Set True if you need image CDN URLs
}
try:
result = evm_api.nft.get_wallet_nfts(api_key=API_KEY, params=params)
nfts = result.get("result", [])
print(f"Found {len(nfts)} NFTs for {wallet_address}")
return nfts
except Exception as e:
print(f"Error fetching wallet NFTs: {e}")
return []
def get_nft_metadata(contract_address: str, token_id: str, chain: str = "eth"):
"""
Fetch full metadata for a specific NFT token.
"""
params = {
"address": contract_address,
"token_id": token_id,
"chain": chain,
"normalizeMetadata": True # Normalize IPFS URIs automatically
}
try:
result = evm_api.nft.get_nft_metadata(api_key=API_KEY, params=params)
# Parse the nested metadata JSON string
if result.get("metadata"):
metadata = json.loads(result["metadata"])
print(f"Name: {metadata.get('name')}")
print(f"Traits: {metadata.get('attributes', [])}")
return result
except Exception as e:
print(f"Error fetching NFT metadata: {e}")
return None
# Example: Check what NFTs Binance's hot wallet holds
binance_hot_wallet = "0x28C6c06298d514Db089934071355E5743bf21d60"
nfts = get_wallet_nfts(binance_hot_wallet, chain="eth", limit=5)
for nft in nfts:
print(f"{nft['name']} | Contract: {nft['token_address']} | Token ID: {nft['token_id']}")
When you parse the response, each NFT object contains `token_address`, `token_id`, `owner_of`, `token_uri`, `metadata`, `name`, and `symbol`. The `metadata` field is a JSON string — you need to parse it separately to access traits and image URLs. The `normalizeMetadata` flag is worth enabling because it resolves IPFS URIs to gateway URLs automatically, saving you a lookup.
Transfer history is where things get interesting for traders. You can pull every transfer event for a contract or a wallet — mints, sales, and peer-to-peer transfers. This is the raw ingredient for building wash-trade detection, whale tracking, or signals that feed into platforms like VoiceOfChain, which aggregates on-chain activity into real-time trading signals. Knowing when a whale wallet on Ethereum suddenly mints 50 NFTs from a new collection — or dumps an entire position — is actionable intelligence.
from moralis import evm_api
import os
from datetime import datetime
API_KEY = os.environ.get("MORALIS_API_KEY")
def get_nft_transfers(contract_address: str, chain: str = "eth", limit: int = 20):
"""
Get recent transfer events for an NFT collection.
Useful for monitoring mint activity or large sales.
"""
params = {
"address": contract_address,
"chain": chain,
"limit": limit,
"order": "DESC" # Most recent first
}
try:
result = evm_api.nft.get_nft_contract_transfers(
api_key=API_KEY,
params=params
)
transfers = result.get("result", [])
for tx in transfers:
ts = tx.get("block_timestamp", "")
from_addr = tx.get("from_address", "")[:10]
to_addr = tx.get("to_address", "")[:10]
token_id = tx.get("token_id")
value = tx.get("value", "0")
# Mint detection: from address is zero address
is_mint = tx["from_address"] == "0x0000000000000000000000000000000000000000"
label = "MINT" if is_mint else "TRANSFER"
print(f"[{label}] Token #{token_id} | {from_addr}... -> {to_addr}... | {ts}")
return transfers
except Exception as e:
print(f"Error fetching transfers: {e}")
return []
# Bored Ape Yacht Club contract
bayc_contract = "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D"
transfers = get_nft_transfers(bayc_contract, chain="eth", limit=10)
Mint detection trick: when `from_address` is the zero address (0x000...000), it's a fresh mint — not a secondary sale. Filter for these to catch early collection launches before they hit secondary markets like OpenSea.
Moralis also exposes price and marketplace data. The NFT floor price endpoint pulls the lowest listed price across major marketplaces. If you're running a trading bot that monitors collections, this endpoint combined with transfer data gives you a two-dimensional view: what's the current floor, and is volume accelerating. Traders on Binance NFT, OKX NFT marketplace, and Bybit often use on-chain APIs like this to time entries before price moves show up in order books.
import Moralis from 'moralis';
const API_KEY = process.env.MORALIS_API_KEY;
async function getNFTFloorPrice(contractAddress, chain = '0x1') {
await Moralis.start({ apiKey: API_KEY });
try {
// Get NFT lowest price endpoint
const response = await Moralis.EvmApi.nft.getNFTLowestPrice({
address: contractAddress,
chain: chain,
days: 7, // Look back 7 days
marketplace: 'opensea'
});
const data = response.toJSON();
const priceEth = parseInt(data.price) / 1e18;
const tokenId = data.token_id;
const txHash = data.transaction_hash;
console.log(`Floor price: ${priceEth.toFixed(4)} ETH`);
console.log(`Last sale token: #${tokenId}`);
console.log(`Tx: ${txHash}`);
return { priceEth, tokenId, txHash };
} catch (error) {
if (error.details?.status === 429) {
console.error('Rate limited — back off and retry');
} else {
console.error('Error:', error.message);
}
return null;
}
}
// Azuki collection
getNFTFloorPrice('0xED5AF388653567Af2F388E6224dC7C4b3241C544');
The rate limiting behavior deserves attention — a 429 response from Moralis means you've hit your compute unit ceiling. Implement exponential backoff in production code. Each endpoint costs a different number of compute units: basic wallet lookups are cheap, but searching by metadata or pulling large transfer histories can run expensive fast. Check the Moralis pricing docs for the compute unit cost table before building anything at scale.
| Endpoint | Method | Use Case | Approx. CU Cost |
|---|---|---|---|
| getWalletNFTs | GET /nft/{address} | Portfolio tracking, whale watching | 5 CU per call |
| getNFTMetadata | GET /nft/{address}/{id} | Trait lookup, rarity checks | 5 CU per call |
| getNFTContractTransfers | GET /nft/{address}/transfers | Volume monitoring, mint detection | 10 CU per call |
| getNFTLowestPrice | GET /nft/{address}/lowestprice | Floor price feeds, bots | 10 CU per call |
| getNFTOwners | GET /nft/{address}/owners | Holder distribution analysis | 15 CU per call |
| searchNFTs | GET /nft/search | Metadata trait search | 20 CU per call |
The real value of Moralis NFT endpoints isn't any single API call — it's how they combine. A practical whale tracker, for instance, pulls wallet NFT holdings once per block, diffs the result against the previous state, and fires an alert when a known large holder drops or acquires a significant position. Pair that with price data from Coinbase or OKX APIs and you have a system that can flag when a top-10 holder of a collection sells out at the same time floor price starts dropping. That's the kind of intelligence that gives you an edge on platforms like Binance NFT or Bybit's marketplace before it shows up in the charts.
VoiceOfChain integrates on-chain signals like NFT whale movements alongside DeFi and token trading signals, making it easier to see the full picture without building every data pipeline yourself. For developers who want to go deeper, Moralis is the right foundation — it eliminates the indexing problem so you can focus on the logic that actually generates alpha. Start with the wallet NFT endpoint and transfer history, get comfortable with pagination and error handling, then layer in Streams when you need real-time push rather than polling. That progression — from REST polling to event-driven streaming — mirrors how most serious NFT tool builders evolve their architecture.