collectorcrypt について
CollectorCrypt API は、Solana 上のコレクションカード NFT マーケットプレイスと関連サービスを扱うスキルです。カード取引、ミステリーパック、実物カードの引き換えに対応し、オンチェーントランザクションはウォレット署名で処理します。
主な機能
- 01コレクションカード NFT の閲覧と取引
- 02ランダムカードパックの生成と開封
- 03NFT と実物カードの引き換え
- 04エスクローによる P2P 資産交換
- 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
主要な概念
製品スイート
- マーケットプレイス — Solana 上の USDC を使用してコレクティブルカード NFT を売買・取引
- ガチャマシン — ミステリーパックシステム。USDC を消費してランダム化された Pokemon カード NFT を入手でき、VRF で検証された公平性を備えています
- Vault — NFT ↔ 物理カードを橋渡し。実際のカードを預けて NFT をミントし、NFT をバーンして物理カードを発送
- スワップ — エスクローを介したピアツーピアのオンチェーン資産スワップ(NFT、pNFT、cNFT、SPL トークン)
- ローンチパッド — 新しいコレクティブルのリリースをミントするためのドロップページ
- 入札者 — eBay の入札自動化。資金を預け、入札を代行し、落札したカードをトークン化
Solana プログラム
| プログラム | ID |
|---|---|
| マーケットプレイス | CcmRKTuZCGJBWQwMHvDYApBRvSZNHqGJXkznqpDTSQUr |
| スワップ | CCSwaptcDXtfjyRMYBqavqBwiW162yXFAJrXN53UuENC |
対応する NFT の種類
- プログラマブル NFT(pNFT) — ロイヤルティが強制される Metaplex 標準。
tokenStandard: "Pnft"を使用します - 圧縮 NFT(cNFT) — Metaplex Bubblegum のマークルツリー構造。
tokenStandard: "Cnft"を使用します - Metaplex Core(
nftStandard: "core") — 単一アカウント標準。公開中のリスティングの多くは Core です(参照レスポンスは"nftStandard": "core"を返します)。Core のリスティングでは、buy/list/offer のボディからtokenStandardを省略してください —"Pnft"/"Cnft"を渡さないでください。tokenStandardを送信するのは、その資産が実際に pNFT または cNFT である場合のみです。
通貨
すべてのマーケットプレイスおよびガチャのトランザクションは、Solana 上の USDC(SPL トークン)を使用します。送料は USDC または USDT を受け付けます。ガス代は SOL で支払われます。
マーケットプレイスの価格は整数の USDC です(例: "price": 25 は $25.00 USDC を意味します)。
トランザクションのパターン(マーケットプレイスと配送)
3 ステップのフロー:
- ビルド — API エンドポイントに POST し、base64 でエンコードされた未署名のトランザクションを受け取ります
- 署名 — Solana ウォレット(Phantom/Solflare、または Starchild ウォレットヘルパー — 下記参照)で署名します
- ブロードキャスト — 署名済みトランザクションを
/marketplace/broadcastに POST します
HTTP ステータス — 200 と 201 の両方を成功として受け入れてください。 実際に確認済み: /marketplace/buy と /marketplace/broadcast は 200 ではなく 201 を返します。任意の 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 を /marketplace/broadcast に signedTransaction フィールドとして渡してください。
ガチャのレアリティ階層
| レアリティ | 確率 |
|---|---|
| Epic | 1% |
| Rare (High) | 4% |
| Uncommon (Mid) | 15% |
| Common (Low) | 80% |
VRF(検証可能な乱数関数)
ガチャの抽選には、改ざん不可能で証明可能に公正な結果を実現するために検証可能な乱数関数が使用されます。選択は 2 段階 です:
- ロール → ティア: 開始トランザクションに対するプレイヤー自身のウォレット署名をシードとして、1~100,000,000 の範囲の一様な整数ロール が、マシンに設定された重み(
/api/machinesのtierRangesを参照)によってレアリティティアにマッピングされます。 - カード → ティア内: 証明可能な選択によって、そのティア内の特定の NFT が選ばれます。
シード(ウォレット署名)と結果は、付与トランザクションのオンチェーンメモにコミットされ、Solana 上に記録されます。これにより予測や操作が防止されます。独立して検証できます:
GET /api/vrf/verify?memo=YOUR_MEMO— 証明、公開鍵、トランザクション署名、および保存されたロールが再計算されたロールと一致するかどうかを返します。/verify-selection/YOUR_MEMO— オンチェーンメモに対するカード選択のブラウザ側でのリプレイ。
ドキュメントには特定の VRF アルゴリズムの名前は記載されて いません。特定のアルゴリズムを断言しないでください。
呼び出し方法
ガチャ API — API キーなし(キーは存在しません)
API キーは存在しません。CC_API_KEY を設定せず、x-api-key ヘッダーを送信せず、キーの取得も試みないでください — CollectorCrypt チームはキーシステムが存在しないことを確認しています。 すべてのガチャエンドポイントは、読み取りも書き込みも同様に、認証なしで呼び出されます。
# 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(パック → 署名 → 送信 → 開封の完全なフロー)。https://dev-gacha.collectorcrypt.com の devnet で、すべての呼び出しをライブで試せます(USDC フォーセットで devnet ウォレットに資金を供給: https://spl-token-faucet.com/?token-name=USDC-Dev)。
マーケットプレイス 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
}'
出荷 API — 2 つの認証トラック
トラック A — Privy ID トークン:
Authorization: Bearer <privy-identity-token>
トラック B — Sign-In With 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 分
- リフレッシュ:
POST /auth/wallet/refreshに{"refreshToken": "..."}を付けて実行 - ログアウト:
POST /auth/wallet/logout - トラック B の制限: 暗号通貨支払いのみ(カード決済なし)、Solana 署名のみ
インテントルーティング
マーケットプレイス
ベース: https://api.collectorcrypt.com
すべての POST エンドポイントは、base64 エンコードされた未署名の Solana トランザクションを返します。ウォレットで署名し、/marketplace/broadcast 経由でブロードキャストします。
NFT の出品 — POST /marketplace/list
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
wallet | string | はい | 出品者の Solana アドレス |
cardId | string | はい | CollectorCrypt カード DB 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 の mint アドレス |
seller | string | いいえ | 省略時は wallet が使用されます |
エラー: 400 (オンチェーンエラー)、404 (リスティングが見つからない)
リスティング価格の更新 — POST /marketplace/update-listing
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
wallet | string | はい | 出品者のウォレット |
tokenMint | string | はい | NFT の mint アドレス |
newPrice | number | はい | USDC での更新後の価格 |
coin | string | はい | "USDC" |
エラー: 400 (価格が変更されていない、またはオンチェーンエラー)、404 (リスティングが見つからない)
NFT の購入 — POST /marketplace/buy
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
wallet | string | はい | 購入者のウォレット |
nftAddress | string | はい | NFT の mint アドレス |
price | number | はい | USDC でのリスティング価格 |
currency | string | はい | "USDC" |
tokenStandard | enum | いいえ | "Pnft" または "Cnft" — Metaplex Core リスティングの場合は省略します (nftStandard: "core") |
sellerWallet | string | いいえ | 省略時は DB から解決されます |
fundingSource | enum | いいえ | "wallet" (デフォルト) または "escrow" |
成功ステータスは 200 または 201 です (実際の購入では 201 が返ります)。レスポンスボディは JSON ではなく生の base64 テキストである可能性があります — 防御的にパースしてください (上記のトランザクションパターンを参照)。
fundingSource: "wallet"→ 単一の base64 署名済みトランザクション (JSON{"transaction": "..."}または プレーンな base64 テキスト)fundingSource: "escrow"→{"transactions": ["BASE64_WITHDRAW_TX", "BASE64_BUY_TX"], "fundingSource": "escrow"}
エスクローには最低 price × 1.02 USDC の残高が必要です。
エラー: 400 (オンチェーンエラー、エスクロー残高不足)、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 mint | 4AWreh7pqVb4jhANAXFz2fwSPKqWr5ZAFMgaAFWZS9nk |
| 出品者 | FfveJgtFmGPCSazkjicf21WLk9rdUaMsownVVA8LRhwf |
| ブロードキャスト署名 | 5SwxeuWGjWbiAFq8YVN3Qsw1PXnKXBakKA2ykgccc78gg6JkGnyi48StezcijXmgWHyGWvojq8TYmTXJoC9XnbjH |
| Solana ステータス | finalized、err: null |
オファーの作成 — POST /marketplace/make-offer
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
wallet | string | はい | 購入者のウォレット |
cardId | string | はい | CollectorCrypt カード DB ID |
nftAddress | string | はい | NFT の mint アドレス |
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..."
}
まず cancel-listing トランザクションに署名し、その後 accept-offer を再度呼び出してください。
エラー: 400(価格のずれ、オンチェーンエラー)、404(オファーが見つかりません)
リスティングの閲覧 — GET /marketplace
公開されており、認証は不要です。未認証のリクエストには5秒間のキャッシュが適用されます。
ページネーション:
| パラメータ | 型 | デフォルト | 説明 |
|---|---|---|---|
page | integer | 1 | 1始まりのページ |
step | integer | 100 | ページサイズ(最大100) |
フィルター(すべて任意):
| パラメータ | 型 | 説明 |
|---|---|---|
search | string | itemName、nftAddress、gemrateCardName、gradingID に対する部分文字列一致。mint で検索する唯一の方法はこれです — nftAddress クエリパラメータは存在しません(GET /marketplace?nftAddress=<mint> は 400 を返します)。代わりに search=<mint> を使用してください。 |
ownerAddress | string | 所有者ウォレットでフィルタリング |
hideOwned | boolean | 呼び出し元自身のカードを非表示にする(認証が必要) |
favoritesOnly | boolean | お気に入り登録済みのカードのみ(認証が必要) |
followingOnly | boolean | フォロー中のユーザーのみ(認証が必要) |
followingOf | string | このウォレットがフォローしているユーザーが所有するカード |
marketplaceStatus | CSV | Buy now、Has offers |
marketplaceSource | CSV | CC、ME |
marketplaceTags | CSV | グローバルタグ名(例: Hot、Featured) |
listPriceMin / listPriceMax | number | USDC 価格範囲 |
insuredValueMin / insuredValueMax | number | 保険価額の範囲 |
yearMin / yearMax | integer | カードの年範囲 |
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 | boolean | 鑑定済みのカードのみ |
autographed | boolean | サイン入りのカードのみ |
burnt | boolean | バーン済みカードを含める(デフォルトでは除外) |
grade | string | 部分文字列一致 |
genericGradeMin / genericGradeMax | number | 数値グレード範囲 |
gradingCompany | CSV | PSA、Beckett、CGC、SGC、TAG、CSG、KSA、PSA/DNA、UDA、Steiner、BBCE、Rare Edition、Not graded |
set / format / language / productCode | string | 未開封品/コミックのメタデータに対する部分文字列一致 |
pokemon | string | gemrateCardName に対する単語境界一致 |
ccBuyback | boolean | 有効な CC 買い戻しがあるカードのみ |
gemrateSet / gemrateGrade / gemrateCardName / gemrateSpecId / gemrateParallel | string | 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 | string | はい | 署名者ウォレットアドレス |
signedTransaction | string | はい | Base64 エンコードされた署名済みトランザクション |
nftAddress | string | いいえ | 5秒後にメタデータの更新をトリガーします |
成功ステータスは 200 または 201 です(ライブブロードキャストは 201 を返します)。レスポンス:
{
"success": true,
"signature": "SOLANA_TRANSACTION_SIGNATURE",
"message": "Transaction broadcast successfully"
}
201 を失敗として扱わないでください — ステータスコードではなく、success === true / signature の存在を確認してください。
残高不足からの復旧: ブロードキャストが "code": "INSUFFICIENT_FUNDS_RETRYABLE" を含む 400 を返した場合、userHasSol: false を指定して元のトランザクションを再構築し、バックエンドが手数料を負担するようにしてから、再署名して再ブロードキャストしてください。
検証: トランザクションは送信前にプログラム ID の許可リストに対して検証されます。
エラー: 400(無効なトランザクション、残高不足で再試行可能、送信失敗)、403(プログラム ID が許可リストにない)
ガチャマシン
ベース: https://gacha.collectorcrypt.com
| メソッド | エンドポイント | 主なパラメータ | 説明 |
|---|---|---|---|
| GET | /api/status | — | マシンの稼働状態(オープン/クローズ) |
| GET | /api/stock | — | マシンごとのレアリティ別 NFT 在庫数 |
| GET | /api/machines | — | 全マシンの完全な設定: 価格、odds、tierRanges(ロール→ティアの範囲)、リアルタイムの stock、instantBuyback %、ev(レアリティで重み付けした保険価値の期待値) |
| GET | /api/getNfts | code、rarity、page、limit | フィルタリング可能な利用可能 NFT |
| POST | /api/generatePack | Body: playerAddress、packType、turbo、altPlayerAddress | 1 パック分の購入トランザクションを作成 |
| 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 を事前確認(tx 作成前) |
| 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 | 種類別のパック数(購入 vs ギフト、使用済み vs 未使用) |
| 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 | ロールの VRF プルーフを検証 |
ガチャのレスポンス形式
generatePack レスポンス:
{"memo": "slug-uuid", "transaction": "base64_encoded_transaction"}
memo は cc-<uuid> です(API キーが存在しないため、パートナースラッグのプレフィックスは適用されません)。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 レスポンス(ターボモードの買い戻し、Common ロール): "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": "..."
}
発送 / 保管庫の引き換え
ベース: 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 | 住所を削除します |
送料
| 地域 | 基本料金 | 追加1点ごと | 署名 | パック割増 |
|---|---|---|---|---|
| USA | $5.99 | $3.00 | +$3.00 (金額 >= $500) | $0.18/パック |
| Canada | $20.99 | $3.00 | 含む | $0.25/パック |
| Europe | $29.99 | $3.00 | 含む | $0.25/パック |
| Australia/NZ | $34.99 | $3.00 | 含む | $0.25/パック |
| Rest of World | $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 — Sign-In With Solana)
ベース: 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 ヘッダーのアクセストークンも可) | トークンを無効化します |
スワッププログラム (オンチェーン)
プログラム ID: CCSwaptcDXtfjyRMYBqavqBwiW162yXFAJrXN53UuENC
スワッププログラムは Anchor ベースの Solana スマートコントラクトです。取引は次のライフサイクルに従います:
Open → Approved → Executed → Settled → (Closed)
↑ ↑
cancel_trade cancel_trade
命令:
| 命令 | 説明 |
|---|---|
create_trade | 2つのウォレット間で取引を初期化します |
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 bps で設定可能です。
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 を意味します。 - buy/broadcast は HTTP
201で成功します — 任意の 2xx を受け入れ、生の base64(JSON ではない)である可能性があるボディを解析し、マーケットプレイスの再取得ではなく Solana RPC(getSignatureStatuses)で結果を検証してください。エンドツーエンドの購入手順を参照してください。 - Metaplex Core(
nftStandard: "core")は一般的です — その場合はtokenStandardを省略してください。アセットが実際にそうである場合にのみ"Pnft"/"Cnft"を送信してください。 - Starchild ウォレットの署名は
signed_transaction(snake_case)を返します — ブロードキャストする前に、それ(または camelCase のフォールバック)を読み取ってください。 - ガチャの
refundAmountは USDC ランポート単位です。 42,500,000 = $42.50 USDC(1 USDC = 1,000,000 ランポート)。 - ガチャの買い戻し期間は 72 時間です。 それ以降、その NFT をマシンに売り戻すことはできません。
- 買い戻しの返金額は、マシンごとの保険額/市場価値に対する割合です(購入価格ではありません)。この率は
GET /api/machinesのinstantBuybackとして公開されています(例:85= 85%)。固定のグローバルレートを想定しないでください。買い戻しトランザクションを構築する前に、正確な返金額amountを取得するにはGET /api/buyback/available?wallet=…&nft=…を使用してください(USDC の基本単位で、すでにマシンの買い戻し率が適用されており、上限は 40,000 USDC です)。 - ノンカストディアル出品 — NFT はデリゲーションにより出品者のウォレットに残ります。出品者が出品をキャンセルせずに NFT を転送した場合、その出品は無効になります。バックエンドによる自動キャンセルは保証されていません。
- オファーの更新にはエスクローの事前入金が必要です —
update-offerは追加の USDC を転送しません。エスクローにはすでに新しい全額が含まれている必要があります。 - cNFT の accept-offer には 2 つのトランザクションが必要になる場合があります — cNFT が現在出品中の場合、API は先に署名が必要な出品キャンセルのトランザクションを返します。
- 発送は実際の物理的な配送を伴います。
/redeem/prepareを呼び出す前に、必ずユーザーとアドレスおよび NFT の選択を確認してください。 - 署名済みトランザクションは取り消せません。 ブロードキャストする前に、NFT アドレス、価格、ウォレットを確認してください。
- VRF のロールは確定です。 パックを開封すると、結果を変更したり再ロールしたりすることはできません。
- トラック B(SIWS)は暗号資産のみです。 カード決済には対応していません。すでに Privy アカウントにリンクされているウォレットは
409 Conflictになります。 userHasSol: false— ユーザーのウォレットにトランザクション手数料用の SOL がない場合にこのフラグを使用します。バックエンドがガス代を支払います。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で閲覧してください。 - スワップはオンチェーンのみです — REST API ラッパーはありません。Anchor プログラム IDL に対して Solana トランザクションを介して操作してください。
- アクセストークンは 15 分で期限切れになります(トラック B / SIWS)— 長時間のセッションにはリフレッシュトークンのローテーションを実装してください。
- eBay Bidder には公開 API ドキュメントがありません —
https://bid.collectorcrypt.comにある一般消費者向けツールです。 - ローンチパッドは管理者が管理するドロップページです — 作成や設定のための公開 API はありません。
- リスティング閲覧のキャッシュ — 認証されていない GET リクエストは 5 秒間キャッシュされます。