cryptopunks
CryptoPunks Skill
A unified toolkit for exploring, visualizing, and analyzing CryptoPunks. Combines two APIs:
- punks.art — traits catalog, pixel art rendering, filtering, batch grid, custom punk generation
- cryptopunks.app — on-chain market data, ownership, bids, sales history
API 1: punks.art (Traits, Rendering & Data)
Base URL: https://punks.art
GET /api/traits — List all traits
Search, filter, and browse the complete trait catalog (133 traits across 13 categories).
| Parameter | Description |
|---|---|
category |
Filter by category: Type, Ear, Eye Makeup, Eyewear, Facial Hair, Hairstyle, Headwear, Lip Makeup, Mouth, Mouth Accessories, Neck, Nose, Skin Markings |
gender |
Filter by gender: Male, Female, Unisex |
search |
Search traits by name (e.g. search=mohawk) |
extended |
Include extended/unisex variants (true/false) |
groupByCategory |
Group results by category (true/false) |
limit |
Max results (default: all) |
offset |
Pagination offset |
Response: { success: true, data: [{ id, slug, name, category, gender, punkCount }], total, offset, limit, categories }
Each trait includes punkCount — the number of punks in the 10k collection that have this trait. Use this for rarity analysis without fetching individual traits.
When groupByCategory=true: { success: true, data: { "Hairstyle": [...], "Eyewear": [...] }, total, categories }
Examples:
# All hairstyles with rarity counts
curl -sL "https://punks.art/api/traits?category=Hairstyle"
# Find rarest traits (sort by punkCount client-side)
curl -sL "https://punks.art/api/traits" | jq '.data | sort_by(.punkCount) | .[0:10]'
# Search for a trait
curl -sL "https://punks.art/api/traits?search=shades"
GET /api/traits/{slug} — Get trait data, render & stats
Get a single trait or combine multiple traits (dash-separated slugs). Returns pixel art in any format, plus the list of all punks that have this trait.
| Parameter | Description |
|---|---|
format |
json (default), pixels, png, svg, ascii, ansi |
background |
Color: hex (FF0000), CSS name (crimson), preset (punk, v1, forsale, bids), gradient (red-blue-gold), or image URL |
size |
Grid size in pixels (default: 24, or 32 for naked) |
naked |
Full-body 32x32 rendering (true/yes/1) |
dingdong |
Anatomical details when naked (true/yes/1) |
includePunkIds |
Include full punkIds array (true default, false for lighter response) |
Trait combination: separate slugs with dashes. Example: alien-regularshades-wildhair.
Type slugs (base body): male1, male2, male3, male4, female1, female2, female3, female4, zombie, ape, alien
Examples:
# How many punks have a Hoodie? (1 call instead of fetching all 10k)
curl -sL "https://punks.art/api/traits/hoodie" | jq '{punkCount, punkIds}'
# Combine traits as PNG
curl -sL "https://punks.art/api/traits/alien-regularshades-wildhair?format=png&background=v1" -o punk.png
# Custom punk in terminal
curl -sL "https://punks.art/api/traits/female2-tiara-greeneyeshadow?format=ansi&background=punk"
JSON response includes:
{
"success": true,
"data": {
"id": "067",
"slug": "hoodie",
"name": "Hoodie",
"category": "Headwear",
"gender": "Male",
"punkCount": 259,
"punkIds": [12, 45, 78, ...],
"traits": [{ "id": "067", "slug": "hoodie", "name": "Hoodie", "category": "Headwear", "gender": "Male" }],
"pixels": [{ "x": 0, "y": 0, "hex": "#000000" }],
"pixelCount": 120,
"colors": ["#000000", "#555555"],
"urls": { "svg": "...", "png": "...", "pixels": "...", "ascii": "...", "ansi": "..." }
}
}
GET /api/traits/grid — Batch render multiple traits
Render multiple traits in a grid. Essential for browsing categories ("show me all hairstyles") or comparing traits side by side.
| Parameter | Description |
|---|---|
slugs |
Comma-separated trait slugs: mohawk,wildhair,crazyhair |
category |
OR render all traits in a category: Hairstyle, Eyewear, etc. |
body |
Optional body type to render traits on: male1, female2, zombie, etc. |
format |
ansi (default), ascii, svg, json |
cols |
Number of columns (default: auto, max 5) |
background |
Background color/gradient/preset |
labels |
Show trait names above each render (true default) |
Max 50 traits per request. Either slugs or category is required.
Examples:
# All hairstyles on a male body
curl -sL "https://punks.art/api/traits/grid?category=Hairstyle&body=male1&format=ansi&background=punk"
# Compare specific eyewear options on female body
curl -sL "https://punks.art/api/traits/grid?slugs=regularshades,nerdglasses,3dglasses,vr,bigshades&body=female1&format=ansi&background=punk"
# All headwear as SVG
curl -sL "https://punks.art/api/traits/grid?category=Headwear&body=male2&format=svg&size=96&background=punk"
# Traits without body (isolated trait pixels)
curl -sL "https://punks.art/api/traits/grid?category=Eyewear&format=ansi"
GET /api/punks — List & filter punks
Server-side filtering — no need to fetch all 10,000 punks and filter client-side.
| Parameter | Description |
|---|---|
type |
Filter by type: male, female, zombie, ape, alien |
traits |
Filter by trait slugs, comma-separated (AND logic): hoodie,earring |
traitCount |
Filter by exact number of traits (including type) |
limit |
Max results (default: 100) |
offset |
Pagination offset |
includeTraits |
Include trait data (true default, false for lighter response) |
Pagination: Default limit is 100. When filtered results are ≤100, all are returned. Use hasMore to check if more pages exist, then increment offset.
Response:
{
"success": true,
"data": [{ "tokenId": 12, "id": "002-067-081", "traits": [...], "traitCount": 3 }],
"total": 259,
"offset": 0,
"limit": 100,
"hasMore": true,
"filters": { "traits": ["hoodie"] }
}
Examples:
# All alien punks (9 results, not 10,000)
curl -sL "https://punks.art/api/punks?type=alien"
# All punks with a Hoodie
curl -sL "https://punks.art/api/punks?traits=hoodie"
# Punks with both Mohawk AND VR glasses
curl -sL "https://punks.art/api/punks?traits=mohawk,vr"
# Punks with no accessories (type only)
curl -sL "https://punks.art/api/punks?traitCount=1"
# Combine filters: female zombies
curl -sL "https://punks.art/api/punks?type=zombie" # then filter by gender client-side
GET /api/punks/{id} — Get punk data & render
Get a specific punk (0–9999) with full trait info and rendering in any format.
| Parameter | Description |
|---|---|
format |
json (default), pixels, png, svg, ascii, ansi |
background |
Color, gradient, preset, or image URL (see below) |
size |
Grid size (default: 24, or 32 for naked) |
naked |
Full-body 32x32 rendering (true/yes/1) |
dingdong |
Anatomical details: true, tripod, in-a-sock, tripod-in-a-sock |
socks |
Add socks: true or hex color (e.g. ff0000) |
nips |
Special nipple style: clown |
Examples:
# Render punk #2113 in terminal
curl -sL "https://punks.art/api/punks/2113?format=ansi&background=punk"
# Get punk data as JSON
curl -sL "https://punks.art/api/punks/7804"
# PNG for download/sharing
curl -sL "https://punks.art/api/punks/3100?format=png&background=v1" -o punk3100.png
JSON response: { success: true, data: { tokenId, id, traits: [...], pixels: [...], pixelCount, colors, urls } }
GET /api/punks/grid — Batch render multiple punks
Render multiple punks in a single grid. This is the key endpoint for displaying lists of punks efficiently — one call instead of N individual renders.
| Parameter | Description |
|---|---|
ids |
Required. Comma-separated punk IDs: 2113,7804,3100 |
format |
ansi (default), ascii, svg, json (no png — use individual punk endpoint for png) |
cols |
Number of columns (default: auto, max 5) |
background |
Background color/gradient/preset for all punks |
labels |
Show punk ID labels above each punk (true default, false to hide) |
size |
Pixel size for SVG output (default: 24) |
Max 100 punks per request.
Examples:
# Show 9 aliens in a 3x3 grid
curl -sL "https://punks.art/api/punks/grid?ids=635,2890,3100,3443,5822,5905,6089,7523,7804&format=ansi&cols=3&background=punk"
# Show recently sold punks side by side
curl -sL "https://punks.art/api/punks/grid?ids=909,5863,497&format=ansi&background=forsale"
# SVG grid for embedding
curl -sL "https://punks.art/api/punks/grid?ids=2113,7804,3100&format=svg&size=96&background=punk"
# JSON data for all punks in batch
curl -sL "https://punks.art/api/punks/grid?ids=2113,7804,3100&format=json"
ANSI output shows punks side-by-side with labels:
#2113 #7804 #3100
██████████████████████████████ ██████████████████████████████ ██████████████████████████████
██ ████████████████ ██ ████████████████████ ██████████ ██████████████
...
GET /api/punks/random — Random punk(s)
Get one or more random punks. Redirects to /api/punks/{id} (single) or /api/punks/grid (multiple).
| Parameter | Description |
|---|---|
count |
Number of random punks (default: 1, max: 100) |
format |
Output format (passed through to target endpoint) |
background |
Background (passed through) |
Examples:
# Random punk in terminal
curl -sL "https://punks.art/api/punks/random?format=ansi&background=punk"
# 5 random punks in a grid
curl -sL "https://punks.art/api/punks/random?count=5&format=ansi&background=punk"
# Random punk as PNG
curl -sL "https://punks.art/api/punks/random?format=png&background=v1" -o random.png
GET /api/ethusd — ETH/USD price history
Get historical ETH/USD daily close prices from Coinbase. Useful for converting wei values to USD.
| Parameter | Description |
|---|---|
start |
Required. Start date (ISO 8601): 2024-01-01 |
end |
Required. End date (ISO 8601): 2024-12-31 |
Response: { candles: [{ start: "1704067200", close: "2281.42" }, ...] }
start is a Unix timestamp (seconds). close is the USD price as a string.
Examples:
# Today's ETH/USD price
curl -sL "https://punks.art/api/ethusd?start=$(date -u +%Y-%m-%d)&end=$(date -u +%Y-%m-%d)"
# ETH price history for 2024
curl -sL "https://punks.art/api/ethusd?start=2024-01-01&end=2024-12-31"
Wei → USD conversion: (weiValue / 1e18) * ethUsdPrice
Background Presets
| Preset | Hex | Description |
|---|---|---|
punk / v2 |
#638696 | Classic CryptoPunks blue |
v1 |
#A89CFF | V1 purple |
forsale |
#95554F | For-sale red-brown |
bids |
#8E6FB6 | Bids purple |
wrapped1 |
#C8DFCA | Wrapped light green |
wrapped2 |
#67A670 | Wrapped dark green |
Also accepts: any CSS color name (147 colors), hex codes (FF03B4), multi-color gradients (red-blue-gold), or image URLs.
Output Formats
| Format | Content-Type | Description |
|---|---|---|
json |
application/json | Full data with traits, pixels, colors, URLs |
pixels |
application/json | Minimal: just pixel coordinates + hex colors |
png |
image/png | Rasterized image |
svg |
image/svg+xml | Vector image |
ascii |
text/plain | ASCII art (unicode blocks, no color) |
ansi |
text/plain | ANSI art with 24-bit RGB escape codes for terminal display |
API 2: cryptopunks.app (Market & Ownership)
Base URL: https://cryptopunks.app
Note: All endpoints return HTTP 308 redirects. Always use -L with curl or redirect: "follow" with fetch.
GET /api/punks/{punkIndex} — Punk market status
Get owner, sale status, bid status for a specific punk.
Response:
{
"success": true,
"data": {
"id": "2113",
"index": 2113,
"ownerAddress": "0x...",
"isForSale": false,
"hasBid": false,
"attributes": [],
"attributeCount": 0,
"type": "MALE",
"wrapped": false,
"typeName": "Male",
"isHuman": true,
"typeCount": 6039,
"attributeCountTotal": 8,
"isForSaleToAnyone": false,
"isWrappedLegacy": false,
"isWrappedNewContract": false
}
}
GET /api/punks/{punkIndex}/details — Full punk details
Returns punk ownership, bid/offer status, trait info, and attribute rarity data.
Response:
{
"success": true,
"data": {
"punk": {
"index": 2113,
"attributeCount": 3,
"punkCountForAttributeCount": 4501,
"isForSale": false,
"hasBid": false,
"bidderAddress": "",
"ownerAddress": "0x...",
"ownerEns": "vault.gwendall.eth",
"wrapped": { "owner": "0x..." }
},
"punkInfo": {
"type": "Guy",
"attributes": ["Handlebars", "Earring", "Crazy_hair"]
},
"punkData": {
"attributeCounts": { "Handlebars": 562, "Earring": 2459, "Crazy_hair": 406 },
"typeCounts": { "Male": 6039, "Female": 3840, "Zombie": 88, "Ape": 24, "Alien": 9 }
}
}
}
Note: punkInfo.type uses "Guy" for males and "Girl" for females. Attributes use underscores (e.g. "Crazy_hair").
GET /api/punks/{punkIndex}/image — Official punk image
Returns a 1024x1024 PNG.
| Parameter | Description |
|---|---|
transparent |
true for transparent background |
bg |
Hex color for background |
GET /api/punks?action={action} — Market data
| Action | Description |
|---|---|
index |
Homepage data (see below) |
floor |
Current floor price as wei string |
floor-punk |
Punk with lowest offer |
offered-ids |
Array of punk IDs currently for sale |
bids |
Punks with active bids |
all-bids |
All active bids (up to 1000) |
recent-sales |
Recent sales (optional count param, default 20, max 50) |
top-sales |
Top sales by value |
leaderboard |
Top holders, bidders, sellers |
attributes |
Punk type and attribute count statistics |
wrapped |
Wrapped punks |
action=index response:
{
"success": true,
"data": {
"owned": [],
"offered": [{ "punkId": "5863", "seller": "0x...", "minValue": "28990000000000000000" }],
"bids": [],
"wrapped": [],
"stats": { "punksForSale": 1159, "punksBid": 7, "totalBidValueInWei": "...", "totalSaleValueInWei": "..." },
"recentEvents": [],
"topSales": [],
"wrappedPunkCount": 0
}
}
action=floor response: { "success": true, "data": "28990000000000000000" } (wei string, "0" if no offers)
action=floor-punk response:
{
"success": true,
"data": {
"currentPunkOffers": {
"items": [{
"punkId": "5863",
"seller": "0x...",
"minValue": "28990000000000000000",
"toAddress": "0x0000000000000000000000000000000000000000",
"offeredAt": 1773609587,
"transactionHash": "0x..."
}]
}
}
}
Note: toAddress = zero address means open to anyone.
action=offered-ids response: { "success": true, "data": [497, 8421, 8633, 5863, ...] }
To get full details for offered punks, use action=offered-ids then look up each punk individually. Do NOT use action=offered (currently broken).
action=recent-sales response:
{
"success": true,
"data": [{
"id": "...",
"punkId": "909",
"seller": "0x...",
"buyer": "0x...",
"value": "29500000000000000000",
"usdValue": "61802",
"timestamp": 1773596015,
"transactionHash": "0x..."
}]
}
Note: value is in wei. punkId is a string.
action=leaderboard response:
{
"success": true,
"data": {
"topHolders": [{ "address": "0x...", "punkCount": 414, "ensAddress": null, "lastActive": 1747157519 }],
"topBidders": [],
"topSellers": []
}
}
action=attributes response:
{
"success": true,
"data": {
"punkTypes": [{ "type": "Male", "count": 6039 }, { "type": "Female", "count": 3840 }],
"attributeCounts": [{ "count": 0, "punksWithCount": 8 }, { "count": 1, "punksWithCount": 333 }]
}
}
Examples:
# Floor price
curl -sL "https://cryptopunks.app/api/punks?action=floor"
# Punks for sale (IDs only — use this, not action=offered)
curl -sL "https://cryptopunks.app/api/punks?action=offered-ids"
# Recent sales
curl -sL "https://cryptopunks.app/api/punks?action=recent-sales&count=10"
# Top holders
curl -sL "https://cryptopunks.app/api/punks?action=leaderboard"
GET /api/account/{address} — Account portfolio
Get all punks owned by an address, plus purchase/sale history.
| Parameter | Description |
|---|---|
address |
Ethereum address or ENS name |
owned |
If true, only returns owned punks |
Response:
{
"success": true,
"data": {
"ethAddress": { "address": "0x...", "ens": "vault.gwendall.eth" },
"owned": [{
"index": 3,
"type": "Male",
"attributes": ["Wild_Hair", "Pipe", "Nerd_Glasses"],
"traitCount": 3,
"wrapped": false,
"backgroundColor": "#638596",
"offerValue": { "valueStrVeryShort": "0 ETH", "valueStrJustUSD": "$0" },
"bidValue": {}
}],
"stashOwner": null,
"isStashContract": false
}
}
GET /api/traits/{punkId} — Punk traits (cryptopunks.app)
Returns raw trait data for a punk. Note: response is NOT wrapped in { success, data }.
Response:
{
"punkId": "2113",
"type": "Male",
"attributes": ["Handlebars", "Earring", "Crazy_hair"]
}
Note: Attributes use underscores (e.g. Crazy_hair). To convert to display format, replace underscores with spaces.
GET /api/jsonRecentSales — Recent sales (alternative format)
| Parameter | Description |
|---|---|
count |
Max results (default: 20, max: 50) |
Response (array, NOT wrapped in { success, data }):
[{
"sellerAddress": "0x...",
"buyerAddress": "0x...",
"valueInWei": "29500000000000000000",
"transactionHash": "0x...",
"blockNumber": 24664412,
"punkIndex": 909,
"timestamp": "Mar 15, 2026, 5:33:35 PM",
"currentPunkStatus": {
"index": 909,
"ownerAddress": "0x...",
"isForSale": false,
"offerValue": 0,
"hasBid": false,
"bidValue": 0
}
}]
Collection Bids API
Base URL: https://bids.cryptopunks.app
Interactive docs: https://bids.cryptopunks.app/docs
| Endpoint | Description |
|---|---|
GET /api/v1/bids |
List bids (filter by bidder, status, limit, chainId) |
GET /api/v1/bids/top |
Highest bids by amount |
GET /api/v1/bids/all |
All bids (up to 1000) |
GET /api/v1/bids/punk/{id} |
Bids that include a specific punk |
POST /api/v1/bids/refresh |
Refresh bid statuses on-chain (body: { bidder, chainId }) |
Common Workflows
"Show me all punks with a Hoodie"
# Step 1: Get count and IDs (1 call)
curl -sL "https://punks.art/api/traits/hoodie" | jq '{punkCount, punkIds}'
# → { "punkCount": 259, "punkIds": [12, 45, 78, ...] }
# Step 2: Render a sample in a grid (1 call)
# Take first 10 IDs from punkIds and display them
curl -sL "https://punks.art/api/punks/grid?ids=12,45,78,112,189,201,234,267,301,345&format=ansi&cols=5&background=punk"
"What's the floor price for Alien punks?"
# Step 1: Get all alien punk IDs (1 call)
curl -sL "https://punks.art/api/punks?type=alien&includeTraits=false" | jq '.data[].tokenId'
# → 635, 2890, 3100, 3443, 5822, 5905, 6089, 7523, 7804
# Step 2: Get offered punk IDs (1 call)
curl -sL "https://cryptopunks.app/api/punks?action=offered-ids"
# Step 3: Cross-reference alien IDs with offered IDs, then check prices
# Step 4: Render the cheapest alien
curl -sL "https://punks.art/api/punks/{id}?format=ansi&background=forsale"
"Show me all 9 Aliens"
# 1 call renders all 9 in a grid
curl -sL "https://punks.art/api/punks/grid?ids=635,2890,3100,3443,5822,5905,6089,7523,7804&format=ansi&cols=3&background=punk"
"Generate a custom punk with Mohawk + VR glasses"
curl -sL "https://punks.art/api/traits/male1-mohawk-vr?format=ansi&background=punk"
"Show me a random punk"
curl -sL "https://punks.art/api/punks/random?format=ansi&background=punk"
"Show me 10 random punks"
curl -sL "https://punks.art/api/punks/random?count=10&format=ansi&cols=5&background=punk"
"How many punks have a Mohawk?"
# 1 call — returns punkCount and punkIds
curl -sL "https://punks.art/api/traits/mohawk" | jq '.data.punkCount'
# → 288
"Show me the rarest punk"
# Punks with 0 attributes (just a type, no accessories) — the rarest
curl -sL "https://punks.art/api/punks?traitCount=1"
# Then render them
curl -sL "https://punks.art/api/punks/grid?ids=...&format=ansi&background=punk"
"Make a nude of punk #507"
curl -sL "https://punks.art/api/punks/507?format=ansi&naked=true&dingdong=on&background=punk"
"Who owns the most punks?"
curl -sL "https://cryptopunks.app/api/punks?action=leaderboard"
# Read data.topHolders — each entry has address, punkCount, ensAddress
"Show me recent sales with visuals"
# Step 1: Get recent sales
curl -sL "https://cryptopunks.app/api/punks?action=recent-sales&count=5"
# Step 2: Extract punkIds, render as grid
curl -sL "https://punks.art/api/punks/grid?ids=909,5863,497,8421,1234&format=ansi&background=forsale"
"What does this wallet own?"
# Step 1: Get owned punks
curl -sL "https://cryptopunks.app/api/account/{address}?owned=true"
# Step 2: Extract indices, render as grid
curl -sL "https://punks.art/api/punks/grid?ids=3,1234,5678&format=ansi&background=punk"
"Show me punks for sale"
# Step 1: Get IDs for sale
curl -sL "https://cryptopunks.app/api/punks?action=offered-ids"
# Step 2: Render first 20 as grid
curl -sL "https://punks.art/api/punks/grid?ids=497,8421,8633,5863,...&format=ansi&cols=5&background=forsale"
"Show me all hairstyles" (artist)
# 1 call renders every hairstyle on a male body
curl -sL "https://punks.art/api/traits/grid?category=Hairstyle&body=male1&format=ansi&cols=5&background=punk"
"Which traits are rarest?" (artist/investor)
# 1 call — sort by punkCount to find rarest
curl -sL "https://punks.art/api/traits" | jq '.data | sort_by(.punkCount) | .[0:10] | .[] | "\(.name): \(.punkCount) punks"'
"What would punk #2113 look like with a Mohawk instead?" (artist)
# Step 1: Get punk's current traits
curl -sL "https://punks.art/api/punks/2113" | jq '.data.traits[].slug'
# → male2, handlebars, earring, crazyhair
# Step 2: Swap crazyhair for mohawk and render
curl -sL "https://punks.art/api/traits/male2-handlebars-earring-mohawk?format=ansi&background=punk"
"What's the cheapest Ape for sale?" (investor)
# Step 1: Get ape punk IDs
curl -sL "https://punks.art/api/punks?type=ape&includeTraits=false" | jq '.data[].tokenId'
# Step 2: Get offered punk IDs
curl -sL "https://cryptopunks.app/api/punks?action=offered-ids"
# Step 3: Cross-reference → find ape IDs in offered list
# Step 4: For matching IDs, get price via /api/punks/{id} on cryptopunks.app
# Step 5: Render the cheapest one
curl -sL "https://punks.art/api/punks/{id}?format=ansi&background=forsale"
"How much is X ETH in USD?" (investor)
# Get today's ETH/USD price
curl -sL "https://punks.art/api/ethusd?start=$(date -u +%Y-%m-%d)&end=$(date -u +%Y-%m-%d)"
# → { candles: [{ close: "2095.32" }] }
# Then: ethAmount * 2095.32 = USD value
"Compare these eyewear options on my punk" (artist)
# Render different eyewear on the same body type
curl -sL "https://punks.art/api/traits/grid?slugs=regularshades,nerdglasses,3dglasses,vr,bigshades,classicshades&body=female1&format=ansi&cols=3&background=punk"
Data Notes
- Punk indices: 0–9999 (10,000 total)
- Types: Male (4 skin tones), Female (4 skin tones), Zombie (88 total), Ape (24 total), Alien (9 total)
- All ETH values from cryptopunks.app are in wei as strings (divide by 1e18 for ETH)
- cryptopunks.app uses underscores in attribute names (e.g.
Crazy_hair); punks.art uses human-readable names (e.g.Crazy Hair) - cryptopunks.app
/detailsusestype: "Guy"for males andtype: "Girl"for females; other endpoints use"MALE"/"Male" - ENS names are auto-resolved on cryptopunks.app endpoints
- ANSI output requires a terminal with 24-bit true color support
- All punks.art responses are edge-cached and immutable
action=offeredis currently broken — useaction=offered-idsinstead
Error Handling & Troubleshooting
punks.art errors
- Invalid punk ID (not 0–9999):
{ success: false, error: "Token ID must be between 0 and 9999" }(400) - Invalid trait slug:
{ success: false, error: "Trait not found: ..." }(404) - Punk grid: no IDs:
{ success: false, error: "ids parameter is required..." }(400) - Punk grid: too many:
{ success: false, error: "Maximum 100 punks per grid request" }(400) - Trait grid: no params:
{ success: false, error: "Either slugs or category parameter is required" }(400) - Trait grid: too many:
{ success: false, error: "Maximum 50 traits per grid request" }(400) - All punks.art responses include
success: true|false— always check this field.
cryptopunks.app errors
- 308 redirects: If you get an empty response, you're not following redirects. Use
-Lwith curl. - action=offered: Returns
{ success: false, error: "Failed to get offered punks" }. Useaction=offered-idsinstead. - Invalid address in /api/account: Returns
{ success: false }with error message.
Common mistakes
- Fetching all 10,000 punks when you could filter server-side with
?type=or?traits= - Rendering punks one-by-one when the grid endpoint handles batches
- Forgetting
-Lon cryptopunks.app requests (308 redirect not followed) - Using
action=offeredinstead ofaction=offered-ids - Not converting wei to ETH (divide by 1e18) when displaying prices
- Using
type: "Male"to filter when/detailsreturnstype: "Guy"