Skip to content

Claimable API

Detect claimable token registrations for a connected wallet and check individual token eligibility.

Endpoints

MethodPathDescription
GET/api/v2/registration/claimableDetect all claimable registrations for a wallet
POST/api/v2/registration/check-qualifyCheck if a wallet qualifies for a specific token

Detect Claimable Registrations

GET /api/v2/registration/claimable

Returns the tokens a wallet can claim, based on the platform's on-chain provenance index across all supported chains. Used by the QuickClaim feature.

Headers

HeaderRequiredDescription
X-API-KeyYesAPI key for authentication
X-Wallet-AddressYes*Wallet address to scan (EVM or Solana)

*If the request carries an authenticated wallet session (Authorization: Bearer <JWT>), the wallet is taken from the session and the X-Wallet-Address header is not needed. The header remains supported for API-key-only callers.

How Detection Works

  1. Provenance lookup: The platform keeps a reverse index of on-chain provenance (deployer, mint authority, update authority, majority holder) for tokens it has seen; the wallet is matched against it, with an indexer fallback for tokens that predate local capture
  2. Registration check: Tokens that already have active registrations (claimed or grace_period) are filtered out
  3. Qualification mapping: Each remaining token is annotated with how the wallet qualifies
  4. Sort: Results ordered by qualification strength (deployer first)

Chains Scanned

ChainChain IDDetection Methods
SolanasolanaDeployer, Mint Authority, Update Authority, Majority Holder
Arbitrum42161Deployer, Majority Holder
Base8453Deployer, Majority Holder
Polygon137Deployer, Majority Holder
BNB Chain56Deployer, Majority Holder
Gnosis100Deployer, Majority Holder
Ethereum1Deployer, Majority Holder

Response Format

json
{
  "tokens": [
    {
      "address": "0x6982508145454ce325ddbe47a25d4ec3d2311933",
      "chainId": "42161",
      "symbol": "PEPE",
      "name": "Pepe",
      "qualification": {
        "method": "deployer",
        "confidence": 1.0,
        "message": "You deployed this token"
      }
    }
  ],
  "total": 1
}

Response Fields

FieldTypeDescription
tokensarrayList of tokens the wallet can claim
tokens[].addressstringToken contract address
tokens[].chainIdstringChain identifier (numeric string for EVM, solana:... for Solana)
tokens[].symbolstringToken symbol
tokens[].namestringToken name
tokens[].qualificationobjectHow the wallet qualifies
tokens[].qualification.methodstringQualification method (see table below)
tokens[].qualification.confidencenumberConfidence score (0-1)
tokens[].qualification.messagestringHuman-readable explanation
totalintegerNumber of claimable tokens returned

The claim fee is not included per token — fetch it once from GET /api/v2/registration/fee.

Qualification Methods

Results are sorted by method priority (highest priority first):

PriorityMethodConfidenceChainsDescription
1deployer1.0AllWallet deployed the token contract
2mint_authority0.95SolanaWallet is the token's mint authority
3update_authority0.9SolanaWallet is the token's update authority
4majority_holder0.8AllWallet holds >50% of token supply

majority_holder is evaluated by the live check-qualify endpoint; the detect endpoint's provenance index currently surfaces the first three methods.

Code Examples

bash
curl https://api.chaindaddy.io/api/v2/registration/claimable \
  -H "X-API-Key: cd_live_abc123..." \
  -H "X-Wallet-Address: 0x1234567890abcdef1234567890abcdef12345678"
javascript
async function getClaimableTokens(apiKey, walletAddress) {
  const response = await fetch('https://api.chaindaddy.io/api/v2/registration/claimable', {
    headers: {
      'X-API-Key': apiKey,
      'X-Wallet-Address': walletAddress,
    },
  });

  const data = await response.json();
  console.log(`Found ${data.total} claimable tokens`);

  return data.tokens;
}

// Usage
const claimable = await getClaimableTokens('cd_live_abc123...', '0x1234...5678');
for (const item of claimable) {
  console.log(`${item.symbol} on chain ${item.chainId}, ${item.qualification.method}`);
}
python
import requests

def get_claimable_tokens(api_key, wallet_address):
    response = requests.get(
        "https://api.chaindaddy.io/api/v2/registration/claimable",
        headers={
            "X-API-Key": api_key,
            "X-Wallet-Address": wallet_address,
        },
    )
    response.raise_for_status()
    data = response.json()

    print(f"Found {data['total']} claimable tokens")

    return data["tokens"]

# Usage
claimable = get_claimable_tokens("cd_live_abc123...", "0x1234...5678")
for item in claimable:
    print(f"{item['symbol']} on chain {item['chainId']} "
          f"({item['qualification']['method']})")

Check Qualification

POST /api/v2/registration/check-qualify

Check if a specific wallet qualifies to claim a registration for a specific token. Use this to verify eligibility before initiating a claim transaction.

Request Body

FieldTypeRequiredDescription
walletstringYesWallet address to check
tokenAddressstringYesToken contract address
chainIdinteger/stringNoChain ID (integer for EVM, "solana" for Solana)
symbolstringNoToken symbol (used to check existing registration status)

Response Format

Eligible:

json
{
  "success": true,
  "eligible": true,
  "qualification": {
    "method": "deployer",
    "confidence": 1.0,
    "message": "You deployed this token"
  },
  "price": 15.0,
  "currency": "USD"
}

Not eligible:

json
{
  "success": true,
  "eligible": false,
  "reason": "not_eligible"
}

Already claimed:

json
{
  "success": true,
  "eligible": false,
  "reason": "already_claimed"
}

Response Fields

FieldTypeDescription
eligiblebooleanWhether the wallet can claim this token
reasonstringReason for ineligibility: not_eligible or already_claimed
qualificationobjectQualification details (only present when eligible)
qualification.methodstringDetected ownership method
qualification.confidencenumberConfidence score (0-1)
qualification.messagestringHuman-readable description
pricenumberClaim fee in USD (only present when eligible)
currencystringFee currency (only present when eligible)

Code Examples

bash
curl -X POST https://api.chaindaddy.io/api/v2/registration/check-qualify \
  -H "X-API-Key: cd_live_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "wallet": "0x1234567890abcdef1234567890abcdef12345678",
    "tokenAddress": "0x6982508145454ce325ddbe47a25d4ec3d2311933",
    "chainId": 42161,
    "symbol": "PEPE"
  }'
javascript
async function checkQualification(apiKey, wallet, tokenAddress, chainId, symbol) {
  const response = await fetch('https://api.chaindaddy.io/api/v2/registration/check-qualify', {
    method: 'POST',
    headers: {
      'X-API-Key': apiKey,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ wallet, tokenAddress, chainId, symbol }),
  });

  const data = await response.json();

  if (data.eligible) {
    console.log(`Eligible via ${data.qualification.method}`);
    console.log(`Claim fee: $${data.price} ${data.currency}`);
  } else {
    console.log(`Not eligible: ${data.reason}`);
  }

  return data;
}

// Usage
const result = await checkQualification(
  'cd_live_abc123...',
  '0x1234...5678',
  '0x6982...1933',
  42161,
  'PEPE'
);
python
import requests

def check_qualification(api_key, wallet, token_address, chain_id, symbol=None):
    payload = {
        "wallet": wallet,
        "tokenAddress": token_address,
        "chainId": chain_id,
    }
    if symbol:
        payload["symbol"] = symbol

    response = requests.post(
        "https://api.chaindaddy.io/api/v2/registration/check-qualify",
        headers={
            "X-API-Key": api_key,
            "Content-Type": "application/json",
        },
        json=payload,
    )
    response.raise_for_status()
    data = response.json()

    if data["eligible"]:
        print(f"Eligible via {data['qualification']['method']}")
        print(f"Claim fee: ${data['price']} {data['currency']}")
    else:
        print(f"Not eligible: {data['reason']}")

    return data

# Usage
result = check_qualification(
    "cd_live_abc123...",
    "0x1234...5678",
    "0x6982...1933",
    42161,
    "PEPE",
)

Common Recipes

QuickClaim Flow (Detect + Claim)

Detection tells you what the wallet can claim. To actually claim, run the standard claim pipeline: POST /api/v2/claim/message → sign → POST /api/v2/claim/verifyPOST /api/v2/claim (see the full claim walkthrough).

javascript
async function quickClaimFlow(apiKey, signer) {
  const walletAddress = await signer.getAddress();
  const post = (path, body) => fetch(`https://api.chaindaddy.io${path}`, {
    method: 'POST',
    headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json' },
    body: JSON.stringify(body),
  }).then(r => r.json());

  // 1. Detect claimable tokens
  const claimable = await getClaimableTokens(apiKey, walletAddress);
  if (claimable.length === 0) {
    console.log('No claimable tokens found');
    return;
  }

  // 2. Show results to user (sorted by qualification strength)
  for (const item of claimable) {
    console.log(
      `${item.symbol} on chain ${item.chainId} ` +
      `(${item.qualification.method}, confidence: ${item.qualification.confidence})`
    );
  }

  // 3. Claim the first token (user selects in UI)
  const selected = claimable[0];
  const chainId = parseInt(selected.chainId, 10);

  // 3a. Get the ownership message and sign it
  const { message, timestamp } = await post('/api/v2/claim/message', {
    symbol: selected.symbol,
    chainId,
    tokenAddress: selected.address,
    claimerAddress: walletAddress,
  });
  const signature = await signer.signMessage(message);

  // 3b. Verify ownership
  const verification = await post('/api/v2/claim/verify', {
    symbol: selected.symbol,
    chainId,
    tokenAddress: selected.address,
    walletAddress,
    signature,
    timestamp,
  });
  if (!verification.verified) throw new Error('Ownership verification failed');

  // 3c. Build the claim transaction
  const claim = await post('/api/v2/claim', {
    symbol: selected.symbol,
    chainId,
    tokenAddress: selected.address,
    walletAddress,
    proofHash: verification.proofHash,
  });

  // 4. Sign and submit
  const tx = await signer.sendTransaction(claim.transaction);
  await tx.wait();
  console.log(`Claimed ${selected.symbol} registration`);
}

Check Before Manual Claim

python
import requests

BASE_URL = "https://api.chaindaddy.io"

def claim_if_eligible(api_key, signer, token_address, chain_id, symbol):
    wallet = signer.address

    def post(path, body):
        res = requests.post(
            f"{BASE_URL}{path}",
            headers={"X-API-Key": api_key, "Content-Type": "application/json"},
            json=body,
        )
        res.raise_for_status()
        return res.json()

    # 1. Check qualification
    result = check_qualification(api_key, wallet, token_address, chain_id, symbol)

    if not result["eligible"]:
        if result["reason"] == "already_claimed":
            print(f"{symbol} is already claimed on this chain")
        else:
            print(f"Not eligible to claim {symbol}")
        return None

    print(f"Eligible via {result['qualification']['method']}")
    print(f"Fee: ${result['price']} {result['currency']}")

    # 2. Get the ownership message and sign it
    msg = post("/api/v2/claim/message", {
        "symbol": symbol, "chainId": chain_id,
        "tokenAddress": token_address, "claimerAddress": wallet,
    })
    signature = signer.sign_message(msg["message"])  # your wallet library

    # 3. Verify ownership
    verification = post("/api/v2/claim/verify", {
        "symbol": symbol, "chainId": chain_id,
        "tokenAddress": token_address, "walletAddress": wallet,
        "signature": signature, "timestamp": msg["timestamp"],
    })
    if not verification["verified"]:
        print("Ownership verification failed")
        return None

    # 4. Build the claim transaction, then sign and submit it
    claim = post("/api/v2/claim", {
        "symbol": symbol, "chainId": chain_id,
        "tokenAddress": token_address, "walletAddress": wallet,
        "proofHash": verification["proofHash"],
    })
    return signer.send_transaction(claim["transaction"])

# Usage
tx = claim_if_eligible(
    "cd_live_abc123...",
    signer,
    "0x6982...1933",
    42161,
    "PEPE",
)

Error Responses

StatusCodeDescription
400INVALID_PARAMSMissing wallet address header or invalid request body
403FORBIDDENInvalid API key or insufficient tier
429RATE_LIMITEDRate limit exceeded

Timeout

The claimable endpoint runs with a 15-second server-side timeout. Wallets with large token histories may take several seconds to resolve.

See Authentication for details on error handling and retry strategies.