Skip to main content

Marketplace API

Overview

The CollectorCrypt Marketplace V2 API lets you build clients on top of the CollectorCrypt V2 marketplace program on Solana. Every request follows the same three-step pattern:

  1. Build — POST to a builder endpoint (/marketplace/list, /buy, etc.) to receive an unsigned transaction. If the wallet has no SOL for fees, the backend can co-sign as fee payer and return a partially-signed transaction (see userHasSol).
  2. Sign — the user's wallet signs the transaction.
  3. Broadcast — POST the signed transaction to /marketplace/broadcast.
  • Program ID: CcmRKTuZCGJBWQwMHvDYApBRvSZNHqGJXkznqpDTSQUr
  • Currency: USDC (SPL Token)
  • NFT types: pNFTs (Programmable NFTs) and cNFTs (Compressed NFTs)

Base URL

EnvironmentBase URL
Productionhttps://api.collectorcrypt.com
Devnethttps://dev-api.collectorcrypt.com

All endpoints below are relative to the base URL.

Devnet USDC faucet

For testing on devnet: https://spl-token-faucet.com/?token-name=USDC-Dev

Request format

All endpoints accept JSON bodies and include a required wallet field — the caller's Solana wallet address (base58). The backend builds an unsigned transaction addressed to that wallet; the wallet's signature on the returned transaction is what authorizes the action on-chain.

curl -X POST "https://api.collectorcrypt.com/marketplace/list" \
-H "Content-Type: application/json" \
-d '{ "wallet": "YOUR_WALLET_ADDRESS", "cardId": "...", "nftAddress": "...", "price": 25.00, "currency": "USDC" }'

Endpoints

1. List an NFT — POST /marketplace/list

Creates a transaction for listing an NFT for sale. The seller must sign and broadcast the transaction via /marketplace/broadcast.

Request Body:

{
"wallet": "SELLER_WALLET_ADDRESS",
"cardId": "card_db_id",
"currency": "USDC",
"price": 25.00,
"nftAddress": "NFT_MINT_ADDRESS",
"tokenStandard": "Pnft",
"userHasSol": true
}
FieldTypeRequiredDescription
walletstringYesThe seller's wallet public key
cardIdstringYesThe CollectorCrypt card ID
currencystringYesCurrency for the listing (use "USDC")
pricenumberYesListing price in USDC
nftAddressstringYesThe NFT mint address
tokenStandard"Pnft" | "Cnft"NoToken standard. Optional; resolved via DAS if omitted.
userHasSolbooleanNoSet to false to have the backend act as fee payer (returned transaction is pre-signed by the backend). Default: the backend detects the wallet's SOL balance and caches the decision.

Response: The unsigned transaction as a base64 string.

BASE64_ENCODED_UNSIGNED_TRANSACTION

Error Responses:

  • 400: On-chain error while building the listing transaction
  • 409: NFT is already listed on the marketplace

2. Cancel a Listing — POST /marketplace/cancel-listing

Creates a transaction to cancel an active listing. The seller must sign and broadcast it.

Request Body:

{
"wallet": "CALLER_WALLET_ADDRESS",
"tokenMint": "NFT_MINT_ADDRESS",
"seller": "SELLER_WALLET_ADDRESS"
}
FieldTypeRequiredDescription
walletstringYesThe caller's wallet public key (the signer)
tokenMintstringYesThe NFT mint address
sellerstringNoThe listing seller — defaults to wallet if omitted

Response: The unsigned transaction as a base64 string.

BASE64_ENCODED_UNSIGNED_TRANSACTION

Error Responses:

  • 400: On-chain error while building the cancel transaction
  • 404: No active listing found on-chain for this NFT

3. Update a Listing Price — POST /marketplace/update-listing

Creates a transaction to update the price of an active listing.

Request Body:

{
"wallet": "SELLER_WALLET_ADDRESS",
"tokenMint": "NFT_MINT_ADDRESS",
"newPrice": 30.00,
"coin": "USDC"
}
FieldTypeRequiredDescription
walletstringYesThe seller's wallet public key
tokenMintstringYesThe NFT mint address
newPricenumberYesUpdated listing price in USDC
coinstringYesCurrency (use "USDC")

Response: The unsigned transaction as a base64 string.

BASE64_ENCODED_UNSIGNED_TRANSACTION

Error Responses:

  • 400: newPrice equals the current listing price, or on-chain error while building the update transaction
  • 404: No listing found on-chain for this NFT

4. Buy an NFT — POST /marketplace/buy

Creates a transaction for purchasing a listed NFT. The buyer must sign and broadcast it.

Request Body:

{
"wallet": "BUYER_WALLET_ADDRESS",
"nftAddress": "NFT_MINT_ADDRESS",
"price": 25.00,
"currency": "USDC",
"tokenStandard": "Pnft",
"sellerWallet": "SELLER_WALLET_ADDRESS",
"fundingSource": "wallet"
}
FieldTypeRequiredDescription
walletstringYesThe buyer's wallet public key
nftAddressstringYesThe NFT mint address
pricenumberYesThe listed price in USDC
currencystringYesCurrency (use "USDC")
tokenStandard"Pnft" | "Cnft"NoToken standard. Optional; resolved via DAS if omitted.
sellerWalletstringNoSeller wallet. Optional; resolved from the DB if omitted.
fundingSource"wallet" | "escrow"NoPayment source. Defaults to "wallet". Set to "escrow" to pay from the buyer's on-chain shared escrow balance.

Response: The unsigned transaction as a base64 string.

BASE64_ENCODED_UNSIGNED_TRANSACTION

When fundingSource is "escrow", the response is a JSON object with two transactions (a withdraw from escrow, then the buy) to sign together:

{
"transactions": ["BASE64_WITHDRAW_TX", "BASE64_BUY_TX"],
"fundingSource": "escrow"
}

Escrow mode requires the buyer's escrow to hold at least price × 1.02 USDC (price + 2% platform fee).

Error Responses:

  • 400: On-chain error, or insufficient escrow balance (escrow mode only)
  • 404: Card, seller wallet, or listing not found
  • 409: Card owner changed since the listing was built (someone else bought it first) — refetch and retry

5. Make an Offer — POST /marketplace/make-offer

Creates a transaction for placing an offer on an NFT. Funds are moved into the buyer's on-chain escrow account. The buyer must sign and broadcast the transaction.

Request Body:

{
"wallet": "BUYER_WALLET_ADDRESS",
"cardId": "card_db_id",
"nftAddress": "NFT_MINT_ADDRESS",
"price": 20.00,
"currency": "USDC",
"tokenStandard": "Cnft",
"userHasSol": true,
"ownerWallet": "OWNER_WALLET_ADDRESS",
"collectionHash": "MERKLE_TREE_COLLECTION_HASH"
}
FieldTypeRequiredDescription
walletstringYesThe buyer's wallet public key
cardIdstringYesThe CollectorCrypt card ID
nftAddressstringYesThe NFT mint address
pricenumberYesOffer price in USDC
currencystringYesCurrency (use "USDC")
tokenStandard"Pnft" | "Cnft"NoToken standard. Optional; resolved via DAS if omitted.
userHasSolbooleanNoSet to false to have the backend act as fee payer (returned transaction is pre-signed by the backend). Default: the backend detects the wallet's SOL balance and caches the decision.
ownerWalletstringNoCurrent NFT owner. Optional; resolved via RPC if omitted.
collectionHashstringNocNFT collection hash. Optional; resolved via DAS if omitted (cNFTs only).

Response: The unsigned transaction as a base64 string.

BASE64_ENCODED_UNSIGNED_TRANSACTION

Error Responses:

  • 400: Could not determine NFT owner from the chain, or on-chain error while building the offer transaction

6. Cancel an Offer — POST /marketplace/cancel-offer

Creates a transaction to cancel an active offer. Optionally keeps funds in escrow for future offers.

Request Body:

{
"wallet": "BUYER_WALLET_ADDRESS",
"nftAddress": "NFT_MINT_ADDRESS",
"keepInEscrow": false
}
FieldTypeRequiredDescription
walletstringYesThe buyer's wallet public key (offer maker)
nftAddressstringYesThe NFT mint address
keepInEscrowbooleanNoIf true, released USDC stays in your escrow account. If false (default), USDC is withdrawn to your wallet.

Response: The unsigned transaction as a base64 string.

BASE64_ENCODED_UNSIGNED_TRANSACTION

If the wallet has insufficient SOL for rent, the backend automatically falls back to keepInEscrow: true (funds stay in escrow).

Error Responses:

  • 404: No active offer found on-chain for this buyer/NFT pair

7. Update an Offer — POST /marketplace/update-offer

Creates a transaction to change the price of an existing offer.

Request Body:

{
"wallet": "BUYER_WALLET_ADDRESS",
"nftAddress": "NFT_MINT_ADDRESS",
"currency": "USDC",
"buyer": "BUYER_WALLET_ADDRESS",
"price": 22.00
}
FieldTypeRequiredDescription
walletstringYesThe buyer's wallet public key (offer maker, signer)
nftAddressstringYesThe NFT mint address
currencystringYesCurrency (use "USDC")
buyerstringYesThe buyer's wallet public key (typically equal to wallet)
pricenumberYesNew offer price in USDC

Response: The unsigned transaction as a base64 string.

BASE64_ENCODED_UNSIGNED_TRANSACTION

The program requires the buyer's escrow to already hold the full new amount — this transaction does not transfer additional USDC into escrow.

Error Responses:

  • 400: New price equals the current offer price, buyer has no escrow account, escrow balance is less than the new price, or on-chain error while building the update transaction
  • 404: Offer not found on-chain (the DB record, if any, is marked Cancelled in the background)

8. Accept an Offer — POST /marketplace/accept-offer

Creates a transaction for the NFT owner to accept a buyer's offer. The seller must sign and broadcast it.

Request Body:

{
"wallet": "SELLER_WALLET_ADDRESS",
"nftAddress": "NFT_MINT_ADDRESS",
"buyer": "BUYER_WALLET_ADDRESS",
"currency": "USDC",
"price": 20.00,
"tokenStandard": "Pnft",
"userHasSol": true
}
FieldTypeRequiredDescription
walletstringYesThe seller's wallet public key (NFT owner, signer)
nftAddressstringYesThe NFT mint address
buyerstringYesThe buyer's wallet public key (the offer maker)
currencystringYesCurrency (use "USDC")
pricenumberYesThe offer price in USDC
tokenStandard"Pnft" | "Cnft"NoToken standard. Optional; resolved via DAS if omitted.
userHasSolbooleanNoSet to false to have the backend act as fee payer (returned transaction is pre-signed by the backend). Default: the backend detects the wallet's SOL balance and caches the decision.

Response: The unsigned transaction as a base64 string.

BASE64_ENCODED_UNSIGNED_TRANSACTION

If the NFT is a cNFT that's currently listed, the program requires the listing to be cancelled first. In that case the response is a JSON object containing a cancel-listing transaction — broadcast it, then call /marketplace/accept-offer again to get the settlement transaction:

{
"requiresCancelListing": true,
"cancelListingTx": "BASE64_CANCEL_LISTING_TX",
"message": "This cNFT is currently listed. Please sign the cancel listing transaction first, then accept the offer."
}

Error Responses:

  • 400: Offer price on-chain has drifted from the submitted price (race: the buyer updated or cancelled), or on-chain error while building the accept transaction
  • 404: Offer not found on-chain for this buyer/NFT pair

9. Browse Listings — GET /marketplace

Returns a paginated, filterable list of cards on the marketplace. This is a read endpoint — no wallet signature is required. Use it to discover listings (and the offers on them) before calling any of the transaction builders above.

The endpoint is public and lightly cached (5 seconds for unauthenticated requests).

Pagination

ParamTypeDefaultDescription
pageinteger11-indexed page number
stepinteger100Page size. Max 100.

Filter parameters (all optional unless noted)

CSV parameters accept either a comma-separated string (?cardType=Card,Sealed) or repeated query keys.

ParamTypeDescription
searchstringSubstring match against itemName, nftAddress, gemrateCardName, and gradingID
ownerAddressstringSolana wallet — return only cards owned by this address
hideOwnedbooleanIf true and the caller is authenticated, hide the caller's own cards
favoritesOnlybooleanOnly cards the caller has favorited (requires auth)
followingOnlybooleanOnly cards owned by users the caller follows (requires auth)
followingOfstringWallet — only cards owned by users that wallet follows
marketplaceStatusCSVBuy now, Has offers — filter by listing/offer state
marketplaceSourceCSVCC (CollectorCrypt V2), ME (Magic Eden)
marketplaceTagsCSVFilter by one or more global tag names (e.g. ?marketplaceTags=Hot,Featured)
listPriceMin / listPriceMaxnumberListed price range in USDC (SOL listings are auto-converted)
insuredValueMin / insuredValueMaxnumberFilter by insuredValue
yearMin / yearMaxintegerCard year range
categoriesCSVOne or more of Baseball, Basketball, Football, Pokemon, Magic The Gathering, Yu-Gi-Oh!, Lorcana, One Piece, Non-Sport, … (see service for the full list)
cardTypeCSVCard, Comic, ComicRaw, Game, Merch, Raw, Sealed
blockchainCSVSolana, … (Prisma Blockchain enum)
authenticatedbooleanOnly authenticated cards
autographedbooleanOnly autographed cards
burntbooleanInclude burned cards. Default excludes them.
gradestringSubstring match against grade
gradeNum filter via genericGradeMin / genericGradeMaxnumberNumeric grade range
gradingCompanyCSVPSA, Beckett, CGC, SGC, TAG, CSG, KSA, PSA/DNA, UDA, Steiner, BBCE, Rare Edition, Not graded
set / format / language / productCodestringSubstring match for sealed/comic metadata
pokemonstringWord-boundary match against gemrateCardName
ccBuybackbooleanOnly cards with an active CollectorCrypt buyback offer
gemrateSet / gemrateGrade / gemrateCardName / gemrateSpecId / gemrateParallelstringGemrate-specific substring filters
orderByenumSee below. Default listedDateDesc.

orderBy values

dateAsc, dateDesc, nameAsc, nameDesc, priceAsc, priceDesc (insured value), yearAsc, yearDesc, listedDateAsc, listedDateDesc, listedPriceAsc, listedPriceDesc.

Example

# First page of Pokémon cards listed on CC for under $100, newest first
curl "https://api.collectorcrypt.com/marketplace?categories=Pokemon&marketplaceSource=CC&listPriceMax=100&orderBy=listedDateDesc&page=1&step=50"

Response

{
"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": "...",
"status": "Transferred",
"createdAt": "2026-04-01T00:00:00.000Z",
"updatedAt": "2026-05-10T00:00:00.000Z",
"listing": {
"createdAt": "2026-05-01T00:00:00.000Z",
"updatedAt": "2026-05-01T00:00:00.000Z",
"currency": "USDC",
"price": "25",
"receiptId": "...",
"sellerId": "...",
"marketplace": "CC"
},
"offers": [{ "id": "offer_id" }],
"owner": {
"id": "user_id",
"name": "...",
"wallet": "OWNER_WALLET_ADDRESS"
},
"images": {
"front": "https://...",
"frontM": "https://...",
"frontS": "https://...",
"back": "https://...",
"backM": "https://...",
"backS": "https://..."
}
}
],
"findTotal": 1234,
"total": 50000,
"totalPages": 25,
"cardsQtyByCategory": {
"Pokemon": 800,
"Baseball": 200,
"...": 0
}
}
FieldDescription
filterNFtCardThe current page of cards. listing is null when the card isn't listed; offers is an array of active-offer ids.
findTotalTotal cards matching the filter (excludes the categories filter — used to compute cardsQtyByCategory).
totalTotal cards in the marketplace overall (status = 'Transferred').
totalPagesceil(findTotal / step).
cardsQtyByCategoryCount of matching cards per category — useful for sidebar facet counts.

10. Broadcast a Transaction — POST /marketplace/broadcast

Broadcasts a signed transaction to the Solana network. Use this after the user signs any transaction returned by the endpoints above.

Request Body:

{
"wallet": "SIGNER_WALLET_ADDRESS",
"signedTransaction": "base64_encoded_signed_transaction",
"nftAddress": "NFT_MINT_ADDRESS"
}
FieldTypeRequiredDescription
walletstringYesThe wallet that signed the transaction — used for fee-payer cache hints
signedTransactionstringYesThe base64-encoded signed transaction
nftAddressstringNoIf provided, triggers a background card metadata refresh after 5 seconds

Response:

{
"success": true,
"signature": "SOLANA_TRANSACTION_SIGNATURE",
"message": "Transaction broadcast successfully"
}

The transaction is validated against an allow-list of program IDs (the CollectorCrypt marketplace program and related system programs) before being submitted.

Retryable insufficient-funds error:

If the signer wallet has insufficient SOL for fees, the endpoint returns 400 with a structured JSON error body in message:

{
"code": "INSUFFICIENT_FUNDS_RETRYABLE",
"message": "Insufficient funds for transaction fees",
"retryable": true,
"useBackendPayer": true
}

Rebuild the transaction by calling the original builder endpoint with userHasSol: false — the backend will set itself as fee payer.

Error Responses:

  • 400: Invalid or undeserializable transaction, insufficient funds (retryable — see above), or submission failure
  • 403: Transaction contains a program ID that isn't on the allow-list

Errors

All error responses use this shape:

{
"statusCode": 400,
"message": "human-readable error",
"error": "Bad Request"
}
StatusMeaning
400Bad request — missing wallet, on-chain failure, price mismatch, insufficient escrow, or invalid signed transaction
403Transaction contains a program ID outside the broadcast allow-list
404Listing, offer, card, or seller wallet not found
409NFT is already listed, or the on-chain owner changed during /buy
429Rate limit exceeded

For /marketplace/broadcast, the insufficient-funds case returns a JSON-encoded string inside message with code: "INSUFFICIENT_FUNDS_RETRYABLE" — see the broadcast section above.