collectorcrypt
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCollectorCrypt API
CollectorCrypt API
Bridge physical trading cards and blockchain — buy, sell, and trade collectible card NFTs on Solana, open mystery gacha packs, redeem NFTs for real cards, and swap assets peer-to-peer.
Marketplace Base URL:
Marketplace Devnet URL:
Gacha Base URL:
Gacha Devnet URL:
https://api.collectorcrypt.comhttps://dev-api.collectorcrypt.comhttps://gacha.collectorcrypt.comhttps://dev-gacha.collectorcrypt.com连接实体交易卡牌与区块链——在Solana上买卖、交易收藏卡牌NFT,开启神秘扭蛋卡包,将NFT兑换为实体卡牌,并进行点对点资产互换。
市场基础URL:
市场测试网URL:
扭蛋基础URL:
扭蛋测试网URL:
https://api.collectorcrypt.comhttps://dev-api.collectorcrypt.comhttps://gacha.collectorcrypt.comhttps://dev-gacha.collectorcrypt.comKey Concepts
核心概念
Product Suite
产品套件
- Marketplace — buy/sell/trade collectible card NFTs using USDC on Solana
- Gacha Machine — mystery pack system; spend USDC for randomized Pokemon card NFTs with VRF-verified fairness
- Vault — bridge NFTs ↔ physical cards; deposit real cards to mint NFTs, burn NFTs to ship physical cards
- Swap — peer-to-peer on-chain asset swaps via escrow (NFTs, pNFTs, cNFTs, SPL tokens)
- Launchpads — drop pages for minting new collectible releases
- Bidder — eBay bid automation; deposit funds, service bids and tokenizes won cards
- 交易市场 — 在Solana上使用USDC买卖/交易收藏卡牌NFT
- 扭蛋机 — 神秘卡包系统;花费USDC获取随机宝可梦卡牌NFT,通过VRF保证公平性
- 存管库 — 实现NFT与实体卡牌双向转换;存入实体卡牌铸造NFT,销毁NFT即可邮寄实体卡牌
- 互换 — 通过托管合约实现链上点对点资产互换(支持NFT、pNFT、cNFT、SPL代币)
- Launchpads — 新收藏系列铸造的发布页面
- Bidder — eBay竞价自动化工具;存入资金、服务竞价并将中标卡牌代币化
Solana Programs
Solana程序
| Program | ID |
|---|---|
| Marketplace | |
| Swap | |
| 程序 | ID |
|---|---|
| 交易市场 | |
| 互换 | |
NFT Types Supported
支持的NFT类型
- Programmable NFTs (pNFTs) — Metaplex standard with enforced royalties; use
tokenStandard: "Pnft" - Compressed NFTs (cNFTs) — Metaplex Bubblegum merkle-tree structure; use
tokenStandard: "Cnft" - Metaplex Core () — single-account standard; many live listings are Core (browse responses return
nftStandard: "core"). For Core listings, omit"nftStandard": "core"from buy/list/offer bodies — do NOT passtokenStandard/"Pnft". Only send"Cnft"when the asset is actually pNFT or cNFT.tokenStandard
- 可编程NFT(pNFTs) — Metaplex标准,强制版税;使用
tokenStandard: "Pnft" - 压缩NFT(cNFTs) — Metaplex Bubblegum默克尔树结构;使用
tokenStandard: "Cnft" - Metaplex核心版() — 单账户标准;当前许多在售列表为核心版(浏览接口返回
nftStandard: "core")。对于核心版列表,在购买/挂单/出价请求体中省略"nftStandard": "core"——请勿传入tokenStandard/"Pnft"。仅当资产确实是pNFT或cNFT时才传入"Cnft"。tokenStandard
Currency
货币
All marketplace and gacha transactions use USDC (SPL Token) on Solana. Shipping fees accept USDC or USDT. Gas fees paid in SOL.
Marketplace prices are in whole USDC (e.g., means $25.00 USDC).
"price": 25所有市场和扭蛋交易均使用Solana上的USDC(SPL代币)。运费支持USDC或USDT支付。Gas费以SOL支付。
市场价格为整数USDC(例如:代表25.00 USDC)。
"price": 25Transaction Pattern (Marketplace & Shipping)
交易流程(市场与物流)
Three-step flow:
- Build — POST to API endpoint, receive base64-encoded unsigned transaction(s)
- Sign — Sign with the Solana wallet (Phantom/Solflare, or the Starchild wallet helper — see below)
- Broadcast — POST signed transaction to
/marketplace/broadcast
HTTP status — accept BOTH and as success. Verified live: and return , not . Treat any 2xx as success; do not hard-check .
200201/marketplace/buy/marketplace/broadcast201200== 200Response body may be raw base64 text, NOT JSON. with can return the unsigned transaction as a plain-text body. Parse defensively:
/marketplace/buyfundingSource: "wallet"python
text = response.text
try:
data = response.json()
tx = data.get("transaction") or data.get("serializedTransaction")
except Exception:
tx = text # body was the raw base64 transactionStarchild wallet signing returns snake_case . When signing with the platform wallet:
signed_transactionpython
from core.skill_tools import wallet
signed = wallet.wallet_sol_sign_transaction(unsigned_tx)三步流程:
- 构建 — 向API端点发送POST请求,获取Base64编码的未签名交易
- 签名 — 使用Solana钱包(Phantom/Solflare,或Starchild钱包工具——见下文)签名
- 广播 — 将签名后的交易POST至
/marketplace/broadcast
HTTP状态码——和均视为成功。 实测:和返回****而非。将所有2xx状态码视为成功;不要硬校验。
200201/marketplace/buy/marketplace/broadcast201200== 200响应体可能是原始Base64文本,而非JSON。 当时,可能直接返回未签名交易的纯文本内容。需做容错解析:
fundingSource: "wallet"/marketplace/buypython
text = response.text
try:
data = response.json()
tx = data.get("transaction") or data.get("serializedTransaction")
except Exception:
tx = text # 响应体为原始Base64交易数据Starchild钱包签名返回蛇形命名的。 使用平台钱包签名时:
signed_transactionpython
from core.skill_tools import wallet
signed = wallet.wallet_sol_sign_transaction(unsigned_tx)→ {"signed_transaction": "<base64>", "encoding": "base64"}
→ {"signed_transaction": "<base64>", "encoding": "base64"}
signed_tx = signed.get("signed_transaction") or signed.get("signedTransaction")
Look for `signed_transaction` first, then the camelCase variant. Feed `signed_tx` into `/marketplace/broadcast` as the `signedTransaction` field.signed_tx = signed.get("signed_transaction") or signed.get("signedTransaction")
优先读取`signed_transaction`,再尝试驼峰命名的备选字段。将`signed_tx`作为`signedTransaction`字段传入`/marketplace/broadcast`。Gacha Rarity Tiers
扭蛋稀有度等级
| Rarity | Probability |
|---|---|
| Epic | 1% |
| Rare (High) | 4% |
| Uncommon (Mid) | 15% |
| Common (Low) | 80% |
| 稀有度 | 概率 |
|---|---|
| Epic(史诗) | 1% |
| Rare(高稀有) | 4% |
| Uncommon(中稀有) | 15% |
| Common(普通) | 80% |
VRF (Verifiable Random Function)
VRF(可验证随机函数)
Gacha rolls use a Verifiable Random Function for tamper-proof, provably-fair results. Selection is two-stage:
- Roll → tier: a uniform integer roll in the range 1–100,000,000, seeded by the player's own wallet signature on the open transaction, maps to a rarity tier via the machine's configured weights (see in
tierRanges)./api/machines - Card → within tier: a provable selection picks the specific NFT inside that tier.
The seed (wallet signature) and result are committed to Solana in the award transaction's on-chain memo, preventing prediction or manipulation. Verify independently:
- — returns the proof, public key, transaction signature, and whether the stored roll matches the recomputed roll.
GET /api/vrf/verify?memo=YOUR_MEMO - — browser-side replay of the card selection against the on-chain memo.
/verify-selection/YOUR_MEMO
The docs do not name a specific VRF algorithm; don't assert one.
扭蛋抽取使用可验证随机函数,确保结果防篡改、可证明公平。选择分为两个阶段:
- 抽取→等级: 生成一个范围在1–100,000,000的均匀整数,以玩家在开启交易时的钱包签名作为种子,通过机器配置的权重映射到对应稀有度等级(详见中的
/api/machines)。tierRanges - 卡牌→等级内: 通过可证明的选择逻辑从对应等级中挑选具体NFT。
种子(钱包签名)和结果会被记录在Solana奖励交易的链上备注中,防止预测或操纵。可独立验证:
- — 返回证明、公钥、交易签名,以及存储的抽取结果是否与重新计算的结果匹配。
GET /api/vrf/verify?memo=YOUR_MEMO - — 基于链上备注在浏览器端重放卡牌选择过程。
/verify-selection/YOUR_MEMO
文档未指定具体VRF算法,请勿断言某一算法。
How to Call
调用方式
Gacha API — No API Key (the key does not exist)
扭蛋API——无API密钥(不存在密钥系统)
There is no API key. Do not set , do not send an header, and do not try to obtain a key — the CollectorCrypt team has confirmed no key system exists. Every gacha endpoint, reads and writes alike, is called with no authentication.
CC_API_KEYx-api-keybash
undefined不存在API密钥。请勿设置,不要发送请求头,也无需尝试获取密钥——CollectorCrypt团队已确认无密钥系统。 所有扭蛋端点,无论读写,均无需认证即可调用。
CC_API_KEYx-api-keybash
undefinedReads 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"}'
-H "Content-Type: application/json"
-d '{"playerAddress":"WALLET_PUBKEY"}'
> **Ignore the docs' authentication section.** The public docs say *"Each request must include a valid `x-api-key` header"* and reference a partner "slug." That does not reflect reality — confirmed both by the team (no key system exists) and by live testing (`/api/generatePack` returns `200` with no header). There is nothing to request and no header to add.
Without a key, generated transactions carry a `cc-<uuid>` memo. Security comes from the **wallet signature**, not from any API credential — nothing executes until the user signs the transaction this API hands back.
Reference implementation: **Gacha Starter Demo** — https://github.com/daxherrera/gacha-starter (full pack → sign → submit → open flow). Try every call live on devnet at `https://dev-gacha.collectorcrypt.com` (fund a devnet wallet via the USDC faucet: https://spl-token-faucet.com/?token-name=USDC-Dev).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"}'
-H "Content-Type: application/json"
-d '{"playerAddress":"WALLET_PUBKEY"}'
> **忽略文档中的认证章节。** 公开文档提到*“每个请求必须包含有效的`x-api-key`请求头”*并引用合作伙伴“slug”。但这与实际情况不符——团队已确认无密钥系统,且实测`/api/generatePack`无需请求头即可返回`200`。无需申请密钥,也无需添加任何请求头。
无密钥情况下,生成的交易带有`cc-<uuid>`格式的备注。安全性依赖于**钱包签名**,而非API凭证——只有用户签名API返回的交易后,操作才会执行。
参考实现:**扭蛋入门Demo** — https://github.com/daxherrera/gacha-starter(完整的卡包→签名→提交→开启流程)。可在测试网`https://dev-gacha.collectorcrypt.com`上实测所有调用(通过USDC水龙头为测试网钱包充值:https://spl-token-faucet.com/?token-name=USDC-Dev)。Marketplace API — No Auth for Reads
交易市场API——读请求无需认证
Public GET endpoints (browse listings) need no authentication. Write endpoints return unsigned transactions for wallet signing — no API key involved.
bash
undefined公开GET端点(浏览列表)无需认证。写端点返回未签名交易供钱包签名——无需API密钥。
bash
undefinedBrowse listings — no auth, 5s cache for unauthenticated requests
浏览列表——无需认证,未认证请求有5秒缓存
Create listing — returns base64 unsigned transaction
创建挂单——返回Base64编码的未签名交易
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 }'
-H "Content-Type: application/json"
-d '{ "wallet": "YOUR_SOLANA_ADDRESS", "cardId": "CC_CARD_DB_ID", "nftAddress": "NFT_MINT_ADDRESS", "currency": "USDC", "price": 50 }'
undefinedcurl -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 }'
-H "Content-Type: application/json"
-d '{ "wallet": "YOUR_SOLANA_ADDRESS", "cardId": "CC_CARD_DB_ID", "nftAddress": "NFT_MINT_ADDRESS", "currency": "USDC", "price": 50 }'
undefinedShipping API — Two Auth Tracks
物流API——两种认证方式
Track A — Privy Identity Token:
Authorization: Bearer <privy-identity-token>Track B — Sign-In With Solana (SIWS):
- — get nonce + message to sign
POST /auth/wallet/nonce - Sign message with wallet (ed25519, base58)
- — exchange signature for access/refresh tokens
POST /auth/wallet/verify
bash
undefined方式A——Privy身份令牌:
Authorization: Bearer <privy-identity-token>方式B——Solana登录(SIWS):
- — 获取随机数+待签名消息
POST /auth/wallet/nonce - 使用钱包签名消息(ed25519,base58编码)
- — 用签名换取访问/刷新令牌
POST /auth/wallet/verify
bash
undefinedStep 1: Get nonce
步骤1:获取随机数
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"}'
-H "Content-Type: application/json"
-d '{"wallet": "YOUR_PUBKEY", "partnerAppId": "your-slug", "domain": "your-app.com", "uri": "https://your-app.com"}'
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"}'
-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
步骤3:验证并获取令牌
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>"}'
-H "Content-Type: application/json"
-d '{"message": "<message-from-nonce>", "signature": "<base58-ed25519-signature>"}'
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>"}'
-H "Content-Type: application/json"
-d '{"message": "<message-from-nonce>", "signature": "<base58-ed25519-signature>"}'
Returns: {"accessToken": "cca_...", "refreshToken": "ccr_...", "expiresAt": ...}
返回:{"accessToken": "cca_...", "refreshToken": "ccr_...", "expiresAt": ...}
**Token management:**
- Access token lifetime: 15 minutes
- Refresh: `POST /auth/wallet/refresh` with `{"refreshToken": "..."}`
- Logout: `POST /auth/wallet/logout`
- Track B limitation: crypto payment only (no card payments), Solana signatures only
**令牌管理:**
- 访问令牌有效期:15分钟
- 刷新令牌:`POST /auth/wallet/refresh`,传入`{"refreshToken": "..."}`
- 登出:`POST /auth/wallet/logout`
- 方式B限制:仅支持加密货币支付(不支持银行卡支付),仅支持Solana签名Intent Routing
意图路由
Marketplace
交易市场
Base:
https://api.collectorcrypt.comAll POST endpoints return base64-encoded unsigned Solana transaction(s). Sign with wallet, then broadcast via .
/marketplace/broadcast基础URL:
https://api.collectorcrypt.com所有POST端点返回Base64编码的未签名Solana交易。使用钱包签名后,通过广播。
/marketplace/broadcastList an NFT — POST /marketplace/list
POST /marketplace/list挂单NFT — POST /marketplace/list
POST /marketplace/list| Field | Type | Required | Description |
|---|---|---|---|
| string | yes | Seller's Solana address |
| string | yes | CollectorCrypt card DB ID |
| string | yes | NFT mint address |
| string | yes | |
| number | yes | Listing price in USDC |
| enum | no | |
| boolean | no | If |
Errors: (on-chain error), (already listed)
400409| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
| string | 是 | 卖家的Solana地址 |
| string | 是 | CollectorCrypt卡牌数据库ID |
| string | 是 | NFT铸造地址 |
| string | 是 | |
| number | 是 | 挂单价格(USDC) |
| enum | 否 | |
| boolean | 否 | 若为 |
错误码:(链上错误)、(已挂单)
400409Cancel a Listing — POST /marketplace/cancel-listing
POST /marketplace/cancel-listing取消挂单 — POST /marketplace/cancel-listing
POST /marketplace/cancel-listing| Field | Type | Required | Description |
|---|---|---|---|
| string | yes | Caller's wallet |
| string | yes | NFT mint address |
| string | no | Defaults to |
Errors: (on-chain error), (no listing found)
400404| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
| string | 是 | 调用者钱包地址 |
| string | 是 | NFT铸造地址 |
| string | 否 | 默认值为 |
错误码:(链上错误)、(未找到挂单)
400404Update a Listing Price — POST /marketplace/update-listing
POST /marketplace/update-listing更新挂单价格 — POST /marketplace/update-listing
POST /marketplace/update-listing| Field | Type | Required | Description |
|---|---|---|---|
| string | yes | Seller's wallet |
| string | yes | NFT mint address |
| number | yes | Updated price in USDC |
| string | yes | |
Errors: (price unchanged or on-chain error), (no listing found)
400404| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
| string | 是 | 卖家钱包地址 |
| string | 是 | NFT铸造地址 |
| number | 是 | 更新后的价格(USDC) |
| string | 是 | |
错误码:(价格未变更或链上错误)、(未找到挂单)
400404Buy an NFT — POST /marketplace/buy
POST /marketplace/buy购买NFT — POST /marketplace/buy
POST /marketplace/buy| Field | Type | Required | Description |
|---|---|---|---|
| string | yes | Buyer's wallet |
| string | yes | NFT mint address |
| number | yes | Listed price in USDC |
| string | yes | |
| enum | no | |
| string | no | Resolved from DB if omitted |
| enum | no | |
Success status is OR (live buys return ). Response body may be raw base64 text rather than JSON — parse defensively (see Transaction Pattern above).
200201201- → single base64 unsigned transaction (JSON
fundingSource: "wallet"or plain base64 text){"transaction": "..."} - →
fundingSource: "escrow"{"transactions": ["BASE64_WITHDRAW_TX", "BASE64_BUY_TX"], "fundingSource": "escrow"}
Escrow requires minimum USDC balance.
price × 1.02Errors: (on-chain error, insufficient escrow), (card/listing not found), (owner changed)
400404409| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
| string | 是 | 买家钱包地址 |
| string | 是 | NFT铸造地址 |
| number | 是 | 挂单价格(USDC) |
| string | 是 | |
| enum | 否 | |
| string | 否 | 若省略则从数据库解析 |
| enum | 否 | |
成功状态码为或(实测购买返回)。响应体可能是原始Base64文本而非JSON——需做容错解析(见上文交易流程)。
200201201- → 单个Base64未签名交易(JSON格式
fundingSource: "wallet"或纯Base64文本){"transaction": "..."} - →
fundingSource: "escrow"{"transactions": ["BASE64_WITHDRAW_TX", "BASE64_BUY_TX"], "fundingSource": "escrow"}
托管账户需至少有数量的USDC余额。
price × 1.02错误码:(链上错误、托管余额不足)、(未找到卡牌/挂单)、(所有者变更)
400404409End-to-End Buy Recipe (tested live)
完整购买流程(已实测)
python
import requests
from core.skill_tools import wallet
BASE = "https://api.collectorcrypt.com"
buyer = "YOUR_WALLET_PUBKEY"python
import requests
from core.skill_tools import wallet
BASE = "https://api.collectorcrypt.com"
buyer = "YOUR_WALLET_PUBKEY"1. Find a listed item, cheapest first
1. 找到在售商品,按价格从低到高排序
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"
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.
2. 构建购买交易。核心版列表省略tokenStandard。
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
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) # 购买返回201
try: unsigned = r.json().get("transaction") or r.json().get("serializedTransaction")
except Exception: unsigned = r.text # 可能为原始Base64文本
3. Sign with Starchild wallet (snake_case key)
3. 使用Starchild钱包签名(蛇形命名字段)
signed = wallet.wallet_sol_sign_transaction(unsigned)
signed_tx = signed.get("signed_transaction") or signed.get("signedTransaction")
signed = wallet.wallet_sol_sign_transaction(unsigned)
signed_tx = signed.get("signed_transaction") or signed.get("signedTransaction")
4. Broadcast
4. 广播交易
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"]
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") # 广播返回201
sig = b.json()["signature"]
5. Verify on Solana RPC — the SOURCE OF TRUTH (see below)
5. 通过Solana RPC验证——权威验证方式(见下文)
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"
**Verify via Solana RPC signature status, not a marketplace refetch.** Marketplace metadata refresh lags after a buy, and there is no `nftAddress` lookup filter (`search=<mint>` is fuzzy and may not reflect the new owner immediately). The authoritative post-broadcast check is `getSignatureStatuses` on the broadcast `signature`:
```json
{"confirmationStatus": "finalized", "err": null, "status": {"Ok": null}}err == nullconfirmationStatusconfirmedfinalizedRegression fixture — a real buy that succeeded (use to smoke-test the flow):
| Field | Value |
|---|---|
| Item | 2017 #024 POKE BALL PSA 9 — Pokémon Japanese Sun & Moon, Ash vs. Team Rocket Deck Kit |
| Price | 19 USDC |
| NFT mint | |
| Seller | |
| Broadcast signature | |
| Solana status | |
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>`为模糊查询,可能无法立即反映新所有者)。广播后的权威验证方式是调用`getSignatureStatuses`查询广播的`signature`:
```json
{"confirmationStatus": "finalized", "err": null, "status": {"Ok": null}}err == nullconfirmationStatusconfirmedfinalized回归测试示例——已成功的真实购买(用于流程冒烟测试):
| 字段 | 值 |
|---|---|
| 商品 | 2017 #024 POKE BALL PSA 9 — 宝可梦日文日月系列,小智vs火箭队卡组套装 |
| 价格 | 19 USDC |
| NFT铸造地址 | |
| 卖家 | |
| 广播签名 | |
| Solana状态 | |
Make an Offer — POST /marketplace/make-offer
POST /marketplace/make-offer发起出价 — POST /marketplace/make-offer
POST /marketplace/make-offer| Field | Type | Required | Description |
|---|---|---|---|
| string | yes | Buyer's wallet |
| string | yes | CollectorCrypt card DB ID |
| string | yes | NFT mint address |
| number | yes | Offer price in USDC |
| string | yes | |
| enum | no | |
| boolean | no | Backend fee payer if |
| string | no | Current NFT owner |
| string | no | cNFT collection hash |
Errors: (can't determine owner or on-chain error)
400| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
| string | 是 | 买家钱包地址 |
| string | 是 | CollectorCrypt卡牌数据库ID |
| string | 是 | NFT铸造地址 |
| number | 是 | 出价金额(USDC) |
| string | 是 | |
| enum | 否 | |
| boolean | 否 | 若为 |
| string | 否 | 当前NFT所有者 |
| string | 否 | cNFT集合哈希 |
错误码:(无法确定所有者或链上错误)
400Cancel an Offer — POST /marketplace/cancel-offer
POST /marketplace/cancel-offer取消出价 — POST /marketplace/cancel-offer
POST /marketplace/cancel-offer| Field | Type | Required | Description |
|---|---|---|---|
| string | yes | Buyer's wallet |
| string | yes | NFT mint address |
| boolean | no | If |
Backend auto-sets if wallet has insufficient SOL for rent.
keepInEscrow: trueErrors: (no active offer found)
404| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
| string | 是 | 买家钱包地址 |
| string | 是 | NFT铸造地址 |
| boolean | 否 | 若为 |
若钱包余额不足以支付租金,后端会自动设置。
keepInEscrow: true错误码:(未找到有效出价)
404Update an Offer — POST /marketplace/update-offer
POST /marketplace/update-offer更新出价 — POST /marketplace/update-offer
POST /marketplace/update-offer| Field | Type | Required | Description |
|---|---|---|---|
| string | yes | Buyer's wallet (signer) |
| string | yes | NFT mint address |
| string | yes | |
| string | yes | Buyer's wallet (typically = |
| number | yes | New offer price in USDC |
Important: Escrow must already contain the full new amount — this instruction does NOT transfer additional USDC.
Errors: (price unchanged, no escrow, insufficient balance, on-chain error), (offer not found)
400404| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
| string | 是 | 买家钱包地址(签名者) |
| string | 是 | NFT铸造地址 |
| string | 是 | |
| string | 是 | 买家钱包地址(通常与 |
| number | 是 | 更新后的出价金额(USDC) |
注意: 托管账户必须已存入足额的新出价金额——此接口不会额外转入USDC。
错误码:(价格未变更、无托管账户、余额不足、链上错误)、(未找到出价)
400404Accept an Offer — POST /marketplace/accept-offer
POST /marketplace/accept-offer接受出价 — POST /marketplace/accept-offer
POST /marketplace/accept-offer| Field | Type | Required | Description |
|---|---|---|---|
| string | yes | Seller's wallet (NFT owner) |
| string | yes | NFT mint address |
| string | yes | Buyer's wallet |
| string | yes | |
| number | yes | Offer price in USDC |
| enum | no | |
| boolean | no | Backend fee payer if |
cNFT edge case: If the cNFT is currently listed, returns:
json
{
"requiresCancelListing": true,
"cancelListingTx": "BASE64_CANCEL_LISTING_TX",
"message": "This cNFT is currently listed. Please sign..."
}Sign the cancel-listing tx first, then re-call accept-offer.
Errors: (price drift, on-chain error), (offer not found)
400404| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
| string | 是 | 卖家钱包地址(NFT所有者) |
| string | 是 | NFT铸造地址 |
| string | 是 | 买家钱包地址 |
| string | 是 | |
| number | 是 | 出价金额(USDC) |
| enum | 否 | |
| boolean | 否 | 若为 |
cNFT特殊情况: 若cNFT当前处于挂单状态,返回:
json
{
"requiresCancelListing": true,
"cancelListingTx": "BASE64_CANCEL_LISTING_TX",
"message": "此cNFT当前处于挂单状态,请先签名取消挂单交易..."
}先签名取消挂单交易,再重新调用接受出价接口。
错误码:(价格变动、链上错误)、(未找到出价)
400404Browse Listings — GET /marketplace
GET /marketplace浏览挂单 — GET /marketplace
GET /marketplacePublic, no auth required. 5-second cache for unauthenticated requests.
Pagination:
| Param | Type | Default | Description |
|---|---|---|---|
| integer | 1 | 1-indexed page |
| integer | 100 | Page size (max 100) |
Filters (all optional):
| Param | Type | Description |
|---|---|---|
| string | Substring match against itemName, nftAddress, gemrateCardName, gradingID. This is the only way to look up by mint — there is NO |
| string | Filter by owner wallet |
| boolean | Hide caller's own cards (requires auth) |
| boolean | Only favorited cards (requires auth) |
| boolean | Only from followed users (requires auth) |
| string | Cards owned by users that this wallet follows |
| CSV | |
| CSV | |
| CSV | Global tag names (e.g., |
| number | USDC price range |
| number | Insured value range |
| integer | Card year range |
| CSV | |
| CSV | |
| CSV | |
| boolean | Only authenticated cards |
| boolean | Only autographed cards |
| boolean | Include burned cards (default excludes) |
| string | Substring match |
| number | Numeric grade range |
| CSV | |
| string | Substring match for sealed/comic metadata |
| string | Word-boundary match against gemrateCardName |
| boolean | Only cards with active CC buyback |
| string | Gemrate-specific filters |
Sort — values:
, , , , , (insured value), , , , , ,
Default:
orderBydateAscdateDescnameAscnameDescpriceAscpriceDescyearAscyearDesclistedDateAsclistedDateDesclistedPriceAsclistedPriceDesclistedDateDescResponse:
json
{
"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}
}- is
listingwhen unlistednull - is array of active offer IDs
offers - = total matching filter;
findTotal= total marketplace cards overalltotal - = per-category count (excludes
cardsQtyByCategoryfilter)categories
公开接口,无需认证。未认证请求有5秒缓存。
分页参数:
| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
| integer | 1 | 从1开始的页码 |
| integer | 100 | 每页数量(最大100) |
过滤参数(均为可选):
| 参数 | 类型 | 描述 |
|---|---|---|
| string | 匹配itemName、nftAddress、gemrateCardName、gradingID的子串。这是唯一通过铸造地址查询的方式——无 |
| string | 按所有者钱包地址过滤 |
| boolean | 隐藏调用者自己的卡牌(需认证) |
| boolean | 仅显示收藏的卡牌(需认证) |
| boolean | 仅显示关注用户的卡牌(需认证) |
| string | 此钱包关注用户所拥有的卡牌 |
| CSV | |
| CSV | |
| CSV | 全局标签名称(例如: |
| number | USDC价格范围 |
| number | 保险价值范围 |
| integer | 卡牌年份范围 |
| CSV | |
| CSV | |
| CSV | |
| boolean | 仅显示已认证卡牌 |
| boolean | 仅显示签名卡牌 |
| boolean | 包含已销毁卡牌(默认排除) |
| string | 匹配等级子串 |
| number | 数值等级范围 |
| CSV | |
| string | 匹配密封/漫画元数据的子串 |
| string | 匹配gemrateCardName的词边界 |
| boolean | 仅显示有CC回购活动的卡牌 |
| string | Gemrate专属过滤参数 |
排序参数——可选值:
、、、、、(保险价值)、、、、、、
默认值:
orderBydateAscdateDescnameAscnameDescpriceAscpriceDescyearAscyearDesclistedDateAsclistedDateDesclistedPriceAsclistedPriceDesclistedDateDesc响应格式:
json
{
"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}
}- 未挂单时为
listingnull - 为有效出价ID数组
offers - = 匹配过滤条件的总数;
findTotal= 市场所有卡牌总数total - = 各分类卡牌数量(排除
cardsQtyByCategory过滤条件)categories
Broadcast a Transaction — POST /marketplace/broadcast
POST /marketplace/broadcast广播交易 — POST /marketplace/broadcast
POST /marketplace/broadcast| Field | Type | Required | Description |
|---|---|---|---|
| string | yes | Signer wallet address |
| string | yes | Base64-encoded signed transaction |
| string | no | Triggers metadata refresh after 5s |
Success status is OR (live broadcasts return ). Response:
200201201json
{
"success": true,
"signature": "SOLANA_TRANSACTION_SIGNATURE",
"message": "Transaction broadcast successfully"
}Don't treat the as a failure — check / presence of , not the status code.
201success === truesignatureInsufficient funds recovery: If broadcast returns with , rebuild the original transaction with so the backend pays fees, then re-sign and re-broadcast.
400"code": "INSUFFICIENT_FUNDS_RETRYABLE"userHasSol: falseValidation: Transaction is validated against an allow-list of program IDs before submission.
Errors: (invalid transaction, insufficient funds retryable, submission failure), (program ID not on allow-list)
400403| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
| string | 是 | 签名者钱包地址 |
| string | 是 | Base64编码的签名交易 |
| string | 否 | 触发5秒后的元数据刷新 |
成功状态码为或(实测广播返回)。响应格式:
200201201json
{
"success": true,
"signature": "SOLANA_TRANSACTION_SIGNATURE",
"message": "交易广播成功"
}请勿将视为失败——检查 / 是否存在 / 是否有交易体,而非状态码。
201success === truesignature余额不足恢复: 若广播返回且包含,请重新构建原始交易并设置,由后端支付手续费,然后重新签名并广播。
400"code": "INSUFFICIENT_FUNDS_RETRYABLE"userHasSol: false验证: 交易在提交前会针对允许的程序ID列表进行验证。
错误码:(无效交易、可重试的余额不足、提交失败)、(程序ID不在允许列表中)
400403Gacha Machine
扭蛋机
Base:
https://gacha.collectorcrypt.com| Method | Endpoint | Primary Params | Description |
|---|---|---|---|
| GET | | — | Machine operational status (open/closed) |
| GET | | — | NFT inventory counts by rarity per machine |
| GET | | — | Full config for all machines: pricing, |
| GET | | | Available NFTs with filtering |
| POST | | Body: | Create purchase transaction for one pack |
| POST | | Body: | Batch purchase multiple packs |
| POST | | Body: | Open purchased pack, receive NFT |
| POST | | Body: | Sell NFT back for USDC (within 72 hours) |
| GET | | | Check buyback completion status |
| GET | | | Pre-check NFT buyback eligibility + refund |
| GET | | | Full pack lifecycle: purchase, NFT send (incl. |
| POST | | Body: | Submit signed transaction to Solana |
| POST | | Body: | Gift packs to another wallet |
| GET | | | Gift history (sent/received) |
| GET | | | Pack counts by type (purchased vs gifted, used vs unused) |
| POST | | Body: | Create sign challenge for opening gifted/purchased packs |
| POST | | Body: | Consume purchased pack after signing, returns memo |
| GET | | | Recent winners with optional filtering |
| GET | | | Verify VRF proof for a roll |
基础URL:
https://gacha.collectorcrypt.com| 方法 | 端点 | 主要参数 | 描述 |
|---|---|---|---|
| GET | | — | 机器运行状态(开启/关闭) |
| GET | | — | 各稀有度NFT的库存数量 |
| GET | | — | 所有机器的完整配置:定价、 |
| GET | | | 可筛选的可用NFT列表 |
| POST | | 请求体: | 创建单包购买交易 |
| POST | | 请求体: | 批量购买多包 |
| POST | | 请求体: | 开启已购买的卡包,获取NFT |
| POST | | 请求体: | 将NFT卖回换取USDC(72小时内有效) |
| GET | | | 检查回购完成状态 |
| GET | | | 预检查NFT回购资格+退款金额(构建回购交易前) |
| GET | | | 卡包全生命周期:购买、NFT发放(包含 |
| POST | | 请求体: | 将签名交易提交至Solana |
| POST | | 请求体: | 向其他钱包赠送卡包 |
| GET | | | 赠送历史(发送/接收) |
| GET | | | 卡包数量统计(购买/赠送、已使用/未使用) |
| POST | | 请求体: | 为开启赠送/购买的卡包创建签名挑战 |
| POST | | 请求体: | 签名后使用已购买的卡包,返回备注 |
| GET | | | 近期中奖记录(可筛选) |
| GET | | | 验证抽取的VRF证明 |
Gacha Response Shapes
扭蛋响应格式
generatePack response:
json
{"memo": "slug-uuid", "transaction": "base64_encoded_transaction"}The is (there is no API key, so no partner slug prefix applies). Body is — defaults to (use for legendary).
memocc-<uuid>{playerAddress, packType?, turbo?, altPlayerAddress?}packTypepokemon_50pokemon_250openPack response (normal win):
json
{
"success": true,
"transactionSignature": "...",
"nft_address": "...",
"nftWon": {
"content": {
"metadata": {"name": "...", "description": "...", "attributes": []}
}
},
"points": 0,
"roll": 12345678,
"rarity": "Epic|Rare|Uncommon|Common"
}rollnftWoncontent.metadatanameimageopenPack response (turbo-mode buyback, Common roll): adds and (USDC base units) — the Common NFT is auto-sold instead of delivered.
"code": "TURBO_MODE_BUYBACK""buybackAmount": 42500000openPack response (payment not yet confirmed):
json
{"success": true, "code": "WAITING_FOR_WEBHOOK", "memo": "slug-uuid-string"}Do NOT assume an NFT was delivered on this response — poll (or retry ) until the win resolves.
GET /api/pack/status?memo=...openPackopenPack is idempotent: calling it again on an already-opened pack returns the original result (same , , , ) — safe to retry.
transactionSignaturenftWonpointsrarityPrize tier mapping ( and return numeric ; returns human-readable ): = Epic, = Rare, = Uncommon, = Common.
pack/statusgetAllWinnersprize_tieropenPackrarity1234buyback response:
json
{
"serializedTransaction": "base64",
"refundAmount": 42500000,
"memo": "..."
}generatePack响应:
json
{"memo": "slug-uuid", "transaction": "base64_encoded_transaction"}memocc-<uuid>{playerAddress, packType?, turbo?, altPlayerAddress?}packTypepokemon_50pokemon_250openPack响应(普通中奖):
json
{
"success": true,
"transactionSignature": "...",
"nft_address": "...",
"nftWon": {
"content": {
"metadata": {"name": "...", "description": "...", "attributes": []}
}
},
"points": 0,
"roll": 12345678,
"rarity": "Epic|Rare|Uncommon|Common"
}rollnftWoncontent.metadatanameimageopenPack响应( turbo模式回购,普通稀有度): 新增和(USDC最小单位)——普通NFT会自动卖出而非发放给用户。
"code": "TURBO_MODE_BUYBACK""buybackAmount": 42500000openPack响应(支付未确认):
json
{"success": true, "code": "WAITING_FOR_WEBHOOK", "memo": "slug-uuid-string"}收到此响应时请勿默认已发放NFT——轮询(或重试)直到中奖结果确定。
GET /api/pack/status?memo=...openPackopenPack接口是幂等的: 对已开启的卡包再次调用会返回原始结果(相同的、、、)——可安全重试。
transactionSignaturenftWonpointsrarity奖励等级映射(和返回数字;返回可读的): = Epic(史诗), = Rare(稀有), = Uncommon(中稀有), = Common(普通)。
pack/statusgetAllWinnersprize_tieropenPackrarity1234buyback响应:
json
{
"serializedTransaction": "base64",
"refundAmount": 42500000,
"memo": "..."
}Shipping / Vault Redemption
物流/存管兑换
Base:
https://api.collectorcrypt.com| Method | Endpoint | Primary Params | Description |
|---|---|---|---|
| POST | | Body: | Fee estimate without creating shipment; returns |
| POST | | Body: | Create pending shipment, returns unsigned transactions |
| POST | | Body: | Broadcast signed burn transactions; returns |
| GET | | — | List user shipments |
| GET | | | Get specific shipment status |
基础URL:
https://api.collectorcrypt.com| 方法 | 端点 | 主要参数 | 描述 |
|---|---|---|---|
| POST | | 请求体: | 估算费用(不创建运单);返回 |
| POST | | 请求体: | 创建待处理运单,返回未签名交易 |
| POST | | 请求体: | 广播签名的销毁交易;返回 |
| GET | | — | 列出用户运单 |
| GET | | | 获取指定运单状态 |
Shipping Address Management
收货地址管理
| Method | Endpoint | Description |
|---|---|---|
| GET | | List saved addresses |
| GET | | Get specific address |
| POST | | Create new address |
| PATCH | | Update address |
| DELETE | | Delete address |
| 方法 | 端点 | 描述 |
|---|---|---|
| GET | | 列出已保存的地址 |
| GET | | 获取指定地址 |
| POST | | 创建新地址 |
| PATCH | | 更新地址 |
| DELETE | | 删除地址 |
Shipping Rates
运费标准
| Region | Base | Each Additional | Signature | Pack Surcharge |
|---|---|---|---|---|
| USA | $5.99 | $3.00 | +$3.00 (value >= $500) | $0.18/pack |
| Canada | $20.99 | $3.00 | Included | $0.25/pack |
| Europe | $29.99 | $3.00 | Included | $0.25/pack |
| Australia/NZ | $34.99 | $3.00 | Included | $0.25/pack |
| Rest of World | $34.99 | $3.00 | Included | $0.25/pack |
Insurance auto-applies at 0.5% of declared value when package exceeds $5,000.
| 地区 | 基础运费 | 额外每张 | 签名费 | 包装附加费 |
|---|---|---|---|---|
| 美国 | $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 Response Shape
Redeem/Prepare响应格式
json
{
"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}
]
}
}json
{
"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": "基础运费(美国,首张卡牌)", "amount": 5.99, "unitPrice": 5.99}
]
}
}Auth (SIWS — Sign-In With Solana)
认证(SIWS — Solana登录)
Base:
https://api.collectorcrypt.com| Method | Endpoint | Primary Params | Description |
|---|---|---|---|
| POST | | Body: | Get nonce + EIP-4361 signing message |
| POST | | Body: | Exchange signature for access + refresh tokens |
| POST | | Body: | Refresh expired access token |
| POST | | Body: | Invalidate tokens |
基础URL:
https://api.collectorcrypt.com| 方法 | 端点 | 主要参数 | 描述 |
|---|---|---|---|
| POST | | 请求体: | 获取随机数+EIP-4361签名消息 |
| POST | | 请求体: | 用签名换取访问+刷新令牌 |
| POST | | 请求体: | 刷新过期的访问令牌 |
| POST | | 请求体: | 使令牌失效 |
Swap Program (On-Chain)
互换程序(链上)
Program ID:
CCSwaptcDXtfjyRMYBqavqBwiW162yXFAJrXN53UuENCThe swap program is an Anchor-based Solana smart contract. Trades follow this lifecycle:
Open → Approved → Executed → Settled → (Closed)
↑ ↑
cancel_trade cancel_tradeInstructions:
| Instruction | Description |
|---|---|
| Initialize trade between two wallets |
| Signal readiness (both parties must approve) |
| Commit to execution (both parties must execute) |
| Abort open or approved trades |
| Transfer standard NFTs into/out of escrow |
| Transfer programmable NFTs |
| Transfer compressed NFTs |
| Transfer SPL tokens |
| Backend confirmation of completion |
| Final cleanup and rent refund |
程序ID:
CCSwaptcDXtfjyRMYBqavqBwiW162yXFAJrXN53UuENC互换程序是基于Anchor的Solana智能合约。交易遵循以下生命周期:
开启 → 已批准 → 已执行 → 已结算 → (已关闭)
↑ ↑
取消交易 取消交易指令:
| 指令 | 描述 |
|---|---|
| 初始化两个钱包间的交易 |
| 表示准备就绪(双方均需批准) |
| 提交执行(双方均需执行) |
| 中止开启或已批准的交易 |
| 转移标准NFT进出托管合约 |
| 转移可编程NFT |
| 转移压缩NFT |
| 转移SPL代币 |
| 后端确认交易完成 |
| 最终清理并退还租金 |
Marketplace On-Chain Details
交易市场链上细节
Account Structure
账户结构
| Account | Purpose |
|---|---|
| Market | Singleton PDA — config (admin keys, fees, treasury, paused status) |
| Listing | Sale info indexed by asset ID + seller, with delegation authority |
| Offer | Buyer offer details with independent escrow backing |
| UserEscrow | Per-user USDC deposit tracking for offer collateral |
| 账户 | 用途 |
|---|---|
| Market | 单例PDA — 配置(管理员密钥、手续费、国库、暂停状态) |
| Listing | 按资产ID+卖家索引的售卖信息,包含委托权限 |
| Offer | 买家出价详情,包含独立托管抵押 |
| UserEscrow | 每个用户的USDC存款跟踪,用于出价抵押 |
Fee Structure
手续费结构
Platform fee: 200 basis points (2%). Configurable 0–200 bps.
fee = floor(price * platform_fee_bps / 10000)Uses u128 intermediate precision to prevent overflow.
平台手续费:200个基点(2%)。可配置范围0–200个基点。
fee = floor(price * platform_fee_bps / 10000)使用u128中间精度防止溢出。
Security Properties
安全特性
- Non-custodial listings — NFTs remain in seller wallets using delegation, not escrow transfers
- Frontrun prevention — parameters validate on-chain prices match expectations
expected_price - Self-trade blocking — enforced validation
seller != buyer - PDA determinism — fixed seed schemes prevent unauthorized account substitution
- Broadcast allow-list — transactions validated against approved program IDs before submission
- 非托管挂单 — NFT通过委托权限保留在卖家钱包中,无需转移至托管合约
- 防抢先交易 — 参数验证链上价格与预期一致
expected_price - 防止自交易 — 强制校验
seller != buyer - PDA确定性 — 固定种子方案防止未授权账户替换
- 广播允许列表 — 交易提交前验证是否属于批准的程序ID
Error Handling
错误处理
Success is any 2xx — accept AND . Several marketplace write endpoints (, ) return on success. Never gate on ; check for a 2xx status plus / a / a transaction body.
200201/marketplace/buy/marketplace/broadcast201status == 200success: truesignatureAll APIs return errors in a standard shape:
json
{"statusCode": 400, "message": "human-readable error", "error": "Bad Request"}| Status | Meaning |
|---|---|
| Invalid input, on-chain failure, price mismatch, insufficient escrow, signing failure |
| Invalid or expired token |
| Access denied, program ID outside broadcast allow-list |
| Card, NFT, listing, offer, or address not found |
| Conflict (already listed, owner changed, wallet linked to Privy account) |
| Rate limit exceeded |
| Machine empty, too many packs open, or processing error |
所有2xx状态码均为成功——接受和。 多个市场写端点(、)成功时返回。切勿仅校验;检查2xx状态码+ / / 交易体。
200201/marketplace/buy/marketplace/broadcast201status == 200success: truesignature所有API返回标准格式错误:
json
{"statusCode": 400, "message": "可读错误信息", "error": "Bad Request"}| 状态码 | 含义 |
|---|---|
| 无效输入、链上失败、价格不匹配、托管余额不足、签名失败 |
| 令牌无效或过期 |
| 访问被拒绝、程序ID不在广播允许列表中 |
| 未找到卡牌、NFT、挂单、出价或地址 |
| 冲突(已挂单、所有者变更、钱包已关联Privy账户) |
| 请求频率超限 |
| 机器库存为空、开启卡包过多或处理错误 |
Safety Notes
注意事项
- Marketplace prices are in whole USDC. means $25.00 USDC.
"price": 25 - Buy/broadcast succeed with HTTP — accept any 2xx, parse the body which may be raw base64 (not JSON), and verify the result on Solana RPC (
201), not via a marketplace refetch. See the End-to-End Buy Recipe.getSignatureStatuses - Metaplex Core () is common — omit
nftStandard: "core"for those; only sendtokenStandard/"Pnft"when the asset really is one."Cnft" - Starchild wallet signing returns (snake_case) — read that (or the camelCase fallback) before broadcasting.
signed_transaction - Gacha is in USDC lamports. 42,500,000 = $42.50 USDC (1 USDC = 1,000,000 lamports).
refundAmount - Gacha buyback window is 72 hours. After that, the NFT cannot be sold back to the machine.
- Buyback refund is a per-machine percentage of insured/market value (not the purchase price). The rate is exposed as in
instantBuyback(e.g.GET /api/machines= 85%); don't assume a fixed global rate. Use85to get the exact refundGET /api/buyback/available?wallet=…&nft=…before building a buyback tx (USDC base units, already adjusted for the machine's buyback % and capped at 40,000 USDC).amount - Non-custodial listings — NFTs stay in seller wallets via delegation. If a seller transfers an NFT without canceling the listing, the listing becomes invalid. Backend auto-cancellation is not guaranteed.
- Escrow must be pre-funded for offer updates — does NOT transfer additional USDC; the escrow must already contain the full new amount.
update-offer - cNFT accept-offer may require two transactions — if the cNFT is currently listed, the API returns a cancel-listing tx that must be signed first.
- Shipping creates real physical shipments. Always confirm address and NFT selection with the user before calling .
/redeem/prepare - Signed transactions are irreversible. Verify NFT address, price, and wallet before broadcasting.
- VRF rolls are final. Once a pack is opened, the result cannot be changed or re-rolled.
- Track B (SIWS) is crypto-only. No card payment support. Wallets already linked to Privy accounts will get .
409 Conflict - — use this flag when the user's wallet lacks SOL for transaction fees; the backend will pay gas. Also use it to recover from
userHasSol: falsebroadcast errors.INSUFFICIENT_FUNDS_RETRYABLE
- 市场价格为整数USDC。 代表25.00 USDC。
"price": 25 - 购买/广播成功时返回HTTP — 接受所有2xx状态码,解析可能为原始Base64的响应体,并通过Solana RPC(
201)验证结果,而非重新查询市场数据。详见完整购买流程。getSignatureStatuses - Metaplex核心版()较为常见 — 此类资产请省略
nftStandard: "core";仅当资产确实为pNFT或cNFT时才传入tokenStandard/"Pnft"。"Cnft" - Starchild钱包签名返回(蛇形命名)——广播前优先读取此字段(或驼峰命名的备选字段)。
signed_transaction - 扭蛋为USDC最小单位。 42,500,000 = 42.50 USDC(1 USDC = 1,000,000最小单位)。
refundAmount - 扭蛋回购窗口期为72小时。 超过此时间后,NFT无法卖回给机器。
- 回购退款为机器设定的保险/市场价值百分比(不是购买价格)。回购率在中以
GET /api/machines字段暴露(例如instantBuyback代表85%);请勿假设固定全局回购率。构建回购交易前,使用85获取精确退款金额(USDC最小单位,已根据机器回购率调整,上限为40,000 USDC)。GET /api/buyback/available?wallet=…&nft=… - 非托管挂单 — NFT通过委托权限保留在卖家钱包中。若卖家未取消挂单就转移NFT,挂单会失效。后端不保证自动取消挂单。
- 更新出价需预先充值托管账户 — 不会额外转入USDC;托管账户必须已存入足额的新出价金额。
update-offer - 接受cNFT出价可能需要两步交易 — 若cNFT当前处于挂单状态,API会返回取消挂单交易,需先签名此交易。
- 物流会创建真实实体运单。 调用前,请务必与用户确认地址和NFT选择。
/redeem/prepare - 签名交易不可撤销。 广播前请验证NFT地址、价格和钱包信息。
- VRF抽取结果不可更改。 卡包开启后,结果无法修改或重新抽取。
- 方式B(SIWS)仅支持加密货币支付。 不支持银行卡支付。已关联Privy账户的钱包会返回。
409 Conflict - — 当用户钱包余额不足支付交易手续费时使用此标志;后端会支付Gas费。也可用于从
userHasSol: false广播错误中恢复。INSUFFICIENT_FUNDS_RETRYABLE
Known Limitations
已知限制
- Marketplace uses delegation, not escrow — if a seller transfers their NFT elsewhere without canceling, the listing breaks silently. Always check listing validity before buying.
- Field names differ across endpoints — listing uses , cancel-listing uses
nftAddress, update-listing usestokenMint+tokenMint+newPrice. Always check the exact field names per endpoint above.coin - Gacha codes are machine-specific (e.g.,
packType,pokemon_50). Usepokemon_250to discover available pack types and current pricing.GET /api/machines - No keyword search for gacha NFTs — use with
GET /api/getNftsandcodefilters, or browse viararity.GET /api/machines - Swap is on-chain only — no REST API wrapper; interact via Solana transactions against the Anchor program IDL.
- Access tokens expire in 15 minutes (Track B / SIWS) — implement refresh token rotation for long sessions.
- eBay Bidder has no public API documentation — it's a consumer-facing tool at .
https://bid.collectorcrypt.com - Launchpads are admin-managed drop pages — no public API for creating or configuring them.
- Browse listings cache — unauthenticated GET requests are cached for 5 seconds.
- 市场使用委托而非托管 — 若卖家未取消挂单就将NFT转移至其他地址,挂单会静默失效。购买前请始终检查挂单有效性。
- 各端点字段名称不一致 — 挂单使用,取消挂单使用
nftAddress,更新挂单使用tokenMint+tokenMint+newPrice。请始终参考上文各端点的精确字段名称。coin - 扭蛋代码为机器专属(例如
packType、pokemon_50)。使用pokemon_250查询可用卡包类型和当前定价。GET /api/machines - 扭蛋NFT无关键词搜索 — 使用配合
GET /api/getNfts和code过滤,或通过rarity浏览。GET /api/machines - 互换仅支持链上操作 — 无REST API封装;需通过Solana交易与Anchor程序IDL交互。
- 访问令牌有效期为15分钟(方式B/SIWS)——长会话需实现刷新令牌轮换。
- eBay Bidder无公开API文档 — 这是面向消费者的工具,地址为。
https://bid.collectorcrypt.com - Launchpads为管理员管理的发布页面 — 无创建或配置的公开API。
- 浏览挂单缓存 — 未认证GET请求有5秒缓存。