Skip to content

Import a token over the API ​

Importing registers a token that was created somewhere else: a wallet proves it controls the token, and the token gets its verified page. On the site this is Import an Existing Token. This page does the same thing from code, in five calls.

You need an API key and the wallet that controls the token: the one that deployed it, owns the contract, holds a majority of the supply, or (on Solana) holds its mint or update authority. The wallet signs one transaction; nothing here needs a session. Every field of every call is in the API Explorer under Registrations.

1. Find what the wallet can import ​

bash
curl -H "X-API-Key: $CHAINDADDY_API_KEY" \
  -H "X-Wallet-Address: 0x1234567890abcdef1234567890abcdef12345678" \
  https://api.chaindaddy.io/api/v2/registration/claimable
json
{
  "tokens": [
    {
      "address": "0x6982508145454ce325ddbe47a25d4ec3d2311933",
      "chainId": "8453",
      "symbol": "MYTKN",
      "name": "My Token",
      "qualification": { "method": "deployer", "confidence": 1, "message": "You deployed this token" }
    }
  ],
  "total": 1
}

Tokens that are already registered are left out, so {"tokens": [], "total": 0} means there is nothing to import. The wallet goes in the X-Wallet-Address header on every call to this route, session or not; without it the answer is 400. A 503 means the lookup failed, not that the list is empty: retry.

This list only finds deployers and Solana authorities. A wallet that qualifies another way (contract owner, majority holder) will not see its token here, but step 2 still says yes.

2. Check one token ​

bash
curl -X POST https://api.chaindaddy.io/api/v2/registration/check-qualify \
  -H "X-API-Key: $CHAINDADDY_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "wallet": "0x1234567890abcdef1234567890abcdef12345678",
    "tokenAddress": "0x6982508145454ce325ddbe47a25d4ec3d2311933",
    "chainId": 8453,
    "symbol": "MYTKN"
  }'
json
{
  "eligible": true,
  "qualification": { "method": "deployer", "confidence": 1, "message": "You deployed this token" },
  "price": 15,
  "currency": "USD",
  "proTrialDays": 0
}

price is what importing costs; 0 means free, as it is for a token launched through Chain Daddy. When eligible is false, reason says why:

reasonMeaning
not_eligibleThe chain shows no way this wallet controls the token.
already_claimedThe token is registered. Read who holds it with GET /api/v2/registration/{symbol}/{chain}.
copycat, not_claimableThe wallet qualifies, but the token cannot be registered: it imitates an established token, or is a major coin. claimability carries the reason and a supportEmail to contest it.

Send symbol: without it an existing registration is not detected and a free import is quoted at full price.

3. Build the transaction ​

bash
curl -X POST https://api.chaindaddy.io/api/v2/claim \
  -H "X-API-Key: $CHAINDADDY_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "symbol": "MYTKN",
    "chainId": 8453,
    "tokenAddress": "0x6982508145454ce325ddbe47a25d4ec3d2311933",
    "walletAddress": "0x1234567890abcdef1234567890abcdef12345678"
  }'
json
{
  "success": true,
  "transaction": { "to": "0x…", "data": "0x…", "value": "0x2386f26fc10000", "gasLimit": 250000, "chainId": 8453 },
  "feeEstimate": { "contractFee": "0x2386f26fc10000", "gasEstimate": 250000, "gasPrice": "0x…", "totalGasCost": "0x…", "totalEstimate": "0x…" },
  "message": "Sign and submit the transaction to claim your token page"
}

The server checks ownership again here, from the chain, before it builds anything. Nothing is signed or sent for you: transaction is unsigned. value is the registration fee, paid in the chain's native coin; feeEstimate.totalEstimate adds the gas (the network's charge for running a transaction). Every amount is wei, as a hex string.

4. Sign and send it ​

Send the transaction from the same wallet, with any wallet library. With viem:

ts
const { transaction: t } = await res.json(); // res: the response from step 3
const hash = await wallet.sendTransaction({ to: t.to, data: t.data, value: BigInt(t.value) });

5. Confirm it landed ​

bash
curl -H "X-API-Key: $CHAINDADDY_API_KEY" \
  "https://api.chaindaddy.io/api/v2/claim/status/0xc1377ce582266b185e571766406924b0ba4537627692ae0dae007c2ac3aa8730?chainId=8453"
json
{ "txHash": "0xc1377ce5…8730", "status": "confirmed", "confirmations": 332408, "blockNumber": 51807835 }

status is pending, confirmed or failed. Always pass chainId: left out, the lookup reads Arbitrum and reports a transaction on any other chain as missing. Once it confirms, GET /api/v2/registration/MYTKN/base answers "status": "claimed" with your wallet as owner, and the page is live at chaindaddy.io/MYTKN.

If a step is refused ​

Errors carry a message in error and a stable code.

StatuscodeMeaning
400VALIDATION_INVALID_INPUTA field is missing, or the chain is not one tokens are registered on.
403CLAIM_UNAUTHORIZEDThe chain shows no way this wallet controls the token.
409CLAIM_DUPLICATEThe symbol is already registered on this chain.
422TOKEN_NOT_REGISTRABLEA copycat or a major coin. check names the rule.
503TOKEN_UNVERIFIEDThe token could not be checked right now. Retry shortly.

Solana ​

Steps 1 and 2 are the same, with "chainId": "solana". For step 3, POST /api/v2/claim/solana/build takes { "claimer", "symbol", "tokenMint" } and returns the unsigned transaction as base64, with the registration's account address (crownPda). Sign and send it, then read GET /api/v2/claim/solana/status/{symbol}.

Before and after ​

  • Is the ticker usable? POST /api/v2/verify/symbol with { "symbol" } answers allowed, warning (it resembles a well-known asset), og_required (only the original project may register it) or blocked.
  • Who holds a ticker? GET /registration/v2/symbol/{symbol}/all-chains lists every registration of it, one per chain. This route and GET /registration/unified/{symbol} have no /api/v2 prefix.
  • Is it healthy? GET /api/v2/heartbeat/{symbol}/{chain} returns the score that keeps a registration alive (EVM chains). See Token Health.
  • Edit the page. PUT /api/v2/registration/{id}/profile?chain=base changes the name, description, links and media. It needs a session for the owner or a manager, and chain is required because the same id names a different page on each chain. Send only the fields you are changing.

Where a path takes {chain}, use a chain key (eth, base, arbitrum, polygon, bnb, avax, robinhood, solana) or a numeric chain id.