Magic Eden API & Scraper
The Magic Eden API returns Solana NFT marketplace data as clean JSON.
🤖 Using an AI assistant? Copy this link into ChatGPT / Claude / Cursor — it reads every endpoint and parameter instantly and tells you if this API fits your use case.
The primary collections endpoint returns collections with symbol, name, description, image, categories and social links, and you can pull a collection, its stats, listings, tokens, a token and its activity, marketplace activity, attributes and a wallet. It is built for NFT analytics, portfolio tools and web3 apps that need Magic Eden data without a scraper. One ReefAPI key, one shared credit pool, the standard envelope.
Symbols, mint addresses and the unit every price is in
Two identifiers run through this engine and they are not interchangeable: a collection is addressed by its symbol, an individual NFT by its Solana mint address. The second thing worth settling before you write any arithmetic is the price unit. Everything below was measured on 2026-08-27 against okay_bears.
| Thing | Format or rule | Measured |
|---|---|---|
| Collection symbol | The last path segment of a marketplace URL, lower snake_case | okay_bears, degods, solana_monkey_business, degenerate_ape_kindergarten |
| popular | NOT_FOUND on every call - the leaderboard feed has no rows behind it | Upstream, not ours: it returns nothing for any time window or page size. Use collections for the ranked list, or search to find one by name |
| Unknown symbol | NOT_FOUND, retryable false, on stats / listings / activity / attributes | collection '<what you sent>' is not a Magic Eden collection symbol - find the right one with the search action |
| Unknown symbol, the two exceptions | collection answers UPSTREAM_HTTP; tokens answers RATE_LIMITED | Both come from the marketplace itself, not from the symbol: the 400 is its own, and the rate limit lands on real symbols too |
| mint_address | Base58 Solana mint, 43 to 44 characters | 9RpvZMKf1qcTsnCPRjGJ8tddzxNusGiYZc9tkS8UhZTA |
| All price fields | SOL as a decimal. Never lamports | floor_price_sol 1.1655. The same figure in lamports would be 1165500000 |
| floor_price_sol | Equals the cheapest active listing at that instant | Collection floor 1.1655 and the first row of listings 1.1655, from two separate calls |
| price_sol on a token | null when list_status is 'unlisted' | A token owned but not for sale returned list_status unlisted, price_sol null |
| seller_fee_basis_points | Creator royalty in basis points, so divide by 100 for a percentage | 500 = 5% on okay_bears, 420 = 4.2% on another collection, 0 on a third |
| block_time | Unix seconds, not milliseconds | 1787784215. Multiply by 1000 before handing it to a JS Date |
| Rarity | Two independent third-party ranks that disagree by design | Okay Bear #9541: moonrank 9502, howrare 9512 |
| attributes[].count | An absolute NFT count, not a share or a fraction | Hat = Rubik's Cube, count 4, floor_sol 22.0 against a collection floor of 1.1655 |
The marketplace rate-limits around 120 requests a minute per source address, and a burst returns RATE_LIMITED with retryable true rather than bad data. Space out paging loops, and retry rather than treating a rate-limit as an empty collection.
Real request and response JSON
Captured from the indexed primary action, collections, on .
{
"method": "POST",
"url": "https://api.reefapi.com/magiceden/v1/collections",
"headers": {
"x-api-key": "$REEF_KEY",
"content-type": "application/json"
},
"body": {
"limit": 20
}
}{
"ok": true,
"meta": {
"api": "magiceden",
"endpoint": "collections",
"mode": "live",
"latency_ms": 360.7,
"record_count": 20,
"bytes": 7962,
"cache_hit": false,
"stop_reason": "limit_reached",
"page": 1,
"has_more": true,
"charged_credits": 1,
"version": "1.0.0"
},
"data": {
"collections": [
{
"symbol": "zpups",
"name": "zPUPS",
"description": "A collection of 1111 zPUPS paired with $ZEC",
"image_url": "https://na-assets.pinit.io/9cATdaUfhTYSQnyRXhC1R6PP1PGzR1AvKjH9mSkPn3HA/a993ae90-bfbf-4f04-992b-cc73236ae7d0/04c6a37f-3d5a-4aca-b682-7b6597ea0499-nft_308.webp",
"categories": [
"pfps"
],
"twitter": null,
"discord": null,
"website": null,
"is_badged": false,
"has_compressed_nfts": false,
"magiceden_url": "https://magiceden.io/marketplace/zpups"
},
{
"symbol": "monstermine_egg",
"name": "MonsterMine Egg",
"description": "A MonsterMine egg waiting to hatch. Its rarity is revealed when opened from a chest.",
"image_url": "https://media.monstermine.io/nfts/egg.jpg",
"categories": [
"pfps"
],
"twitter": null,
"discord": null,
"website": null,
"is_badged": false,
"has_compressed_nfts": false,
"magiceden_url": "https://magiceden.io/marketplace/monstermine_egg"
},
{
"symbol": "pumpers__",
"name": "PUMPERS",
"description": "pumper paired with $pump",
"image_url": "https://we-assets.pinit.io/CVwvx86yHTsSpGMyfPgdLYX99YAmsEm5Md4perQiZTzs/77e7e15f-f0f5-4980-8762-841bc6de020b/06515a0d-4747-4fcc-9f37-a52958671f23-605.jpeg",
"categories": [
"pfps"
],
"twitter": null,
"discord": null,
"website": null,
"is_badged": false,
"has_compressed_nfts": false,
"magiceden_url": "https://magiceden.io/marketplace/pumpers__"
}
]
}
}What the Magic Eden API does
| Action | Description | Concrete use case | Key params |
|---|---|---|---|
| collections | Browse Magic Eden collections (paginated). Each: symbol, name, description, image, categories and social links. Use the returned symbol with the other actions. Offset pagination via the `page` param. | Pricing teams call collections to get browse Magic Eden collections (paginated). | page, limit |
| collection | Full collection detail by symbol: metadata (name, description, image, categories, social links) merged with live market stats — floor price (SOL), listed count, 24h average sale price and all-time volume. | Marketplace operators call collection to get full collection detail by symbol. | symbol |
| stats | Live market stats for a collection: floor price (SOL), number of NFTs currently listed, 24-hour average sale price and all-time trading volume. | Catalog enrichment teams call stats to get live market stats for a collection. | symbol |
| listings | Active NFT listings in a collection (NFTs currently for sale), cheapest first. Each: token mint, name, price (SOL), seller, rarity rank (Moonrank + HowRare), image and traits. Optional min/max price filter (SOL). Offset pagination via `page`. | Retail analysts call listings to get active NFT listings in a collection (NFTs currently for sale), cheapest first. | symbol, page, limit, min_price, max_price |
| tokens | All tokens (NFTs) in a collection (listed or not), paginated. Each: mint address, name, owner, image, list status, price if listed, and traits. Offset pagination via `page`. | Pricing teams call tokens to get all tokens (NFTs) in a collection (listed or not), paginated. | symbol, page, limit |
| token | Single NFT / token detail by its Solana mint address: name, collection, current owner, image, all traits, list status and price if listed. Get a mint address from a listings[], tokens[] or activity[] row. | Marketplace operators call token to get single NFT / token detail by its Solana mint address. | mint_address |
| token_activity | On-chain activity history for a single NFT by mint address: every sale, listing, delisting and bid with type, price (SOL), buyer / seller and block time. Offset pagination via `page`. | Catalog enrichment teams call token_activity to get on-chain activity history for a single NFT by mint address. | mint_address, page, limit |
| activity | Recent on-chain activity for a collection: sales, listings, delistings and bids. Each event: type, price (SOL), buyer / seller, token mint and block time. Filter by event type (default: all). Offset pagination via `page`. | Retail analysts call activity to get recent on-chain activity for a collection. | symbol, page, limit, event_type |
| attributes | Trait floor prices for a collection — for every trait value (e.g. Background = Yellow), the floor price (SOL) and how many NFTs carry it. Useful for trait-based valuation. | Pricing teams call attributes to get trait floor prices for a collection. | symbol |
| wallet | NFTs held by a Solana wallet address: each token's mint, name, collection, image, list status and price if listed. Offset pagination via `page`. | Marketplace operators call wallet to get nFTs held by a Solana wallet address. | address, page, limit |
| popular | Popular / trending Magic Eden collections over a time window — the marketplace leaderboard. Each: symbol, name, floor price (SOL) and all-time volume. Choose a window (1h / 1d / 7d / 30d). | Catalog enrichment teams call popular to get popular / trending Magic Eden collections over a time window. | time_range, limit |
| launchpad | Magic Eden Launchpad collections — upcoming and live primary mints. Each: symbol, name, mint price (SOL), supply size, launch datetime, chain and contract. Offset pagination via `page`. | Retail analysts call launchpad to get magic Eden Launchpad collections. | page, limit |
| search | Search Magic Eden collections by free-text name. Resolves a name to its collection symbol(s): first tries an exact symbol match, then scans popular collections and collection pages for a name/symbol substring match. Returns matching collections (symbol, name, image, categories) — use the returned symbol with the other actions. | Pricing teams call search to search Magic Eden collections by free-text name. | query, limit |
Call collections from your stack
curl -X POST https://api.reefapi.com/magiceden/v1/collections \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"limit":20}'import requests
r = requests.post(
"https://api.reefapi.com/magiceden/v1/collections",
headers={"x-api-key": REEF_KEY},
json={
"limit": 20
},
)
print(r.json()["data"])const res = await fetch("https://api.reefapi.com/magiceden/v1/collections", {
method: "POST",
headers: {
"x-api-key": process.env.REEF_KEY,
"content-type": "application/json",
},
body: JSON.stringify({
"limit": 20
}),
});
const { ok, data, meta, error } = await res.json();Ask your MCP-connected assistant: call reefapi.magiceden.collections with {"limit":20}.Who uses this API and why
- NFT-analytics tools call stats and listings to track a collection's floor price and volume.
- Portfolio apps use wallet and token to value a holder's NFTs in real time.
- Web3 products use activity and attributes to power trait rarity and market feeds.
Questions developers ask before integrating
Are prices in SOL or in lamports?
SOL, as decimals, on every price field: floor_price_sol, price_sol, avg_price_24hr_sol, volume_24hr_sol, mint_price_sol and floor_sol on trait rows. A measured okay_bears floor of 1.1655 would be 1165500000 in lamports, so the two are never ambiguous at a glance. No conversion is needed and none should be applied.
When do I pass a symbol and when a mint address?
Collection-scoped actions (collection, stats, listings, tokens, activity, attributes) take `symbol`. NFT-scoped actions (token, token_activity) take `mint_address`. `wallet` takes a Solana wallet address. Mints come out of listings[].token_mint, tokens[].mint_address and activity[].token_mint, so the normal route is symbol first, mint second. `search` only resolves an exact symbol, so a free-text word such as 'bears' returned a 400 while 'okay_bears' and 'degods' each resolved to a single collection.
Why do two activity rows share the same transaction signature?
Because one on-chain transaction can produce more than one marketplace event. A single signature on okay_bears came back as both a 'bid' row (with a buyer, no seller) and a 'poolUpdate' row (with a seller, no buyer) at the same price and the same block_time. Note that poolUpdate is not one of the documented event_type filter values, so it only appears when you leave event_type off. If you are summing volume, deduplicate on signature plus type or you will double-count.
Why is token_mint null on some activity rows?
Because those events are collection-level, not token-level. Bids and pool updates placed against the whole collection rather than one NFT have no mint to name, so the field is null while collection_symbol and price_sol are populated. Filtering with event_type 'buyNow' returned 20 rows that all carried a token_mint, which is the clean path if you want per-NFT sale history.
Moonrank and HowRare disagree on the same NFT. Which is right?
Neither is authoritative; they are two independent rarity services with different scoring methods, and both are passed through unchanged. Okay Bear #9541 ranked 9502 by Moonrank and 9512 by HowRare. Pick one and stay with it for internal comparisons rather than averaging them. If you want a valuation signal grounded in actual money instead, use `attributes`, which returned 162 trait-value rows for okay_bears, each with the number of NFTs carrying that trait and the current floor for it.
total_supply says 9,858 but the collection describes itself as 10,000. Which is wrong?
Neither. total_supply is the live on-chain count and the description is the mint-day marketing number; the difference is burns and lost tokens. On the same call, unique_holders came back as 4,230 and listed_count as 689, so roughly 7% of the surviving supply was on sale at that moment. Use listed_count over total_supply for a sell-pressure ratio, and never use the description's number for anything arithmetic.
Which stats does the engine actually return?
The `stats` action returned symbol, floor_price_sol, listed_count, avg_price_24hr_sol, volume_24hr_sol, volume_7d_sol, volume_30d_sol, txns_24hr, highest_offer_sol, unique_holders and total_supply. `collection` returns a subset of those merged with the metadata (name, description, image_url, categories, twitter, discord, website). Note that volume comes in fixed 24-hour, 7-day and 30-day windows; there is no all-time volume figure in the live payload, so do not build against one.
Does launchpad only show upcoming mints?
No. The rows are drawn from the marketplace's launchpad list and include mints whose launch_datetime is already in the past, so the first page returned launches dated February 2026 when queried in August. Each row carries symbol, name, mint_price_sol, size (the planned supply, e.g. 495 or 4444), launch_datetime as an ISO string, chain_id ('solana') and the contract_address. Filter on launch_datetime yourself if you only want what has not opened yet.
What is the Magic Eden API?
Magic Eden API is a ReefAPI endpoint group for magic eden It returns live JSON through POST requests under /magiceden/v1.
Is the Magic Eden API free to try?
Yes. ReefAPI starts with 1,000 free credits, no card required. Magic Eden calls use the same shared credit balance as every other ReefAPI engine.
Do I need a Magic Eden login or account?
No login to Magic Eden is needed for the API response. You call ReefAPI with your x-api-key header, and the playground can run live examples before you create a production key.
How fresh is the Magic Eden data?
The page example is captured from a live collections call, and production requests fetch live data through ReefAPI rather than a static sample.
How many credits does the Magic Eden API use?
Magic Eden actions currently cost 1-2 credits per successful call. Failed or blocked calls are free. All APIs draw from one credit pool.
Can I call Magic Eden from an AI assistant or MCP client?
Yes. Connect ReefAPI once through MCP and your assistant can call magiceden actions with the same key, credit pool and JSON envelope used by normal REST requests.