关于 collectorcrypt
CollectorCrypt API 技能用于与 Solana 上的收藏卡 NFT 市场及周边服务交互,适合构建卡牌交易、盲包和实体卡兑换流程。它涵盖市场、Gacha、Vault、Swap 等服务,并通过钱包签名处理链上交易。
主要功能
- 01浏览并交易收藏卡 NFT
- 02创建并开启随机卡牌盲包
- 03在 NFT 与实体卡之间兑换
- 04通过托管机制进行点对点交换
- 05支持多种 Solana NFT 标准
适用场景
- 01浏览市场并购买或上架收藏卡
- 02集成盲包生成与开包流程
- 03将实体卡存入 Vault 铸造 NFT
- 04构建链上 NFT 或代币交换流程
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ starchild-ai-agent/ official-skills --skill collectorcrypt安装后在 Claude Code 中输入/collectorcrypt确认已加载。
详细介绍
CollectorCrypt API
连接实体集换式卡牌与区块链 —— 在 Solana 上买卖和交易收藏卡牌 NFT,开启神秘扭蛋包,将 NFT 兑换为实体卡牌,并进行点对点资产兑换。
市场基础 URL: https://api.collectorcrypt.com
市场 Devnet URL: https://dev-api.collectorcrypt.com
扭蛋基础 URL: https://gacha.collectorcrypt.com
扭蛋 Devnet URL: https://dev-gacha.collectorcrypt.com
核心概念
产品套件
- Marketplace — 在 Solana 上使用 USDC 买卖和交易收藏卡牌 NFT
- Gacha Machine — 神秘卡包系统;使用 USDC 购买随机生成的 Pokemon 卡牌 NFT,并通过 VRF 验证公平性
- Vault — 连接 NFT 与实体卡牌;存入实体卡牌以铸造 NFT,销毁 NFT 以寄送实体卡牌
- Swap — 通过托管机制进行链上点对点资产兑换(NFT、pNFT、cNFT、SPL 代币)
- Launchpads — 用于铸造全新收藏品系列的发售页面
- Bidder — eBay 出价自动化;存入资金、代为出价,并将竞得的卡牌代币化
Solana 程序
| 程序 | ID |
|---|---|
| Marketplace | CcmRKTuZCGJBWQwMHvDYApBRvSZNHqGJXkznqpDTSQUr |
| Swap | CCSwaptcDXtfjyRMYBqavqBwiW162yXFAJrXN53UuENC |
支持的 NFT 类型
- 可编程 NFT(pNFT) — 采用 Metaplex 标准并强制执行版税;使用
tokenStandard: "Pnft" - 压缩 NFT(cNFT) — 采用 Metaplex Bubblegum 默克尔树结构;使用
tokenStandard: "Cnft" - Metaplex Core(
nftStandard: "core") — 单账户标准;许多正在交易的挂单都是 Core(浏览响应会返回"nftStandard": "core")。对于 Core 挂单,买入/挂单/出价请求正文中省略tokenStandard—— 切勿传入"Pnft"/"Cnft"。只有当资产确实是 pNFT 或 cNFT 时,才发送tokenStandard。
货币
所有市场和扭蛋交易均使用 Solana 上的 USDC(SPL Token)。运费支持使用 USDC 或 USDT 支付。Gas 费用以 SOL 支付。
市场价格以整数 USDC 为单位(例如,"price": 25 表示 $25.00 USDC)。
交易流程(市场与配送)
三步流程:
- 构建 — 向 API 端点发送 POST 请求,获取 base64 编码的未签名交易
- 签名 — 使用 Solana 钱包(Phantom/Solflare,或 Starchild 钱包辅助工具,见下文)签名
- 广播 — 将已签名交易 POST 到
/marketplace/broadcast
HTTP 状态码 —— 200 和 201 均应视为成功。 实测确认:/marketplace/buy 和 /marketplace/broadcast 返回 201,而非 200。任何 2xx 状态码都应视为成功;不要严格检查 == 200。
响应正文可能是原始 base64 文本,而非 JSON。 使用 fundingSource: "wallet" 调用 /marketplace/buy 时,未签名交易可能以纯文本正文形式返回。请采用防御式解析:
text = response.text
try:
data = response.json()
tx = data.get("transaction") or data.get("serializedTransaction")
except Exception:
tx = text # body was the raw base64 transaction
Starchild 钱包签名会返回 snake_case 格式的 signed_transaction。 使用平台钱包签名时:
from core.skill_tools import wallet
signed = wallet.wallet_sol_sign_transaction(unsigned_tx)
# → {"signed_transaction": "<base64>", "encoding": "base64"}
signed_tx = signed.get("signed_transaction") or signed.get("signedTransaction")
优先查找 signed_transaction,然后再查找 camelCase 变体。将 signed_tx 作为 signedTransaction 字段传入 /marketplace/broadcast。
扭蛋稀有度等级
| 稀有度 | 概率 |
|---|---|
| Epic | 1% |
| Rare(高) | 4% |
| Uncommon(中) | 15% |
| Common(低) | 80% |
VRF(可验证随机函数)
抽卡使用可验证随机函数,确保结果防篡改且可证明公平。选择分为 两个阶段:
- **抽取 → 稀有度等级:**生成一个均匀分布的整数,范围为 1–100,000,000,以玩家在待处理交易上的钱包签名作为种子,再根据机器配置的权重映射到稀有度等级(参见
/api/machines中的tierRanges)。 - **卡牌 → 等级内选择:**通过可验证的选择,从该等级中选出具体的 NFT。
种子(钱包签名)和结果会记录在 Solana 的奖励交易链上备忘录中,防止预测或操纵。可独立验证:
GET /api/vrf/verify?memo=YOUR_MEMO— 返回证明、公钥、交易签名,以及存储的抽取结果是否与重新计算的结果相符。/verify-selection/YOUR_MEMO— 在浏览器端重放卡牌选择,并与链上备忘录进行比对。
文档没有指定具体的 VRF 算法;请勿声称使用了某种算法。
如何调用
Gacha API — 无需 API 密钥(密钥并不存在)
没有 API 密钥。请勿设置 CC_API_KEY、勿发送 x-api-key 标头,也不要尝试获取密钥 — CollectorCrypt 团队已确认不存在密钥系统。 所有 Gacha 端点,无论是读取还是写入,调用时均无需身份验证。
# Reads AND writes — no auth header of any kind
curl -s "https://gacha.collectorcrypt.com/api/machines"
curl -s -X POST "https://gacha.collectorcrypt.com/api/generatePack" \
-H "Content-Type: application/json" \
-d '{"playerAddress":"WALLET_PUBKEY"}'
请忽略文档中的身份验证部分。 公开文档称“每个请求都必须包含有效的
x-api-key标头”,并提到了合作伙伴的“slug”。这与实际情况不符 — 团队已确认不存在密钥系统,且实测/api/generatePack在未提供标头时返回200。无需申请任何内容,也无需添加任何标头。
没有密钥时,生成的交易会携带 cc-<uuid> 备忘录。安全性来自钱包签名,而非任何 API 凭据 — 在用户签署此 API 返回的交易之前,不会执行任何操作。
参考实现:Gacha Starter Demo — https://github.com/daxherrera/gacha-starter(完整的卡包 → 签名 → 提交 → 开启流程)。可在 devnet 上实时尝试所有调用:https://dev-gacha.collectorcrypt.com(通过 USDC 水龙头为 devnet 钱包注资:https://spl-token-faucet.com/?token-name=USDC-Dev)。
Marketplace API — 读取无需身份验证
公开的 GET 端点(浏览挂单)无需身份验证。写入端点会返回未签名的交易,由钱包签名 — 不涉及 API 密钥。
# Browse listings — no auth, 5s cache for unauthenticated requests
curl -s "https://api.collectorcrypt.com/marketplace?page=1&step=20&categories=Pokemon"
# Create listing — returns base64 unsigned transaction
curl -s -X POST "https://api.collectorcrypt.com/marketplace/list" \
-H "Content-Type: application/json" \
-d '{
"wallet": "YOUR_SOLANA_ADDRESS",
"cardId": "CC_CARD_DB_ID",
"nftAddress": "NFT_MINT_ADDRESS",
"currency": "USDC",
"price": 50
}'
Shipping API — 两种身份验证方式
方式 A — Privy 身份令牌:
Authorization: Bearer <privy-identity-token>
方式 B — 使用 Solana 登录(SIWS):
POST /auth/wallet/nonce— 获取 nonce 和待签名消息- 使用钱包签署消息(ed25519,base58)
POST /auth/wallet/verify— 用签名交换访问令牌和刷新令牌
# Step 1: Get nonce
curl -s -X POST "https://api.collectorcrypt.com/auth/wallet/nonce" \
-H "Content-Type: application/json" \
-d '{"wallet": "YOUR_PUBKEY", "partnerAppId": "your-slug", "domain": "your-app.com", "uri": "https://your-app.com"}'
# Step 3: Verify and get tokens
curl -s -X POST "https://api.collectorcrypt.com/auth/wallet/verify" \
-H "Content-Type: application/json" \
-d '{"message": "<message-from-nonce>", "signature": "<base58-ed25519-signature>"}'
# Returns: {"accessToken": "cca_...", "refreshToken": "ccr_...", "expiresAt": ...}
令牌管理:
- 访问令牌有效期:15 分钟
- 刷新:使用
{"refreshToken": "..."}调用POST /auth/wallet/refresh - 登出:
POST /auth/wallet/logout - 方式 B 的限制:仅支持加密货币支付(不支持银行卡支付),且仅支持 Solana 签名
意图路由
Marketplace
基础地址:https://api.collectorcrypt.com
所有 POST 端点都会返回经过 base64 编码的未签名 Solana 交易。使用钱包签名后,通过 /marketplace/broadcast 广播。
挂售 NFT — POST /marketplace/list
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
wallet | string | 是 | 卖家的 Solana 地址 |
cardId | string | 是 | CollectorCrypt 卡牌数据库 ID |
nftAddress | string | 是 | NFT 铸币地址 |
currency | string | 是 | "USDC" |
price | number | 是 | 以 USDC 计价的挂售价 |
tokenStandard | enum | 否 | "Pnft" 或 "Cnft" |
userHasSol | boolean | 否 | 若为 false,则由后端支付费用 |
错误:400(链上错误)、409(已挂售)
取消挂单 — POST /marketplace/cancel-listing
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
wallet | string | 是 | 调用者的钱包 |
tokenMint | string | 是 | NFT 铸造地址 |
seller | string | 否 | 默认为 wallet |
错误:400(链上错误),404(未找到挂单)
更新挂单价格 — POST /marketplace/update-listing
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
wallet | string | 是 | 卖家的钱包 |
tokenMint | string | 是 | NFT 铸造地址 |
newPrice | number | 是 | 更新后的 USDC 价格 |
coin | string | 是 | "USDC" |
错误:400(价格未变或链上错误),404(未找到挂单)
购买 NFT — POST /marketplace/buy
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
wallet | string | 是 | 买家的钱包 |
nftAddress | string | 是 | NFT 铸造地址 |
price | number | 是 | 挂单价格(USDC) |
currency | string | 是 | "USDC" |
tokenStandard | enum | 否 | "Pnft" 或 "Cnft" — Metaplex Core 挂单请省略此项(nftStandard: "core") |
sellerWallet | string | 否 | 如果省略,则从数据库解析 |
fundingSource | enum | 否 | "wallet"(默认)或 "escrow" |
成功状态为 200 或 201(实时购买返回 201)。响应正文可能是原始 base64 文本,而非 JSON — 请采取稳健的解析方式(见上文的 Transaction Pattern)。
fundingSource: "wallet"→ 单个 base64 未签名交易(JSON{"transaction": "..."}或纯 base64 文本)fundingSource: "escrow"→{"transactions": ["BASE64_WITHDRAW_TX", "BASE64_BUY_TX"], "fundingSource": "escrow"}
Escrow 要求 USDC 余额至少为 price × 1.02。
错误:400(链上错误、Escrow 余额不足),404(未找到卡片/挂单),409(所有者已变更)
端到端购买操作指南(经实时测试)
import requests
from core.skill_tools import wallet
BASE = "https://api.collectorcrypt.com"
buyer = "YOUR_WALLET_PUBKEY"
# 1. Find a listed item, cheapest first
listings = requests.get(f"{BASE}/marketplace",
params={"page": 1, "step": 1, "marketplaceStatus": "Buy now", "orderBy": "listedPriceAsc"}
).json()["filterNFtCard"]
item = listings[0]
mint = item["nftAddress"]
price = float(item["listing"]["price"])
seller = item["owner"]["wallet"]
std = item.get("nftStandard") # "core" | "Pnft" | "Cnft"
# 2. Build buy tx. Omit tokenStandard for Core listings.
body = {"wallet": buyer, "nftAddress": mint, "price": price,
"currency": "USDC", "sellerWallet": seller}
if std in ("Pnft", "Cnft"):
body["tokenStandard"] = std
r = requests.post(f"{BASE}/marketplace/buy", json=body)
assert r.status_code in (200, 201) # buy returns 201
try: unsigned = r.json().get("transaction") or r.json().get("serializedTransaction")
except Exception: unsigned = r.text # may be raw base64
# 3. Sign with Starchild wallet (snake_case key)
signed = wallet.wallet_sol_sign_transaction(unsigned)
signed_tx = signed.get("signed_transaction") or signed.get("signedTransaction")
# 4. Broadcast
b = requests.post(f"{BASE}/marketplace/broadcast",
json={"wallet": buyer, "signedTransaction": signed_tx, "nftAddress": mint})
assert b.status_code in (200, 201) and b.json().get("success") # broadcast returns 201
sig = b.json()["signature"]
# 5. Verify on Solana RPC — the SOURCE OF TRUTH (see below)
status = requests.post("https://api.mainnet-beta.solana.com", json={
"jsonrpc": "2.0", "id": 1, "method": "getSignatureStatuses",
"params": [[sig], {"searchTransactionHistory": True}]}
).json()["result"]["value"][0]
assert status and status["err"] is None and status["confirmationStatus"] == "finalized"
请通过 Solana RPC 签名状态进行验证,而非重新获取市场数据。 购买后,市场元数据的刷新会有延迟;同时没有 nftAddress 查找筛选器(search=<mint> 是模糊搜索,可能无法立即反映新的所有者)。广播后权威的检查方式是对广播的 signature 调用 getSignatureStatuses:
{"confirmationStatus": "finalized", "err": null, "status": {"Ok": null}}
err == null(且 confirmationStatus 为 confirmed/finalized)表示购买已在链上完成。仅在需要显示时才回退到重新获取市场数据,切勿将其作为成功判定条件。
回归测试样例 — 一笔成功的真实购买(用于对流程进行冒烟测试):
| 字段 | 值 |
|---|---|
| 商品 | 2017 #024 POKE BALL PSA 9 — Pokémon Japanese Sun & Moon, Ash vs. Team Rocket Deck Kit |
| 价格 | 19 USDC |
| NFT 铸造地址 | 4AWreh7pqVb4jhANAXFz2fwSPKqWr5ZAFMgaAFWZS9nk |
| 卖家 | FfveJgtFmGPCSazkjicf21WLk9rdUaMsownVVA8LRhwf |
| 广播签名 | 5SwxeuWGjWbiAFq8YVN3Qsw1PXnKXBakKA2ykgccc78gg6JkGnyi48StezcijXmgWHyGWvojq8TYmTXJoC9XnbjH |
| Solana 状态 | finalized,err: null |
发起报价 — POST /marketplace/make-offer
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
wallet | string | 是 | 买家的钱包 |
cardId | string | 是 | CollectorCrypt 卡片数据库 ID |
nftAddress | string | 是 | NFT 铸造地址 |
price | number | 是 | 报价(USDC) |
currency | string | 是 | "USDC" |
tokenStandard | enum | 否 | "Pnft" 或 "Cnft" |
userHasSol | boolean | 否 | 如果为 false,则由后端支付费用 |
ownerWallet | string | 否 | 当前 NFT 所有者 |
collectionHash | string | 否 | cNFT 集合哈希 |
错误:400(无法确定所有者或链上错误)
取消报价 — POST /marketplace/cancel-offer
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
wallet | string | 是 | 买家的钱包 |
nftAddress | string | 是 | NFT 铸造地址 |
keepInEscrow | boolean | 否 | 如果为 true,USDC 会留在托管账户中;默认为 false |
如果钱包中的 SOL 不足以支付租金,后端会自动将 keepInEscrow 设为 true。
错误:404(未找到有效报价)
更新报价 — POST /marketplace/update-offer
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
wallet | string | 是 | 买家的钱包(签名者) |
nftAddress | string | 是 | NFT 铸造地址 |
currency | string | 是 | "USDC" |
buyer | string | 是 | 买家的钱包(通常与 wallet 相同) |
price | number | 是 | 新报价,单位为 USDC |
重要: 托管账户中必须已包含全部新金额 — 此指令不会转入额外的 USDC。
错误:400(价格未变、无托管资金、余额不足、链上错误),404(未找到报价)
接受报价 — POST /marketplace/accept-offer
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
wallet | string | 是 | 卖家的钱包(NFT 所有者) |
nftAddress | string | 是 | NFT 铸造地址 |
buyer | string | 是 | 买家的钱包 |
currency | string | 是 | "USDC" |
price | number | 是 | 报价,单位为 USDC |
tokenStandard | enum | 否 | "Pnft" 或 "Cnft" |
userHasSol | boolean | 否 | 如果为 false,则由后端支付手续费 |
cNFT 边缘情况: 如果 cNFT 当前已上架,则返回:
{
"requiresCancelListing": true,
"cancelListingTx": "BASE64_CANCEL_LISTING_TX",
"message": "This cNFT is currently listed. Please sign..."
}
先签署取消上架交易,然后重新调用 accept-offer。
错误:400(价格偏差、链上错误),404(未找到报价)
浏览列表 — GET /marketplace
公开接口,无需身份验证。未验证请求的缓存时间为 5 秒。
分页:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
page | 整数 | 1 | 页码从 1 开始 |
step | 整数 | 100 | 每页数量(最多 100) |
筛选条件(均为可选):
| 参数 | 类型 | 说明 |
|---|---|---|
search | 字符串 | 按 itemName、nftAddress、gemrateCardName、gradingID 进行子串匹配。这是按 mint 查询的唯一方式——没有 nftAddress 查询参数(GET /marketplace?nftAddress=<mint> 会返回 400)。请改用 search=<mint>。 |
ownerAddress | 字符串 | 按持有者钱包筛选 |
hideOwned | 布尔值 | 隐藏调用者自己的卡片(需要身份验证) |
favoritesOnly | 布尔值 | 仅显示收藏的卡片(需要身份验证) |
followingOnly | 布尔值 | 仅显示来自已关注用户的卡片(需要身份验证) |
followingOf | 字符串 | 显示由此钱包关注的用户所持有的卡片 |
marketplaceStatus | CSV | Buy now、Has offers |
marketplaceSource | CSV | CC、ME |
marketplaceTags | CSV | 全局标签名称(例如,Hot、Featured) |
listPriceMin / listPriceMax | 数字 | USDC 价格范围 |
insuredValueMin / insuredValueMax | 数字 | 保额范围 |
yearMin / yearMax | 整数 | 卡片年份范围 |
categories | CSV | Pokemon、Baseball、Basketball、Football、Magic The Gathering、Yu-Gi-Oh!、Lorcana、One Piece、Non-Sport 等 |
cardType | CSV | Card、Comic、ComicRaw、Game、Merch、Raw、Sealed |
blockchain | CSV | Solana 等 |
authenticated | 布尔值 | 仅显示经过认证的卡片 |
autographed | 布尔值 | 仅显示带签名的卡片 |
burnt | 布尔值 | 包含已销毁的卡片(默认排除) |
grade | 字符串 | 子串匹配 |
genericGradeMin / genericGradeMax | 数字 | 数字评分范围 |
gradingCompany | CSV | PSA、Beckett、CGC、SGC、TAG、CSG、KSA、PSA/DNA、UDA、Steiner、BBCE、Rare Edition、Not graded |
set / format / language / productCode | 字符串 | 对密封商品/漫画元数据进行子串匹配 |
pokemon | 字符串 | 针对 gemrateCardName 按单词边界匹配 |
ccBuyback | 布尔值 | 仅显示启用了 CC 回购的卡片 |
gemrateSet / gemrateGrade / gemrateCardName / gemrateSpecId / gemrateParallel | 字符串 | Gemrate 专用筛选条件 |
排序 — orderBy 的取值:
dateAsc、dateDesc、nameAsc、nameDesc、priceAsc、priceDesc(保额)、yearAsc、yearDesc、listedDateAsc、listedDateDesc、listedPriceAsc、listedPriceDesc
默认值:listedDateDesc
响应:
{
"filterNFtCard": [
{
"id": "card_db_id",
"itemName": "...",
"nftAddress": "NFT_MINT_ADDRESS",
"nftStandard": "Pnft",
"blockchain": "Solana",
"category": "Pokemon",
"type": "Card",
"year": 1999,
"grade": "10",
"gradeNum": 10,
"gradingCompany": "PSA",
"gradingID": "...",
"insuredValue": "...",
"listing": {
"price": "25",
"currency": "USDC",
"marketplace": "CC",
"sellerId": "...",
"createdAt": "ISO_DATE"
},
"offers": [{"id": "offer_id"}],
"owner": {
"id": "user_id",
"name": "...",
"wallet": "OWNER_WALLET_ADDRESS"
},
"images": {
"front": "URL",
"frontM": "URL",
"frontS": "URL",
"back": "URL",
"backM": "URL",
"backS": "URL"
}
}
],
"findTotal": 1234,
"total": 50000,
"totalPages": 25,
"cardsQtyByCategory": {"Pokemon": 800, "Baseball": 200}
}
- 未上架时,
listing为null offers是有效报价 ID 的数组findTotal= 符合筛选条件的总数;total= 市场中的卡片总数cardsQtyByCategory= 各类别的数量(不包括categories筛选条件)
广播交易 — POST /marketplace/broadcast
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
wallet | 字符串 | 是 | 签名者钱包地址 |
signedTransaction | 字符串 | 是 | Base64 编码的已签名交易 |
nftAddress | 字符串 | 否 | 5 秒后触发元数据刷新 |
成功状态为 200 或 201(实时广播返回 201)。响应:
{
"success": true,
"signature": "SOLANA_TRANSACTION_SIGNATURE",
"message": "Transaction broadcast successfully"
}
不要将 201 视为失败——请检查 success === true 或是否存在 signature,而不是检查状态码。
**余额不足时的恢复方式:**如果广播返回 400,且 "code": "INSUFFICIENT_FUNDS_RETRYABLE",请将 userHasSol: false 传入,以重新构建原始交易,让后端支付费用;然后重新签名并再次广播。
**验证:**提交前,会根据程序 ID 允许列表验证交易。
错误:400(交易无效、可重试的余额不足、提交失败),403(程序 ID 不在允许列表中)
Gacha Machine
基础 URL:https://gacha.collectorcrypt.com
| 方法 | 端点 | 主要参数 | 描述 |
|---|---|---|---|
| GET | /api/status | — | 机器运行状态(开启/关闭) |
| GET | /api/stock | — | 每台机器按稀有度划分的 NFT 库存数量 |
| GET | /api/machines | — | 所有机器的完整配置:价格、odds、tierRanges(roll→tier 边界)、实时 stock、instantBuyback %,以及 ev(按稀有度加权的预期保价) |
| GET | /api/getNfts | code、rarity、page、limit | 支持筛选的可用 NFT |
| POST | /api/generatePack | Body:playerAddress、packType、turbo、altPlayerAddress | 创建一包的购买交易 |
| POST | /api/generateYoloPacks | Body:count(1-100)、packType、playerAddress、turbo、altPlayerAddress | 批量购买多包 |
| POST | /api/openPack | Body:memo | 打开已购买的包并获得 NFT |
| POST | /api/buyback | Body:playerAddress、nftAddress、altRecipient | 将 NFT 卖回以换取 USDC(72 小时内) |
| GET | /api/buyback/check | memo | 检查回购完成状态 |
| GET | /api/buyback/available | wallet、nft | 预先检查 NFT 是否符合回购条件,并返回退款 amount(构建交易前) |
| GET | /api/pack/status | memo | 完整的包生命周期:购买、发送 NFT(包括 prize_tier、insured_value、vrf_proof)以及回购历史 |
| POST | /api/submitTransaction | Body:signedTransaction(base64) | 将已签名交易提交至 Solana |
| POST | /api/generateGift | Body:sender、receiver、packType、count | 向另一个钱包赠送包 |
| GET | /api/getGifted | wallet | 赠送历史(已发送/已接收) |
| GET | /api/purchasedPacks | wallet | 按类型统计包数量(已购买/已赠送、已使用/未使用) |
| POST | /api/generatePurchasedPack | Body:publicKey、packType、ledger | 创建用于打开已赠送/已购买包的签名挑战 |
| POST | /api/usePurchasedPack | Body:nonce、packType、publicKey、signature/transactionSignature、ledger | 签名后使用已购买的包,并返回 memo |
| GET | /api/getAllWinners | timestamp、slug、epic、packType、count | 最近的获胜者,支持可选筛选 |
| GET | /api/vrf/verify | memo | 验证一次 roll 的 VRF 证明 |
Gacha 响应格式
generatePack 响应:
{"memo": "slug-uuid", "transaction": "base64_encoded_transaction"}
memo 的格式为 cc-<uuid>(没有 API 密钥,因此不适用合作方 slug 前缀)。请求 Body 为 {playerAddress, packType?, turbo?, altPlayerAddress?}——packType 默认为 pokemon_50(传奇包使用 pokemon_250)。
openPack 响应(普通获胜):
{
"success": true,
"transactionSignature": "...",
"nft_address": "...",
"nftWon": {
"content": {
"metadata": {"name": "...", "description": "...", "attributes": []}
}
},
"points": 0,
"roll": 12345678,
"rarity": "Epic|Rare|Uncommon|Common"
}
roll 是范围为 1–100,000,000 的整数(不是小数)。nftWon 嵌套在 content.metadata 下——顶层没有 name/image。
**openPack 响应(turbo 模式回购,Common roll):**会添加 "code": "TURBO_MODE_BUYBACK" 和 "buybackAmount": 42500000"(USDC 基础单位)——Common NFT 会自动售出,而不是交付。
openPack 响应(付款尚未确认):
{"success": true, "code": "WAITING_FOR_WEBHOOK", "memo": "slug-uuid-string"}
不要根据此响应假设 NFT 已交付——轮询 GET /api/pack/status?memo=...(或重试 openPack),直到获胜结果确定。
**openPack 具有幂等性:**再次调用已打开的包时,会返回原始结果(相同的 transactionSignature、nftWon、points、rarity)——可以安全重试。
奖品等级映射(pack/status 和 getAllWinners 返回数字 prize_tier;openPack 返回易读的 rarity):1 = Epic,2 = Rare,3 = Uncommon,4 = Common。
buyback 响应:
{
"serializedTransaction": "base64",
"refundAmount": 42500000,
"memo": "..."
}
发货 / Vault 赎回
基础 URL:https://api.collectorcrypt.com
| 方法 | 端点 | 主要参数 | 描述 |
|---|---|---|---|
| POST | /redeem/estimate | 请求体:nftAddresses、shippingAddressId | 估算费用,不创建发货单;返回 price、insurancePrice、feesPrice、shippingPrice、total、numberOfCards、breakdown |
| POST | /redeem/prepare | 请求体:nftAddresses、shippingAddressId、coin(USDC|USDT)、deliveryCompany、comment、insurance | 创建待处理发货单,返回未签名交易 |
| POST | /blockchain/:outboundShipmentId/burn | 请求体:transactions(base64 签名)、evmTransactions | 广播已签名的销毁交易;返回 id、status、transactionUrls |
| GET | /outbound-shipment | — | 列出用户的发货单 |
| GET | /outbound-shipment/:id | id | 获取指定发货单的状态 |
发货地址管理
| 方法 | 端点 | 描述 |
|---|---|---|
| GET | /shipping-address | 列出已保存的地址 |
| GET | /shipping-address/:id | 获取指定地址 |
| POST | /shipping-address/create | 创建新地址 |
| PATCH | /shipping-address/update/:id | 更新地址 |
| DELETE | /shipping-address/:id | 删除地址 |
运费
| 地区 | 基础费用 | 每件附加费用 | 签收服务 | 包装附加费 |
|---|---|---|---|---|
| 美国 | $5.99 | $3.00 | +$3.00(价值 >= $500) | $0.18/包 |
| 加拿大 | $20.99 | $3.00 | 已包含 | $0.25/包 |
| 欧洲 | $29.99 | $3.00 | 已包含 | $0.25/包 |
| 澳大利亚/新西兰 | $34.99 | $3.00 | 已包含 | $0.25/包 |
| 世界其他地区 | $34.99 | $3.00 | 已包含 | $0.25/包 |
当包裹价值超过 $5,000 时,将自动按申报价值的 0.5% 购买保险。
Redeem/Prepare 响应结构
{
"outboundShipmentId": "shipment_...",
"transactions": ["<base64-unsigned-tx>"],
"evmTransactions": [],
"totalCost": 14.99,
"submitUrl": "/blockchain/shipment_.../burn",
"breakdown": {
"region": "USA",
"declaredValue": 700,
"numberOfCards": 10,
"lines": [
{"code": "shipping_base", "label": "Base shipping (USA, first card)", "amount": 5.99, "unitPrice": 5.99}
]
}
}
身份验证(SIWS — 使用 Solana 登录)
基础 URL:https://api.collectorcrypt.com
| 方法 | 端点 | 主要参数 | 描述 |
|---|---|---|---|
| POST | /auth/wallet/nonce | 请求体:wallet、partnerAppId、domain、uri | 获取 nonce 和 EIP-4361 签名消息 |
| POST | /auth/wallet/verify | 请求体:message、signature(base58 ed25519) | 使用签名换取访问令牌和刷新令牌 |
| POST | /auth/wallet/refresh | 请求体:refreshToken | 刷新已过期的访问令牌 |
| POST | /auth/wallet/logout | 请求体:refreshToken(以及 Authorization 标头中的访问令牌) | 使令牌失效 |
Swap 程序(链上)
程序 ID:CCSwaptcDXtfjyRMYBqavqBwiW162yXFAJrXN53UuENC
Swap 程序是一个基于 Anchor 的 Solana 智能合约。交易遵循以下生命周期:
Open → Approved → Executed → Settled → (Closed)
↑ ↑
cancel_trade cancel_trade
指令:
| 指令 | 描述 |
|---|---|
create_trade | 初始化两个钱包之间的交易 |
approve_trade | 表示已准备就绪(双方都必须批准) |
execute_trade | 确认执行交易(双方都必须执行) |
cancel_trade | 中止未完成或已批准的交易 |
execute_nft_batch | 将标准 NFT 转入或转出托管账户 |
execute_pnft_batch | 转移可编程 NFT |
execute_cnft_batch | 转移压缩 NFT |
execute_token_batch | 转移 SPL 代币 |
mark_trade_settled | 后端确认交易完成 |
close_trade | 最终清理并退还租金 |
市场链上详情
账户结构
| 账户 | 用途 |
|---|---|
| Market | 单例 PDA — 配置(管理员密钥、费用、金库、暂停状态) |
| Listing | 按资产 ID 和卖家索引的销售信息,包含委托权限 |
| Offer | 买家报价详情,由独立托管资金支持 |
| UserEscrow | 按用户跟踪用于报价抵押的 USDC 存款 |
费用结构
平台费用:200 个基点(2%)。可在 0–200 个基点范围内配置。
fee = floor(price * platform_fee_bps / 10000)
使用 u128 中间精度以防止溢出。
安全属性
- 非托管式上架 — NFT 通过委托保留在卖家钱包中,而不是通过托管转账
- 防止抢跑 —
expected_price参数会验证链上价格是否符合预期 - 禁止自我交易 — 强制执行
seller != buyer验证 - PDA 确定性 — 固定的种子方案可防止未经授权的账户替换
- 广播允许列表 — 提交前会根据已批准的程序 ID 验证交易
错误处理
任何 2xx 状态码都表示成功 — 200 和 201 都应接受。 多个市场写入端点(/marketplace/buy、/marketplace/broadcast)成功时会返回 201。不要以 status == 200 作为判断条件;应检查是否为 2xx 状态码,并确认存在 success: true、signature 或交易正文。
所有 API 均按标准格式返回错误:
{"statusCode": 400, "message": "human-readable error", "error": "Bad Request"}
| 状态码 | 含义 |
|---|---|
400 | 输入无效、链上失败、价格不匹配、托管资金不足、签名失败 |
401 | 令牌无效或已过期 |
403 | 访问被拒绝,程序 ID 不在广播允许列表中 |
404 | 未找到卡片、NFT、上架条目、报价或地址 |
409 | 冲突(已上架、所有者已更改、钱包已关联 Privy 账户) |
429 | 超出速率限制 |
500 | 机器为空、开启的卡包过多或处理错误 |
安全须知
- 市场价格以整数 USDC 计。
"price": 25表示 25.00 美元 USDC。 - 购买/广播成功时返回 HTTP
201— 接受任何 2xx 状态码,解析响应正文(可能是原始 base64,而非 JSON),并通过 Solana RPC(getSignatureStatuses)验证结果,而不是重新查询市场。请参阅端到端购买流程。 - Metaplex Core(
nftStandard: "core")很常见 — 对这类资产请省略tokenStandard;只有当资产确实属于对应类型时才发送"Pnft"/"Cnft"。 - Starchild 钱包签名会返回
signed_transaction(蛇形命名)— 广播前读取该字段(或其驼峰命名回退字段)。 - Gacha 的
refundAmount以 USDC lamports 为单位。 42,500,000 = 42.50 美元 USDC(1 USDC = 1,000,000 lamports)。 - Gacha 回购窗口为 72 小时。 超过此时间后,NFT 无法卖回给机器。
- 回购退款按每台机器的保险价值/市场价值百分比计算(而非购买价格)。该比例通过
GET /api/machines中的instantBuyback字段提供(例如,85= 85%);不要假设所有机器都采用固定比例。构建回购交易前,请使用GET /api/buyback/available?wallet=…&nft=…获取确切的退款amount(USDC 基本单位,已按机器回购比例调整,且上限为 40,000 USDC)。 - 非托管式上架 — NFT 通过委托保留在卖家钱包中。如果卖家转移 NFT 却未取消上架,该上架将失效。后端不保证自动取消。
- 更新报价前必须预先为托管账户注资 —
update-offer不会转入额外的 USDC;托管账户必须已包含新的全额资金。 - 接受 cNFT 报价可能需要两笔交易 — 如果 cNFT 当前已上架,API 会返回一笔必须先签名的取消上架交易。
- 发货会产生真实的实物配送。 调用
/redeem/prepare前,务必与用户确认地址和 NFT 选择。 - 签名后的交易不可撤销。 广播前请核实 NFT 地址、价格和钱包。
- VRF 抽取结果不可更改。 卡包开启后,结果无法更改或重新抽取。
- 路径 B(SIWS)仅支持加密货币。 不支持银行卡支付。已关联 Privy 账户的钱包会收到
409 Conflict。 userHasSol: false— 用户钱包缺少支付交易手续费的 SOL 时,请使用此标记;后端将代付 Gas。发生INSUFFICIENT_FUNDS_RETRYABLE广播错误时,也可使用此标记进行恢复。
已知限制
- 市场采用委托而非托管机制 — 如果卖家将 NFT 转移到其他地方但未取消挂单,挂单会悄无声息地失效。购买前务必检查挂单是否有效。
- 不同端点的字段名不一致 — 挂单使用
nftAddress,取消挂单使用tokenMint,更新挂单使用tokenMint+newPrice+coin。务必查看上文各端点对应的准确字段名。 - 扭蛋的
packType代码因机器而异(例如pokemon_50、pokemon_250)。使用GET /api/machines查询可用的包类型和当前价格。 - 无法按关键词搜索扭蛋 NFT — 使用带有
code和rarity筛选条件的GET /api/getNfts,或通过GET /api/machines浏览。 - Swap 仅支持链上操作 — 没有 REST API 封装;请通过 Solana 交易与 Anchor 程序 IDL 交互。
- 访问令牌会在 15 分钟后过期(Track B / SIWS)— 长会话需实现刷新令牌轮换。
- eBay Bidder 没有公开 API 文档 — 这是面向消费者的工具,地址为
https://bid.collectorcrypt.com。 - Launchpad 是由管理员管理的发售页面 — 没有用于创建或配置它们的公开 API。
- 浏览挂单缓存 — 未经身份验证的 GET 请求会缓存 5 秒。