# Chain Daddy β€” Full Documentation Generated: 2026-07-04T12:03:08.949Z --- # Alerts & Notifications URL: https://docs.chaindaddy.io/alerts/ Category: alerts # Alerts & Notifications Chain Daddy tells you when something important happens β€” your token's health changes, a holder milestone lands, someone makes an offer, or a token you hold is migrating. ## Where to find them Every notification lands in your **in-app inbox** β€” the πŸ”” **bell** at the top of Chain Daddy. It's always on and can't be switched off, so nothing is ever lost; the unread count shows on the bell. ![The bell in the top nav, with an unread count](/screenshots/notif-bell.png) Click it to open your inbox β€” search and filter past notifications by category, or hit the βš™οΈ **gear** to open your **Preferences**. ![The notification inbox β€” search, category filters, and the gear that opens Preferences](/screenshots/notif-center.png) ## Channels Choose where each alert reaches you: | Channel | What it is | |---------|-----------| | **In-app inbox** πŸ”” | Always on. Every notification lands here, with search and filters. | | **Email** βœ‰οΈ | A copy in your inbox. Add and verify an address in Preferences. | | **Browser push** πŸ“² | A pop-up even when Chain Daddy is closed. Enable per device. | | **SMS** πŸ’¬ | A text, for the most critical alerts. | | **Webhooks** πŸ”— | An automated post to your own service (creators and developers). | ::: tip Sensible defaults You don't have to configure anything. The important alerts β€” *Token at risk*, *Token inactive*, *Token lost* β€” are already on. Adjust only if you want more or less. ::: ## Turning on a channel 1. **Connect your wallet and sign in.** Your wallet is your identity β€” no username or password. The one-time **sign-in signature** moves no funds and costs no gas. 2. **Add the channels you want** in Preferences β€” verify an **email**, add a **phone** for SMS, or enable **push** (choose *Allow* when your browser asks). ![Preferences β€” add and verify an email address, and a phone number for critical SMS alerts](/screenshots/notif-channels.png) 3. **Set how things are delivered** under *Delivery Settings* β€” turn on **Quiet Hours**, pause all emails, or switch email to a once-daily **digest** at 9am. ![Delivery Settings β€” Quiet Hours, Pause All Emails, and Real-time vs Daily Digest email delivery](/screenshots/notif-delivery.png) 4. **Tune it per alert type.** Under *Notification Types*, choose which channels each alert uses β€” e.g. *Token At Risk* by Email + Push + In-App, but a *Health Reminder* in-app only. ![Notification Types β€” a per-alert-type grid of Email / Push / In-App / XMTP / SMS toggles, grouped by category](/screenshots/notif-types.png) ## What each notification means ### Your token's health | Notification | What happened | What to do | |--------------|---------------|-----------| | **Token at risk** | Health fell near the at-risk line (60%). | Post an update or engage holders β€” see [what feeds your score](/platform/heartbeat). | | **Token inactive** | Crossed into the inactive window. | Act soon β€” an inactive listing can be reclaimed. | | **Token restored** | Recovered above the danger line. | Nothing β€” you're back in good standing. | | **Token lost** | Another wallet reclaimed your listing. | See [Token Health](/platform/heartbeat) on reclaiming. | ### Community & offers | Notification | What it means | |--------------|---------------| | **Holder milestone** | Passed a holder count milestone (100, 500, 1K, 5K, 10K, 25K, 50K, 100K). | | **New holder** / **Holder drop** | A notable rise or fall in holders. | | **Purchase via profile** | Someone bought your token through your Chain Daddy page. | | **Copycat detected** | A token is impersonating your name, ticker, or logo. Review it under **Token Manager β†’ Admin β†’ Alerts**. | | **Offer received / accepted / declined** | Movement on a [deal](/creator-tools/deals) for your token. | ### Token migrations (for holders) A **migration** moves a project's holders to a new token β€” you swap old for new within a window. | Notification | What to do | |--------------|-----------| | **Migration started** | Read the terms (ratio, new token, deadline), then swap when ready. | | **Migration deadline soon** | Swap now if you haven't. | | **Migration complete** | The window has closed. | ::: warning Verify before you swap Chain Daddy shows the terms, but the swap happens through the project's own process. Always confirm on the project's official channels, and never share your seed phrase. ::: ## For holders: get notified about a token you hold You don't need to be a creator. On any token's page, connect your wallet and click **Get notified**, approve a **free signature** (no gas, no funds moved) to prove you hold it, and pick your channels. Balances are re-checked about daily, so if you sell, the messages stop. Receiving is always free. ## Creator alert setup Token owners configure these from **Token Manager β†’ Admin β†’ Alerts**; availability depends on your [plan](/pricing/plans). - **Health alerts** β€” warn you before your score reaches the at-risk line (all tiers). - **Copycat detection** β€” flag impersonators ([Pro+](/pricing/plans)). - **Holder milestones** and **purchase tracking** β€” track growth and demand ([Pro](/pricing/plans)). ### Forward alerts to Discord {#discord-alerts} Post your token's events (health changes, holder milestones) to your own Discord server via a webhook. Add it under **Token Manager β†’ Admin β†’ Alerts** and pick which events to forward β€” each posts a formatted embed. This forwards *your* events to *your* server; it's separate from the personal channels above ([Pro](/pricing/plans)). ## Managing & turning off Change channels or types, pause with quiet hours, switch to a daily digest, or unsubscribe from any email β€” all in **Preferences** (bell β†’ gear). Still stuck? See the [FAQ](/faq). --- # Analytics URL: https://docs.chaindaddy.io/analytics/ Category: analytics # Analytics Chain Daddy provides analytics at several levels, from basic token metrics visible to anyone, to detailed engagement data and programmatic access for higher tiers. --- ## Basic Analytics {#basic-analytics} Every token page displays core token metrics: current holder count, recent trading volume, and the token's [health score](#health-score). These are visible to anyone who visits the page, including non-holders. Basic analytics are available on all tiers and require no configuration. Data updates automatically based on on-chain activity. ## Health Score {#health-score} Your token's **health score** is the metric that decides whether your registration stays active. It's shown right in your token manager's **Analytics** tab β€” a single 0–100 number, updated daily β€” so you can watch it at a glance and act before it slips. ![The Analytics tab in the token manager β€” holder growth, pageviews, and the token's health score](/screenshots/auto/manager-analytics--desktop--light.png) The score blends three on-chain signals: - **Activity** (50%) β€” how recently the listing has been active (a stepped decay). - **Trading volume** (30%) β€” DEX volume, smoothed and capped against pool liquidity to filter wash trading. - **Holder health** (20%) β€” the shape of your holder distribution: concentration, suspicious wallets, and breadth. A score below 60 sustained for 30 consecutive days expires the registration and reopens the ticker for re-registration. For the full formula, thresholds, and how to keep it healthy, see [Token Health & Anti-Squatting](/platform/heartbeat). ## Profile Pageviews {#profile-pageviews} Track how many visitors view your token page over time. The pageviews dashboard shows daily, weekly, and monthly view counts along with visitor trends. Use it to measure the impact of social posts, launches, or listing announcements on page traffic. Access pageview data from **Token Manager > Analytics**. ::: tip Pro and above Profile pageview tracking is available starting at [Pro](/pricing/plans). ::: ## Token Analytics {#crown-analytics} A detailed analytics dashboard covering token page engagement beyond simple pageviews. Token analytics includes click-through rates on your social links, featured links, and gated links, plus performance data for embedded widgets (buy button, tip links, badges). Use these insights to understand what visitors interact with and optimize your token page layout accordingly. ::: tip Pro and above Token analytics is available starting at [Pro](/pricing/plans). ::: ## GA/Pixel Tracking {#ga-pixel-tracking} Connect Google Analytics, Meta Pixel, or other tracking pixels to your token page. Add your tracking ID or pixel code and Chain Daddy injects it into your public page, giving you full access to your own analytics platform for visitor behavior, attribution, and conversion tracking. ::: tip Coming Soon GA/pixel tracking is planned for Pro+ and above. Not yet available. ::: ## Embed Analytics {#embed-analytics} Track the performance of your embedded widgets, buy buttons, tip links, and holder badges, wherever they are placed. Embed analytics reports impressions, clicks, and conversions per widget and per referrer domain. Identify which external sites drive the most engagement with your embeds. ::: tip Coming Soon Embed analytics is planned for Pro+ and above. Not yet available. ::: ## Analytics API {#analytics-api} Access your analytics data programmatically via REST endpoints. Query pageviews, holder growth, embed performance, and engagement metrics in JSON format. Integrate analytics into your own dashboards, bots, or reporting tools. See the [API Reference](/api-reference/authentication) for endpoint documentation and authentication details. ::: tip Developer and above The analytics API is available starting at [Developer](/pricing/plans). ::: ## Export Data {#export-data} Download your analytics as CSV or JSON files. Export pageview history, holder growth timelines, embed performance logs, and engagement summaries. Exports are generated on demand from **Token Manager > Analytics > Export** and cover the date range you select. ::: tip Developer and above Analytics data export is available starting at [Developer](/pricing/plans). ::: ## Custom Reports {#custom-reports} ::: tip Coming Soon Custom reports are not yet available. They will be added in a future release. ::: Configure scheduled analytics reports with the metrics you care about. Choose the data points, frequency (daily, weekly, monthly), and delivery method (email or webhook). Custom reports aggregate data across all your registrations if you hold multiple, and can include holder growth, engagement trends, embed performance, and holder notification reach in a single summary. --- # Authentication URL: https://docs.chaindaddy.io/api-reference/authentication Category: api-reference # Authentication All API requests require an API key passed via the `X-API-Key` header. That key is one of three independent auth systems. This page covers the first β€” the `X-API-Key` header used by the public REST API. Developer endpoints (`/api/v2/developer/*`) instead take a Bearer credential ([session JWT or API key](/developer/runners#authenticating-to-the-developer-api)), and platform ↔ runner traffic is HMAC-signed ([Security & Auth](/developer/security)): ![Diagram of the three authentication systems: the X-API-Key header authenticates the public REST API; the developer API accepts a session JWT or a cd_live_ API key on the Authorization Bearer header; the platform and app runners sign requests to each other with HMAC in the X-App-Signature header](/diagrams/auth-landscape-light.svg){.light-only} ![Diagram of the three authentication systems: the X-API-Key header authenticates the public REST API; the developer API accepts a session JWT or a cd_live_ API key on the Authorization Bearer header; the platform and app runners sign requests to each other with HMAC in the X-App-Signature header](/diagrams/auth-landscape-dark.svg){.dark-only} ## Getting an API Key 1. Connect your wallet at [chaindaddy.io](https://chaindaddy.io) 2. Open the API dashboard at [chaindaddy.io/_api](https://chaindaddy.io/_api) 3. Click **Generate Key** 4. Copy your key immediately, it won't be shown again ::: warning Store Your Key Securely API keys grant access to your account's API quota. Never commit keys to source control or expose them in client-side code. ::: ## Key Format Keys follow the format `cd_live_` followed by 64 hexadecimal characters: ``` cd_live_a1b2c3d4e5f6... (64 hex chars) ``` ## Making Authenticated Requests Include your key in the `X-API-Key` header on every request: ::: code-group ```bash [curl] curl -H "X-API-Key: cd_live_YOUR_KEY_HERE" \ https://api.chaindaddy.io/api/v2/search?symbol=PEPE ``` ```javascript [JavaScript] const response = await fetch( 'https://api.chaindaddy.io/api/v2/search?symbol=PEPE', { headers: { 'X-API-Key': 'cd_live_YOUR_KEY_HERE' } } ); const data = await response.json(); ``` ```python [Python] import requests response = requests.get( 'https://api.chaindaddy.io/api/v2/search', params={'symbol': 'PEPE'}, headers={'X-API-Key': 'cd_live_YOUR_KEY_HERE'} ) data = response.json() ``` ::: ## Rate Limiting Each API tier has daily request limits and per-second rate limits: | Tier | Price | Requests/Day | Rate Limit | |------|-------|-------------|------------| | **Free** | $0 | 100 | 1 req/sec | | **PRO** | ${{price.subscriptionTiers.pro.monthly}}/mo | 5,000 | 5 req/sec | | **PRO+** | ${{price.subscriptionTiers.pro_plus.monthly}}/mo | 15,000 | 10 req/sec | | **Developer** | ${{price.subscriptionTiers.developer.monthly}}/mo | 50,000 | 15 req/sec | | **Partner** | ${{price.subscriptionTiers.business.monthly}}/mo | 250,000 | 50 req/sec | Free, PRO, and PRO+ limits are included with their respective [plan tiers](/pricing/plans). Developer and Partner are standalone API plans. ### API Feature Matrix Endpoint access by tier: | Feature | Free | PRO | PRO+ | Developer | Partner | |---------|------|-----|------|-----------|---------| | Search | Yes | Yes | Yes | Yes | Yes | | Token data | Yes | Yes | Yes | Yes | Yes | | Registration status | Yes | Yes | Yes | Yes | Yes | | Listing export | β€” | Yes | Yes | Yes | Yes | | Webhooks | β€” | β€” | β€” | Yes | Yes | | Bulk endpoints | β€” | β€” | β€” | Yes | Yes | | SLA guarantee | β€” | β€” | β€” | β€” | 99.9% | ::: tip Partner For custom rate limits, dedicated infrastructure, priority support, or SLA requirements, contact the team via the dashboard. ::: ### Rate Limit Headers Every response includes rate limit headers: | Header | Description | |--------|-------------| | `X-RateLimit-Limit` | Daily request limit | | `X-RateLimit-Remaining` | Remaining requests today | | `X-RateLimit-Reset` | Unix timestamp when limit resets | | `Retry-After` | Seconds to wait (only on 429 responses) | ### Handling 429 Responses When you exceed your rate limit, the API returns a `429 Too Many Requests` response: ```json { "error": "rate_limit_exceeded", "message": "Too many requests per second", "retry_after": 1 } ``` ::: tip Retry Strategy Read the `Retry-After` header and wait that many seconds before retrying. Implement exponential backoff for repeated 429 responses. ::: ::: code-group ```javascript [JavaScript] async function fetchWithRetry(url, options, maxRetries = 3) { for (let attempt = 0; attempt < maxRetries; attempt++) { const response = await fetch(url, options); if (response.status === 429) { const retryAfter = parseInt(response.headers.get('Retry-After') || '1'); await new Promise(resolve => setTimeout(resolve, retryAfter * 1000)); continue; } return response; } throw new Error('Max retries exceeded'); } ``` ```python [Python] import time import requests def fetch_with_retry(url, headers, max_retries=3): for attempt in range(max_retries): response = requests.get(url, headers=headers) if response.status_code == 429: retry_after = int(response.headers.get('Retry-After', '1')) time.sleep(retry_after) continue return response raise Exception('Max retries exceeded') ``` ::: ## Error Response Format All error responses follow a consistent JSON format: ```json { "error": "error_type", "message": "Human-readable description of what went wrong", "code": "MACHINE_READABLE_CODE" } ``` | Field | Type | Description | |-------|------|-------------| | `error` | string | Error type identifier | | `message` | string | Human-readable description | | `code` | string | Machine-readable error code (optional) | ### Common Error Codes | HTTP Status | Error | Description | |-------------|-------|-------------| | 400 | `bad_request` | Missing or invalid parameters | | 403 | `forbidden` | Invalid API key or insufficient tier | | 404 | `not_found` | Resource does not exist | | 409 | `conflict` | Symbol already claimed on this chain | | 429 | `rate_limit_exceeded` | Too many requests | ## Base URL All endpoints in this reference are served from the production API: ``` https://api.chaindaddy.io ``` There is no separate sandbox environment. For development and testing, use a Free-tier API key β€” read endpoints (search, token data, registration status) are safe to call, and write endpoints only return unsigned transaction data (nothing happens on-chain until you sign and submit). See the [API Explorer](/api-reference/explorer) to try endpoints interactively. --- # CLI URL: https://docs.chaindaddy.io/api-reference/cli Category: api-reference # CLI Reference The `@chaindaddy/cli` package provides a command-line interface for managing token registrations and publishing Crown Apps. Manage wallets, discover reclaimable registrations, create tokens, check heartbeat health, export listing data, and drive the full app build β†’ sign β†’ submit pipeline from your terminal. ## Installation ```bash npm install -g @chaindaddy/cli ``` Requires Node.js 18+. ## Global Options | Flag | Description | |------|-------------| | `--json` | Output as JSON (machine-readable, no colors). Honored when set on any parent command | | `--non-interactive` | Never prompt; fail when required input is missing (for CI and agents) | | `--version` | Display CLI version | | `--help` | Display help for any command | Environment variables: `CROWN_API_KEY` (a `cd_live_…` API key) authenticates API calls non-interactively; `CROWN_DEV_TOKEN` overrides the stored developer credential. ## Commands ### `wallet` Manage the local wallet keystore used for signing transactions. ```bash # Create a new wallet keypair (add --solana for a Solana keypair too) chaindaddy wallet init # Import an existing private key or mnemonic chaindaddy wallet import # Import a Solana keypair (base58 secret key) chaindaddy wallet import --solana # Register a Ledger hardware wallet chaindaddy wallet add-hardware --path "44'/60'/0'/0/0" # List stored wallet addresses chaindaddy wallet list ``` Wallets are encrypted and stored locally. Hardware wallet entries store only the derivation path and address. ### `discover` Find inactive registrations available to reclaim. ```bash # List inactive registrations chaindaddy discover # Filter by chain chaindaddy discover --chain arbitrum # Filter by symbol chaindaddy discover --symbol DOGE # Filter by minimum market cap chaindaddy discover --min-mcap 10000 # Limit results chaindaddy discover --limit 20 ``` | Option | Description | |--------|-------------| | `--inactive` | Show inactive registrations (default behavior) | | `--chain ` | Filter by chain identifier | | `--symbol ` | Filter by symbol name | | `--min-mcap ` | Minimum market cap in USD | | `--limit ` | Max results (default: 50) | ### `reclaim` Reclaim an inactive registration. ```bash chaindaddy reclaim ``` | Option | Description | |--------|-------------| | `--wallet
` | Wallet address to use | | `--yes` | Skip confirmation | | `--dry-run` | Simulate without broadcasting transactions | Guides you through wallet selection, fee confirmation, and transaction submission. ### `status` View heartbeat health of registrations β€” a single token, everything a wallet owns, or an at-risk scan. ```bash # Single token chaindaddy status --symbol DOGE --chain arbitrum # Resolve a registration id, then show its heartbeat chaindaddy status --crown # Every registration a wallet owns, with heartbeat chaindaddy status --wallet 0x1234... # List at-risk / inactive registrations chaindaddy status --at-risk --limit 100 ``` | Option | Description | |--------|-------------| | `--symbol ` | Token symbol (use with `--chain`) | | `--chain ` | Chain key, e.g. `arbitrum` (required with `--symbol`) | | `--crown ` | Registration/token id to resolve, then show heartbeat | | `--wallet
` | Show every registration a wallet owns | | `--at-risk` | List registrations that are at-risk or inactive | | `--limit ` | Max ids to scan with `--at-risk` (default: 100) | ### `estimate` Get pricing estimates for token creation and registration claiming. ```bash # Estimate for a single chain chaindaddy estimate --symbol DOGE --chains arbitrum # Estimate for multiple chains chaindaddy estimate --chains arbitrum,solana,base # Estimate with bundle pricing chaindaddy estimate --bundle multi-chain-3 ``` | Option | Description | |--------|-------------| | `--symbol ` | Token symbol | | `--chains ` | Target chains, comma-separated (default: `arbitrum`) | | `--bundle ` | Bundle type: `multi-chain-3`, `multi-chain-5`, `all-chain` | | `--wallet
` | Wallet address for the fee check | ### `create` Create a new token and mint its registration β€” interactive wizard, or fully flag-driven for scripting. ```bash # Interactive wizard chaindaddy create # Non-interactive chaindaddy create --symbol MTK --name "My Token" --chains arbitrum,base \ --supply 1000000000 --decimals 18 --mintable --yes # Batch mode from a JSON spec file chaindaddy create --batch tokens.json ``` | Option | Description | |--------|-------------| | `--symbol ` / `--name ` | Token symbol and name (skip prompts) | | `--chains ` | Target chains, comma-separated | | `--supply ` | Total supply (default: 1000000000) | | `--decimals ` | Decimals (default: 18) | | `--mintable` / `--burnable` | Token features | | `--wallet
` | Wallet address to use | | `--yes` | Skip confirmation (required for non-interactive) | | `--dry-run` | Simulate without broadcasting transactions | | `--batch ` | Read token specs from a JSON file | ### `profile` Manage token page profiles. ```bash # Set or update profile fields chaindaddy profile set --website https://example.com --twitter example \ --description "The example token" ``` `profile set` options: `--description`, `--category`, `--tags`, `--website`, `--twitter`, `--discord`, `--telegram`, `--logo`. A `profile view` subcommand exists but is not wired to the API yet β€” use the token page or `chaindaddy status` in the meantime. ### `listings` Prepare listing submissions for third-party aggregator platforms. ```bash # List supported platforms and their submission URLs chaindaddy listings platforms # Check how submission-ready a token is for a platform chaindaddy listings readiness --symbol DOGE --platform cmc # Build a submission template (real URL + field checklist) chaindaddy listings export --symbol DOGE --platform coingecko --out ./doge-cg.json ``` | Option | Description | |--------|-------------| | `--symbol ` | Token symbol | | `--crown ` | Registration/token id to resolve to a symbol | | `--platform ` | Platform id: `cmc`, `coingecko`, `dexscreener` (default: `cmc`) | | `--out ` | Write the template JSON to a file instead of stdout (`export` only) | ### `clone` Expand an existing token to additional chains. ```bash chaindaddy clone ``` | Option | Description | |--------|-------------| | `--supply ` / `--decimals ` | Override supply/decimals for new chains | | `--wallet
` | Wallet address | | `--yes` | Skip confirmation | | `--dry-run` | Simulate without broadcasting transactions | Shows current chain presence, available target chains, pricing breakdown, and handles the deployment transaction. ### `app` Build, sign, and submit Crown Apps (widgets and headless runners). See [Developer Getting Started](/developer/getting-started) for the full walkthrough. | Command | Description | |---------|-------------| | `app login` | Authenticate the CLI with a developer account (wallet challenge β†’ API key) | | `app whoami` | Show the active developer credentials | | `app key create` | Create a new developer API key β€” returned exactly once | | `app key list` | List your API keys | | `app key rotate ` | Create a new key and schedule the old one for expiry in 24h | | `app key revoke ` | Immediately deactivate an API key | | `app init [template] [dir]` | Scaffold a new app project: `widget`, `headless`, or `full` | | `app validate [dir]` | Validate `capp.json` against the manifest schema | | `app build [dir]` | Bundle a widget with esbuild (ESM, external react/react-dom) | | `app scan [target]` | Run the platform security/size scanner on a bundle or `.crown` package | | `app pack [dir]` | Produce a `.crown` package from the manifest, bundle, and assets | | `app sign ` | Sign a `.crown` package with your developer API key (HMAC-SHA256) | | `app verify ` | Verify a `.crown` package: structure, hashes, and (with `--check-signature`) HMAC | | `app inspect ` | Show the contents and metadata of a `.crown` package | | `app submit ` | Upload a signed `.crown` package for review (`--watch` streams the scan log) | | `app status ` | Get the current status of a submission | | `app logs ` | Fetch or stream the scan log for a submission | | `app list [apps\|submissions]` | List your apps or submissions | | `app request-publish ` | Move a pending submission to the human-review queue | | `app tokens` | List tokens you have claimed (install targets for dev preview) | | `app install ` | Install (enable) an app on one of your tokens for dev preview | | `app uninstall ` | Uninstall (disable) an app from a token | | `app preview ` | Print the URL to preview an installed app on a token page | **Exit codes** (stable, for agents and CI): `0` success, `1` user error, `2` system error, `3` validation failed, `4` auth error, `5` server error. ## Quick Start ```bash # 1. Install npm install -g @chaindaddy/cli # 2. Create a wallet chaindaddy wallet init # 3. Find reclaimable symbols chaindaddy discover --chain arbitrum # 4. Estimate costs chaindaddy estimate --symbol DOGE --chains arbitrum # 5. Create a token chaindaddy create ``` ## JSON Output All commands support `--json` for scripting and automation: ```bash # Get machine-readable output chaindaddy status --wallet 0x1234... --json | jq '.' # Use in scripts EXPIRED=$(chaindaddy discover --chain arbitrum --json | jq -r '.crowns[0].crown_id') chaindaddy reclaim "$EXPIRED" --yes ``` --- # Claimable API URL: https://docs.chaindaddy.io/api-reference/endpoints/claimable Category: api-reference # Claimable API Detect claimable token registrations for a connected wallet and check individual token eligibility. ## Endpoints | Method | Path | Description | |--------|------|-------------| | `GET` | `/api/v2/registration/claimable` | Detect all claimable registrations for a wallet | | `POST` | `/api/v2/registration/check-qualify` | Check 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 | Header | Required | Description | |--------|----------|-------------| | `X-API-Key` | Yes | API key for authentication | | `X-Wallet-Address` | Yes* | Wallet address to scan (EVM or Solana) | *If the request carries an authenticated wallet session (`Authorization: Bearer `), 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 | Chain | Chain ID | Detection Methods | |-------|----------|-------------------| | Solana | `solana` | Deployer, Mint Authority, Update Authority, Majority Holder | | Arbitrum | `42161` | Deployer, Majority Holder | | Base | `8453` | Deployer, Majority Holder | | Polygon | `137` | Deployer, Majority Holder | | BNB Chain | `56` | Deployer, Majority Holder | | Gnosis | `100` | Deployer, Majority Holder | | Ethereum | `1` | Deployer, 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 | Field | Type | Description | |-------|------|-------------| | `tokens` | array | List of tokens the wallet can claim | | `tokens[].address` | string | Token contract address | | `tokens[].chainId` | string | Chain identifier (numeric string for EVM, `solana:...` for Solana) | | `tokens[].symbol` | string | Token symbol | | `tokens[].name` | string | Token name | | `tokens[].qualification` | object | How the wallet qualifies | | `tokens[].qualification.method` | string | Qualification method (see table below) | | `tokens[].qualification.confidence` | number | Confidence score (0-1) | | `tokens[].qualification.message` | string | Human-readable explanation | | `total` | integer | Number of claimable tokens returned | The claim fee is not included per token β€” fetch it once from [`GET /api/v2/registration/fee`](/api-reference/endpoints/registrations#get-claim-fee). ### Qualification Methods Results are sorted by method priority (highest priority first): | Priority | Method | Confidence | Chains | Description | |----------|--------|------------|--------|-------------| | 1 | `deployer` | 1.0 | All | Wallet deployed the token contract | | 2 | `mint_authority` | 0.95 | Solana | Wallet is the token's mint authority | | 3 | `update_authority` | 0.9 | Solana | Wallet is the token's update authority | | 4 | `majority_holder` | 0.8 | All | Wallet holds >50% of token supply | `majority_holder` is evaluated by the live [check-qualify](#check-qualification) endpoint; the detect endpoint's provenance index currently surfaces the first three methods. ### Code Examples ::: code-group ```bash [curl] curl https://api.chaindaddy.io/api/v2/registration/claimable \ -H "X-API-Key: cd_live_abc123..." \ -H "X-Wallet-Address: 0x1234567890abcdef1234567890abcdef12345678" ``` ```javascript [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 [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 | Field | Type | Required | Description | |-------|------|----------|-------------| | `wallet` | string | Yes | Wallet address to check | | `tokenAddress` | string | Yes | Token contract address | | `chainId` | integer/string | No | Chain ID (integer for EVM, `"solana"` for Solana) | | `symbol` | string | No | Token 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 | Field | Type | Description | |-------|------|-------------| | `eligible` | boolean | Whether the wallet can claim this token | | `reason` | string | Reason for ineligibility: `not_eligible` or `already_claimed` | | `qualification` | object | Qualification details (only present when eligible) | | `qualification.method` | string | Detected ownership method | | `qualification.confidence` | number | Confidence score (0-1) | | `qualification.message` | string | Human-readable description | | `price` | number | Claim fee in USD (only present when eligible) | | `currency` | string | Fee currency (only present when eligible) | ### Code Examples ::: code-group ```bash [curl] 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 [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 [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/verify` β†’ `POST /api/v2/claim` (see the [full claim walkthrough](/api-reference/endpoints/registrations#claim-a-registration)). ::: code-group ```javascript [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 ::: code-group ```python [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 | Status | Code | Description | |--------|------|-------------| | `400` | `INVALID_PARAMS` | Missing wallet address header or invalid request body | | `403` | `FORBIDDEN` | Invalid API key or insufficient tier | | `429` | `RATE_LIMITED` | Rate limit exceeded | ::: warning 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](/api-reference/authentication) for details on error handling and retry strategies. --- # Registration API URL: https://docs.chaindaddy.io/api-reference/endpoints/registrations Category: api-reference # Registration API Look up registration status, verify ownership, claim registrations, and update token page metadata. ## Endpoints | Method | Path | Description | |--------|------|-------------| | `GET` | `/api/v2/registration/{id}` | Get registration by ID (or symbol) | | `GET` | `/api/v2/registration/{symbol}/{chain}` | Get registration status for a symbol on a chain | | `GET` | `/registration/unified/{symbol}` | Get unified registration data for a symbol *(root-level)* | | `GET` | `/registration/v2/symbol/{symbol}/all-chains` | Get all registrations for a symbol across chains *(root-level)* | | `GET` | `/registration/{id}/roles` | Get registration owner, managers, and maintainers *(root-level)* | | `GET` | `/api/v2/registry/info` | Get registry protocol info and supported chains | | `GET` | `/api/v2/registration/fee` | Get the current claim fee | | `GET` | `/api/v2/heartbeat/{symbol}/{chain}` | Get heartbeat score and activity status | | `POST` | `/api/v2/verify/symbol` | Validate a symbol before claiming | | `POST` | `/api/v2/claim/message` | Get the ownership message to sign | | `POST` | `/api/v2/claim/verify` | Verify token ownership | | `POST` | `/api/v2/claim` | Build the claim (mint) transaction | | `POST` | `/api/v2/claim/solana/build` | Build a Solana claim transaction | | `PUT` | `/api/v2/registration/{id}/profile` | Update token page profile (authenticated) | | `POST` | `/api/v2/metadata/upload` | Upload token metadata | ::: warning Three root-level routes Most endpoints live under `https://api.chaindaddy.io/api/v2/...`, but three registration lookups are served at the **root** of the API host with **no `/api/v2` prefix**: - `https://api.chaindaddy.io/registration/unified/{symbol}` - `https://api.chaindaddy.io/registration/v2/symbol/{symbol}/all-chains` - `https://api.chaindaddy.io/registration/{id}/roles` Calling these with an `/api/v2` prefix returns a different (or missing) resource. The examples below always show the full URL. ::: Chain path parameters (`{chain}`) accept a chain key (`eth`, `arbitrum`, `base`, `polygon`, `bnb`, `avax`, `gnosis`, `solana`), a common alias (`arb`, `sol`, `bsc`), or a numeric EVM chain ID. ## Get Registration by ID ``` GET /api/v2/registration/{id} ``` Retrieve registration data by its on-chain ID. The `{id}` path parameter accepts a numeric registration ID or a symbol string (resolves to the first registration for that symbol). ### Path Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `id` | string | Yes | Registration's on-chain ID (numeric) or a symbol | ### Response Format ```json { "tokenId": 123, "owner": "0x1234567890abcdef1234567890abcdef12345678", "chainId": 42161, "symbol": "DOGE", "identity": { "displayName": "Doge", "avatarUrl": "https://..." }, "tierCount": 2, "verifiedDomains": ["doge.example.com"], "metadataCid": "bafy...", "attestationCount": 3 } ``` ### Response Fields | Field | Type | Description | |-------|------|-------------| | `tokenId` | integer | Registration's on-chain ID | | `owner` | string | Registration owner wallet address | | `chainId` | integer | Chain ID where the registration exists | | `symbol` | string | Token symbol | | `identity` | object \| omitted | Display identity resolved from registration metadata | | `tierCount` | integer | Number of holder access tiers configured | | `verifiedDomains` | string[] \| omitted | DNS-verified domains linked to the registration | | `canonicalPeer` | object \| omitted | Canonical peer reference (`chainId`, `crownId`) when set | | `metadataCid` | string \| omitted | IPFS CID of the registration metadata | | `attestationCount` | integer \| omitted | Count of operator attestations | ### Code Examples ::: code-group ```bash [curl] curl -H "X-API-Key: cd_live_YOUR_KEY_HERE" \ "https://api.chaindaddy.io/api/v2/registration/123" ``` ```javascript [JavaScript] const API_KEY = 'cd_live_YOUR_KEY_HERE'; const BASE_URL = 'https://api.chaindaddy.io'; async function getRegistration(id) { const response = await fetch( `${BASE_URL}/api/v2/registration/${id}`, { headers: { 'X-API-Key': API_KEY } } ); return response.json(); } const registration = await getRegistration(123); console.log(registration.symbol, registration.owner); ``` ```python [Python] import requests API_KEY = 'cd_live_YOUR_KEY_HERE' BASE_URL = 'https://api.chaindaddy.io' def get_registration(registration_id): response = requests.get( f'{BASE_URL}/api/v2/registration/{registration_id}', headers={'X-API-Key': API_KEY} ) response.raise_for_status() return response.json() registration = get_registration(123) print(registration['symbol'], registration['owner']) ``` ::: ## Get Registration Status ``` GET /api/v2/registration/{symbol}/{chain} ``` Resolve the registration status for a symbol on a specific chain β€” the primary "is this claimed, and by whom?" lookup. ### Parameters | Parameter | Location | Type | Required | Description | |-----------|----------|------|----------|-------------| | `symbol` | path | string | Yes | Token symbol | | `chain` | path | string | Yes | Chain key (e.g. `arbitrum`) or numeric chain ID | | `tokenAddress` | query | string | No | Token contract address to scope the lookup | ### Response Returns the resolved registration status object, including `status` (`available`, `unclaimed`, `grace_period`, `claimed`, `owned`, `inactive`), `tokenId`, `owner`, heartbeat data, metadata, and `verifiedDomains` when present. The same status values are documented in the [Search API](/api-reference/endpoints/search#registration-object-json-field-crown). ```bash curl -H "X-API-Key: cd_live_YOUR_KEY_HERE" \ "https://api.chaindaddy.io/api/v2/registration/DOGE/arbitrum" ``` ## Get Unified Registration ``` GET /registration/unified/{symbol} ``` *(Root-level route β€” no `/api/v2` prefix.)* Get registration data for a symbol, abstracting whether the registration is confirmed on-chain or still pending from token creation. ### Path Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `symbol` | string | Yes | Token symbol | ### Response Format ```json { "symbol": "DOGE", "owner": "0x1234567890abcdef1234567890abcdef12345678", "tokenId": 123, "chainId": 42161, "status": "confirmed", "primaryType": "evm", "primaryClaimedAt": null, "isPending": false } ``` ### Response Fields | Field | Type | Description | |-------|------|-------------| | `symbol` | string | Token symbol | | `owner` | string | Registration owner wallet address | | `tokenId` | integer | Registration's on-chain ID | | `chainId` | integer | Chain ID of the registration | | `status` | string | Registration status: `confirmed` or `pending` | | `primaryType` | string | Primary chain type: `evm` or `solana` | | `primaryClaimedAt` | string \| null | Timestamp of initial claim | | `isPending` | boolean | Whether the registration is awaiting on-chain confirmation | ### Code Examples ::: code-group ```bash [curl] # Root-level route: no /api/v2 prefix curl -H "X-API-Key: cd_live_YOUR_KEY_HERE" \ "https://api.chaindaddy.io/registration/unified/DOGE" ``` ```javascript [JavaScript] async function getUnifiedRegistration(symbol) { // Root-level route: no /api/v2 prefix const response = await fetch( `${BASE_URL}/registration/unified/${symbol}`, { headers: { 'X-API-Key': API_KEY } } ); return response.json(); } const registration = await getUnifiedRegistration('DOGE'); console.log(registration.status, registration.isPending); ``` ```python [Python] def get_unified_registration(symbol): # Root-level route: no /api/v2 prefix response = requests.get( f'{BASE_URL}/registration/unified/{symbol}', headers={'X-API-Key': API_KEY} ) response.raise_for_status() return response.json() registration = get_unified_registration('DOGE') print(registration['status'], registration['isPending']) ``` ::: ## Get All Registrations Across Chains ``` GET /registration/v2/symbol/{symbol}/all-chains ``` *(Root-level route β€” no `/api/v2` prefix.)* Retrieve all registrations for a symbol across all supported chains, including pending ones. ### Parameters | Parameter | Location | Type | Required | Description | |-----------|----------|------|----------|-------------| | `symbol` | path | string | Yes | Token symbol | | `excludeEvm` | query | string | No | Exclude registrations owned by this EVM address | ### Response Format ```json { "symbol": "DOGE", "crowns": [ { "tokenId": 123, "owner": "0x1234567890abcdef1234567890abcdef12345678", "ownerType": "evm", "chainType": "evm", "isLinked": true, "isActive": true, "deploymentCount": 1, "primaryChainId": 42161, "isPending": false }, { "tokenId": 456, "owner": "7nYB...3kPZ", "ownerType": "solana", "chainType": "solana", "isLinked": false, "isActive": true, "deploymentCount": 1, "primaryChainId": null, "isPending": false } ] } ``` ### Response Fields #### Registration Object | Field | Type | Description | |-------|------|-------------| | `tokenId` | integer | Registration's on-chain ID | | `owner` | string | Registration owner wallet address | | `ownerType` | string | Owner wallet type: `evm` or `solana` | | `chainType` | string | Chain type: `evm` or `solana` | | `isLinked` | boolean | Whether this registration is linked to other same-symbol registrations | | `isActive` | boolean | Whether the registration is currently active | | `deploymentCount` | integer | Number of chain deployments linked | | `primaryChainId` | integer \| null | Primary chain ID (null for Solana) | | `isPending` | boolean | Whether the registration is awaiting confirmation | ### Code Examples ::: code-group ```bash [curl] # Root-level route: no /api/v2 prefix curl -H "X-API-Key: cd_live_YOUR_KEY_HERE" \ "https://api.chaindaddy.io/registration/v2/symbol/DOGE/all-chains" # Exclude a specific owner curl -H "X-API-Key: cd_live_YOUR_KEY_HERE" \ "https://api.chaindaddy.io/registration/v2/symbol/DOGE/all-chains?excludeEvm=0x1234..." ``` ```javascript [JavaScript] async function getAllRegistrations(symbol, options = {}) { const params = new URLSearchParams(options); // Root-level route: no /api/v2 prefix const url = `${BASE_URL}/registration/v2/symbol/${symbol}/all-chains?${params}`; const response = await fetch(url, { headers: { 'X-API-Key': API_KEY } }); return response.json(); } const data = await getAllRegistrations('DOGE'); console.log(`Found ${data.crowns.length} registrations across chains`); // Find linked registrations (same wallet, shared metadata) const linked = data.crowns.filter(r => r.isLinked); ``` ```python [Python] def get_all_registrations(symbol, **kwargs): # Root-level route: no /api/v2 prefix response = requests.get( f'{BASE_URL}/registration/v2/symbol/{symbol}/all-chains', params=kwargs, headers={'X-API-Key': API_KEY} ) response.raise_for_status() return response.json() data = get_all_registrations('DOGE') print(f"Found {len(data['crowns'])} registrations across chains") # Find linked registrations (same wallet, shared metadata) linked = [r for r in data['crowns'] if r['isLinked']] ``` ::: ## Get Registration Roles ``` GET /registration/{id}/roles ``` *(Root-level route β€” no `/api/v2` prefix.)* Get owner, managers, and maintainers for a registration. The `id` parameter accepts either a numeric registration ID or a symbol string. ### Path Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `id` | string | Yes | Registration ID (numeric) or symbol (string) | ### Response Format ```json { "tokenId": 123, "owner": "0x1234567890abcdef1234567890abcdef12345678", "manager": "0xabcdef1234567890abcdef1234567890abcdef12", "managers": [ "0xabcdef1234567890abcdef1234567890abcdef12" ], "maintainers": [], "isPending": false } ``` ### Response Fields | Field | Type | Description | |-------|------|-------------| | `tokenId` | integer | Registration ID | | `owner` | string | Registration owner address | | `manager` | string \| null | Primary manager address | | `managers` | string[] | All manager addresses | | `maintainers` | string[] | All maintainer addresses | | `isPending` | boolean | Whether the registration is awaiting confirmation | ### Code Examples ::: code-group ```bash [curl] # Root-level route: no /api/v2 prefix curl -H "X-API-Key: cd_live_YOUR_KEY_HERE" \ "https://api.chaindaddy.io/registration/123/roles" # By symbol curl -H "X-API-Key: cd_live_YOUR_KEY_HERE" \ "https://api.chaindaddy.io/registration/DOGE/roles" ``` ```javascript [JavaScript] async function getRegistrationRoles(id) { // Root-level route: no /api/v2 prefix const response = await fetch( `${BASE_URL}/registration/${id}/roles`, { headers: { 'X-API-Key': API_KEY } } ); return response.json(); } const roles = await getRegistrationRoles('DOGE'); console.log('Owner:', roles.owner); console.log('Manager:', roles.manager); ``` ```python [Python] def get_registration_roles(registration_id): # Root-level route: no /api/v2 prefix response = requests.get( f'{BASE_URL}/registration/{registration_id}/roles', headers={'X-API-Key': API_KEY} ) response.raise_for_status() return response.json() roles = get_registration_roles('DOGE') print('Owner:', roles['owner']) print('Manager:', roles['manager']) ``` ::: ## Get Registry Info ``` GET /api/v2/registry/info ``` Get information about the underlying registry protocol. No parameters required. Cached for 1 hour. ### Response Format ```json { "success": true, "protocol": "opencrown", "protocolVersion": "v1", "isOpenCrown": true, "supportedChains": ["eth", "arbitrum", "base", "polygon", "bnb", "avax", "gnosis", "solana"] } ``` | Field | Type | Description | |-------|------|-------------| | `protocol` | string | Registry protocol identifier (wire value) | | `protocolVersion` | string | Registry protocol version | | `supportedChains` | string[] | Chain keys the registry supports | For fee-cap data see `GET /api/v2/registry/fee-caps`; for the current claim fee use [`GET /api/v2/registration/fee`](#get-claim-fee) below. ## Get Claim Fee ``` GET /api/v2/registration/fee ``` Get the current claim fee. The fee is a flat USD amount, identical on every chain β€” payment happens on whichever chain you are claiming on. ### Response Format ```json { "baseFeeUsd": 15, "multiplier": 1, "totalFeeUsd": 15, "currency": "USD" } ``` | Field | Type | Description | |-------|------|-------------| | `baseFeeUsd` | number | Base claim fee in USD | | `multiplier` | number | Fee multiplier (currently always `1`) | | `totalFeeUsd` | number | Effective total fee in USD | | `currency` | string | Always `"USD"` | ## Get Heartbeat Status ``` GET /api/v2/heartbeat/{symbol}/{chain} ``` Get the heartbeat score and activity status for a registration. EVM chains only. ### Parameters | Parameter | Location | Type | Required | Description | |-----------|----------|------|----------|-------------| | `symbol` | path | string | Yes | Token symbol | | `chain` | path | string | Yes | Chain key (e.g. `arbitrum`) | | `tokenAddress` | query | string | No | Token contract address to scope the lookup | ### Response Format ```json { "symbol": "DOGE", "chainId": 42161, "score": 85, "status": "healthy", "lastUpdated": "2026-01-15T12:00:00Z", "components": { "timestamp": 45, "volume": 25, "holders": 15, "confidence": 1 } } ``` ### Response Fields | Field | Type | Description | |-------|------|-------------| | `symbol` | string | Token symbol | | `chainId` | integer | Chain ID | | `score` | number | Composite heartbeat score (0-100) | | `status` | string | `healthy`, `moderate`, `at_risk`, or `inactive` | | `lastUpdated` | string | ISO 8601 timestamp of the last heartbeat | | `components` | object | Score breakdown: `timestamp`, `volume`, `holders`, `confidence` | Related: `GET /api/v2/heartbeat/{symbol}/{chain}/history` returns the score history, and `GET /api/v2/heartbeat/at-risk` lists registrations currently at risk. ### Code Examples ::: code-group ```bash [curl] curl -H "X-API-Key: cd_live_YOUR_KEY_HERE" \ "https://api.chaindaddy.io/api/v2/heartbeat/DOGE/arbitrum" ``` ```javascript [JavaScript] async function getHeartbeat(symbol, chain) { const response = await fetch( `${BASE_URL}/api/v2/heartbeat/${symbol}/${chain}`, { headers: { 'X-API-Key': API_KEY } } ); return response.json(); } const heartbeat = await getHeartbeat('DOGE', 'arbitrum'); if (heartbeat.score < 60) { console.log(`Warning: ${heartbeat.symbol} is at risk (score: ${heartbeat.score})`); } ``` ```python [Python] def get_heartbeat(symbol, chain): response = requests.get( f'{BASE_URL}/api/v2/heartbeat/{symbol}/{chain}', headers={'X-API-Key': API_KEY} ) response.raise_for_status() return response.json() heartbeat = get_heartbeat('DOGE', 'arbitrum') if heartbeat['score'] < 60: print(f"Warning: {heartbeat['symbol']} is at risk (score: {heartbeat['score']})") ``` ::: ## Validate a Symbol ``` POST /api/v2/verify/symbol ``` Check whether a symbol is valid and claimable before starting a claim β€” catches format errors, blocked symbols, canonical-asset collisions, and cross-chain compatibility issues. ### Request Body | Field | Type | Required | Description | |-------|------|----------|-------------| | `symbol` | string | Yes | Symbol to validate (1-12 alphanumeric characters) | ### Response Format ```json { "success": true, "symbol": "DOGE", "status": "warning", "warningMessage": "DOGE matches a well-known asset", "requiresAcknowledgment": true, "crossChainCompatibility": { "solana": { "compatible": true }, "evm": { "compatible": true } } } ``` | Field | Type | Description | |-------|------|-------------| | `status` | string | `allowed`, `warning`, `og_required`, or `blocked` | | `blockedReason` | string \| omitted | Why the symbol is blocked (invalid length/characters, reserved) | | `canonicalAsset` | object \| omitted | Known canonical asset that matches this symbol | | `warningMessage` | string \| omitted | Human-readable warning to surface to the user | | `requiresAcknowledgment` | boolean | Whether the user must acknowledge the warning to proceed | | `requiresOgVerification` | boolean | Whether claiming requires original-project verification | | `crossChainCompatibility` | object \| omitted | Per-ecosystem compatibility (`solana`, `evm`) | ## Claim a Registration Claiming is a four-step flow: get a message to sign, sign it with the wallet, verify ownership, then build and submit the mint transaction. ![Sequence diagram of the four-step claim flow: your app requests the ownership message, has the wallet sign it, and verifies ownership to receive a proof hash; it then builds the unsigned claim transaction with the proof hash, signs and submits it on-chain, and polls the claim status endpoint with the transaction hash until the mint confirms](/diagrams/claim-flow-light.svg){.light-only} ![Sequence diagram of the four-step claim flow: your app requests the ownership message, has the wallet sign it, and verifies ownership to receive a proof hash; it then builds the unsigned claim transaction with the proof hash, signs and submits it on-chain, and polls the claim status endpoint with the transaction hash until the mint confirms](/diagrams/claim-flow-dark.svg){.dark-only} ### Step 1: Get the message to sign ``` POST /api/v2/claim/message ``` | Field | Type | Required | Description | |-------|------|----------|-------------| | `symbol` | string | Yes | Token symbol | | `chainId` | integer | Yes | Target chain ID | | `tokenAddress` | string | Yes | Token contract address | | `claimerAddress` | string | Yes | Wallet address claiming the registration | Returns `{ message, timestamp, params, feeEstimate }`. Sign `message` with the claimer wallet, and keep `timestamp` β€” you must send the same value to `/claim/verify`. ### Step 2: Verify ownership ``` POST /api/v2/claim/verify ``` | Field | Type | Required | Description | |-------|------|----------|-------------| | `symbol` | string | Yes | Token symbol | | `chainId` | integer | Yes | Target chain ID | | `tokenAddress` | string | Yes | Token contract address | | `walletAddress` | string | Yes | Wallet address claiming the registration | | `signature` | string | Yes | Signature over the message from step 1 | | `timestamp` | integer | Yes | The `timestamp` returned in step 1 | **Response:** ```json { "verified": true, "verificationMethod": "deployer", "methodsAttempted": ["deployer"], "message": "Wallet deployed the token contract", "proofHash": "0xabc...", "expiresAt": 1767312000 } ``` | Field | Type | Description | |-------|------|-------------| | `verified` | boolean | Whether ownership was verified | | `verificationMethod` | string | Method that succeeded: `deployer`, `owner`, `majorityHolder`, etc. | | `methodsAttempted` | string[] | All methods tried | | `proofHash` | string | Proof reference to pass to `/api/v2/claim` | | `expiresAt` | integer | Unix timestamp when the verification expires (24h) | ### Step 3: Build the claim transaction ``` POST /api/v2/claim ``` | Field | Type | Required | Description | |-------|------|----------|-------------| | `symbol` | string | Yes | Token symbol | | `chainId` | integer | Yes | Target chain ID (must be an enabled minting chain) | | `tokenAddress` | string | Yes | Token contract address | | `walletAddress` | string | Yes | Wallet address claiming the registration | | `proofHash` | string | Yes | Proof hash returned by `/api/v2/claim/verify` | **Response:** ```json { "success": true, "transaction": { "to": "0x1234...", "data": "0xabcdef...", "value": "10000000000000000", "chainId": 42161 }, "feeEstimate": { "gasLimit": "250000", "maxFeePerGas": "..." }, "message": "Sign and submit the transaction to claim your crown" } ``` ::: warning Unsigned transaction The response contains **unsigned** transaction data. Your application must sign and submit it with the claiming wallet to complete the mint. Returns `409` if the symbol is already claimed on that chain. ::: ### Step 4: Track the mint ``` GET /api/v2/claim/status/{txHash} ``` Poll with the submitted transaction hash until the mint confirms. ### Solana claims For Solana tokens, use the Solana pipeline instead of step 3: ``` POST /api/v2/claim/solana/build ``` Builds an unsigned Solana claim transaction. Supporting endpoints: `POST /api/v2/claim/solana/quote` (fee quote), `GET /api/v2/claim/solana/status/{symbol}` (status), `GET /api/v2/claim/methods/{chainType}` (available verification methods). ### Full Claim Flow Example ::: code-group ```javascript [JavaScript] async function claimRegistration(symbol, tokenAddress, chainId, signer) { const walletAddress = await signer.getAddress(); const post = (path, body) => fetch(`${BASE_URL}${path}`, { method: 'POST', headers: { 'X-API-Key': API_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify(body), }).then(r => r.json()); // Step 1: Get the message to sign const { message, timestamp } = await post('/api/v2/claim/message', { symbol, chainId, tokenAddress, claimerAddress: walletAddress, }); // Step 2: Sign it and verify ownership const signature = await signer.signMessage(message); const verification = await post('/api/v2/claim/verify', { symbol, chainId, tokenAddress, walletAddress, signature, timestamp, }); if (!verification.verified) { throw new Error(`Not verified: ${verification.message}`); } // Step 3: Build the claim transaction const claim = await post('/api/v2/claim', { symbol, chainId, tokenAddress, walletAddress, proofHash: verification.proofHash, }); if (!claim.success) throw new Error('Claim build failed'); // Step 4: Sign and submit on-chain const tx = await signer.sendTransaction(claim.transaction); const receipt = await tx.wait(); return { txHash: receipt.hash, success: true }; } ``` ```python [Python] import time def claim_registration(symbol, token_address, chain_id, signer): """Complete claim flow: message -> sign -> verify -> claim.""" wallet = signer.address def post(path, body): res = requests.post(f'{BASE_URL}{path}', json=body, headers={'X-API-Key': API_KEY}) res.raise_for_status() return res.json() # Step 1: Get the message to sign msg = post('/api/v2/claim/message', { 'symbol': symbol, 'chainId': chain_id, 'tokenAddress': token_address, 'claimerAddress': wallet, }) # Step 2: Sign it and verify ownership signature = signer.sign_message(msg['message']) # your wallet library 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']: raise Exception(f"Not verified: {verification.get('message')}") # Step 3: Build the claim transaction claim = post('/api/v2/claim', { 'symbol': symbol, 'chainId': chain_id, 'tokenAddress': token_address, 'walletAddress': wallet, 'proofHash': verification['proofHash'], }) # Step 4: Sign and submit on-chain tx_hash = signer.send_transaction(claim['transaction']) return {'txHash': tx_hash, 'success': True} ``` ::: ### Error Responses | Status | Error | Description | |--------|-------|-------------| | 400 | `bad_request` | Missing required fields or chain is not an enabled minting chain | | 401 | `unauthorized` | Ownership verification failed | | 409 | `conflict` | Symbol already claimed on this chain | ## Update Token Page Profile ``` PUT /api/v2/registration/{id}/profile ``` Update the token page profile for a registration. **Requires authentication** β€” a wallet session (`Authorization: Bearer ` from signing in at chaindaddy.io) belonging to the registration owner or an authorized manager, in addition to your `X-API-Key`. ### Request Body All fields are optional β€” send only what you want to change: | Field | Type | Description | |-------|------|-------------| | `name` | string | Display name | | `description` | string | Project description | | `logoUrl` / `bannerUrl` | string | Image URLs | | `website` | string | Project website URL | | `xdotcom` | string | X (Twitter) handle or URL | | `telegram` / `discord` | string | Community links | | `tags` | string[] | Freeform tags | | `anthemUrl`, `anthemLoop`, `backgroundUrl`, `backgroundMode`, `introVideoUrl`, `backgroundVideoUrl` | various | Token page media settings | Social/website fields that carry verification requirements are only persisted when a matching signed verification exists β€” unverified values are dropped silently. ## Upload Token Metadata ``` POST /api/v2/metadata/upload ``` Upload token metadata (name, symbol, chain, description, logo/banner URLs, links) for pinning. URL fields are validated against SSRF and social fields are gated by the verification records for the registration. ```bash curl -X POST \ -H "X-API-Key: cd_live_YOUR_KEY_HERE" \ -H "Content-Type: application/json" \ -d '{ "name": "Doge", "symbol": "DOGE", "chain": "arbitrum", "description": "Updated project description", "website": "https://example.com" }' \ "https://api.chaindaddy.io/api/v2/metadata/upload" ``` ## Common Recipes ### Get Registration Status for a Symbol on a Chain Determine if a registration is claimed and who owns it: ::: code-group ```javascript [JavaScript] async function getRegistrationStatus(symbol, chain) { const response = await fetch( `${BASE_URL}/api/v2/registration/${symbol}/${chain}`, { headers: { 'X-API-Key': API_KEY } } ); const record = await response.json(); return { status: record.status, owner: record.owner, tokenId: record.tokenId, }; } const status = await getRegistrationStatus('DOGE', 'arbitrum'); console.log(`Status: ${status.status}, Owner: ${status.owner}`); ``` ```python [Python] def get_registration_status(symbol, chain): """Get registration status for a symbol on a specific chain.""" record = requests.get( f'{BASE_URL}/api/v2/registration/{symbol}/{chain}', headers={'X-API-Key': API_KEY} ).json() return { 'status': record.get('status'), 'owner': record.get('owner'), 'tokenId': record.get('tokenId'), } status = get_registration_status('DOGE', 'arbitrum') print(f"Status: {status['status']}, Owner: {status['owner']}") ``` ::: ### Monitor Registration Health Check heartbeat scores and surface at-risk registrations: ::: code-group ```javascript [JavaScript] async function monitorRegistrations(entries) { // entries: [{ symbol: 'DOGE', chain: 'arbitrum' }, ...] const alerts = []; for (const { symbol, chain } of entries) { const heartbeat = await getHeartbeat(symbol, chain); if (heartbeat.score < 60) { alerts.push({ symbol, chain, score: heartbeat.score, status: heartbeat.status }); } } return alerts; } const alerts = await monitorRegistrations([ { symbol: 'DOGE', chain: 'arbitrum' }, { symbol: 'PEPE', chain: 'base' }, ]); if (alerts.length > 0) { console.log('At-risk registrations:', alerts); } ``` ```python [Python] def monitor_registrations(entries): """Check heartbeat scores for multiple (symbol, chain) pairs.""" alerts = [] for symbol, chain in entries: heartbeat = get_heartbeat(symbol, chain) if heartbeat['score'] < 60: alerts.append({ 'symbol': symbol, 'chain': chain, 'score': heartbeat['score'], 'status': heartbeat['status'], }) return alerts alerts = monitor_registrations([('DOGE', 'arbitrum'), ('PEPE', 'base')]) if alerts: print('At-risk registrations:', alerts) ``` ::: ## Error Responses | Status | Error | Description | |--------|-------|-------------| | 400 | `bad_request` | Invalid parameters or missing required fields | | 401 | `unauthorized` | Missing/invalid session for authenticated endpoints | | 403 | `forbidden` | Invalid API key, insufficient tier, or unauthorized | | 404 | `not_found` | Registration or token not found | | 409 | `conflict` | Symbol already claimed on this chain | | 429 | `rate_limit_exceeded` | Daily or per-second rate limit exceeded | See [Authentication](/api-reference/authentication) for rate limiting details and retry strategies. --- # Search API URL: https://docs.chaindaddy.io/api-reference/endpoints/search Category: api-reference # Search API Search for tokens by symbol across all supported chains. ## Endpoints | Method | Path | Description | |--------|------|-------------| | `GET` | `/api/v2/search` | Search tokens across all chains | | `GET` | `/api/v2/token/:symbol/:chain` | Get token info for a specific symbol and chain | ## Search Tokens ``` GET /api/v2/search ``` Returns token data and registration status for a symbol across all supported chains, sorted by relevance score. ### Parameters | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | `symbol` | string | Yes | β€” | Token symbol to search (1-20 alphanumeric characters) | | `chain` | string | No | `all` | Filter by chain key: `eth`, `arbitrum`, `base`, `polygon`, `bnb`, `avax`, `gnosis`, `solana` | | `status` | string | No | `all` | Filter by registration status: `available`, `unclaimed`, `claimed`, `inactive` | | `page` | integer | No | `1` | Page number for pagination | | `pageSize` | integer | No | `25` | Results per page (max 100) | | `refresh` | boolean | No | `false` | Force cache refresh for real-time data | | `expand` | boolean | No | `true` | Enable query expansion for related symbols | | `includeDeployer` | boolean | No | `false` | Include deployer wallet address in results | | `includeOwnership` | boolean | No | `false` | Include ownership verification details | ### Response Format ```json { "success": true, "symbol": "PEPE", "filters": { "chain": "all", "status": "all" }, "sort": { "field": "score", "order": "desc" }, "results": [ { "chainId": 42161, "chainName": "Arbitrum", "chainKey": "arbitrum", "chainIcon": "https://assets.chaindaddy.io/chains/arbitrum.svg", "source": "dexscreener", "sources": ["dexscreener", "coingecko"], "token": { "address": "0x6982508145454ce325ddbe47a25d4ec3d2311933", "symbol": "PEPE", "name": "Pepe", "decimals": 18, "logoUrl": "https://assets.chaindaddy.io/tokens/pepe.png", "website": "https://pepecoin.org", "twitter": "@pepecoineth", "marketCap": 1000000, "fdv": 1500000, "volume24h": 50000, "priceUsd": 0.00000123, "priceChange24h": -2.5, "liquidity": 200000, "holders": 5000 }, "crown": { "status": "claimed", "tokenId": 123, "owner": "0x1234567890abcdef1234567890abcdef12345678", "verificationMethod": "deployer" } } ], "pagination": { "total": 12, "returned": 5, "page": 1, "pageSize": 25, "totalPages": 1, "hasMore": false, "nextCursor": null }, "meta": { "totalResults": 12, "chainCounts": { "arbitrum": 3, "eth": 2, "solana": 4, "base": 2, "bnb": 1 }, "statusCounts": { "claimed": 3, "unclaimed": 7, "available": 2 }, "queryExpanded": false, "expansionQueries": [] } } ``` ### Response Fields #### Top-level | Field | Type | Description | |-------|------|-------------| | `success` | boolean | Whether the request completed | | `symbol` | string | Searched symbol (uppercased) | | `filters` | object | Applied filter parameters | | `sort` | object | Applied sort parameters | | `results` | array | Array of search results | | `pagination` | object | Pagination information | | `meta` | object | Result metadata and counts | #### Result Object | Field | Type | Description | |-------|------|-------------| | `chainId` | integer | Numeric chain ID (e.g., 42161 for Arbitrum) | | `chainName` | string | Human-readable chain name | | `chainKey` | string | Short chain identifier (e.g., `arbitrum`, `solana`) | | `chainIcon` | string | URL to chain icon asset | | `source` | string | Primary data source used | | `sources` | string[] | All data sources that contributed | #### Token Object | Field | Type | Description | |-------|------|-------------| | `address` | string | Token contract address | | `symbol` | string | Token symbol | | `name` | string | Token display name | | `nameSource` | string | Source of the token name | | `decimals` | integer | Token decimal places | | `logoUrl` | string | Token logo image URL | | `website` | string | Project website | | `twitter` | string | Twitter/X handle | | `telegram` | string | Telegram group URL | | `discord` | string | Discord invite URL | | `marketCap` | number | Market capitalization (USD) | | `fdv` | number | Fully diluted valuation (USD) | | `volume24h` | number | 24-hour trading volume (USD) | | `priceUsd` | number | Current price in USD | | `priceChange24h` | number | 24-hour price change (%) | | `liquidity` | number | Available liquidity (USD) | | `holders` | integer | Number of token holders | #### Registration Object (JSON field: `crown`) The JSON response field is named `crown` for API stability. Its contents describe the token's on-chain registration. | Field | Type | Description | |-------|------|-------------| | `status` | string | Registration status (see below) | | `tokenId` | integer \| null | Registration's on-chain ID | | `owner` | string \| null | Registration owner wallet address | | `verificationMethod` | string \| null | Method used to verify ownership | **Registration Status Values:** | Status | Meaning | |--------|---------| | `available` | No token exists on this chain | | `unclaimed` | Token exists but no registration minted | | `grace_period` | New registration in 30-day grace period | | `claimed` | Registration exists, owned by someone else | | `owned` | Factory-created token, you own it | | `inactive` | Registration exists but heartbeat below 60% | #### Pagination Object | Field | Type | Description | |-------|------|-------------| | `total` | integer | Total results matching query | | `returned` | integer | Results in this response | | `page` | integer | Current page number | | `pageSize` | integer | Results per page | | `totalPages` | integer | Total available pages | | `hasMore` | boolean | Whether more pages exist | | `nextCursor` | string \| null | Cursor for next page (if applicable) | #### Meta Object | Field | Type | Description | |-------|------|-------------| | `totalResults` | integer | Total results across all pages | | `chainCounts` | object | Result count per chain key | | `statusCounts` | object | Result count per registration status | | `queryExpanded` | boolean | Whether query expansion was used | | `expansionQueries` | string[] | Related symbols searched | ### Sorting Results are sorted by a composite relevance score: 1. **Status priority**: available β†’ unclaimed β†’ grace_period β†’ claimed β†’ owned β†’ inactive 2. **Market score**: 40% market cap + 30% volume + 30% liquidity 3. **Chain priority**: arbitrum β†’ solana β†’ polygon β†’ base β†’ bnb β†’ eth ### Code Examples ::: code-group ```bash [curl] # Basic search curl -H "X-API-Key: cd_live_YOUR_KEY_HERE" \ "https://api.chaindaddy.io/api/v2/search?symbol=PEPE" # With filters and pagination curl -H "X-API-Key: cd_live_YOUR_KEY_HERE" \ "https://api.chaindaddy.io/api/v2/search?symbol=DOGE&chain=arbitrum&status=unclaimed&page=1&pageSize=10" # Force refresh with deployer info curl -H "X-API-Key: cd_live_YOUR_KEY_HERE" \ "https://api.chaindaddy.io/api/v2/search?symbol=PEPE&refresh=true&includeDeployer=true" ``` ```javascript [JavaScript] const API_KEY = 'cd_live_YOUR_KEY_HERE'; const BASE_URL = 'https://api.chaindaddy.io'; async function searchTokens(symbol, options = {}) { const params = new URLSearchParams({ symbol, ...options }); const response = await fetch(`${BASE_URL}/api/v2/search?${params}`, { headers: { 'X-API-Key': API_KEY } }); return response.json(); } // Basic search const results = await searchTokens('PEPE'); console.log(`Found ${results.pagination.total} results`); // Filtered search const arbResults = await searchTokens('DOGE', { chain: 'arbitrum', status: 'unclaimed', pageSize: '10' }); ``` ```python [Python] import requests API_KEY = 'cd_live_YOUR_KEY_HERE' BASE_URL = 'https://api.chaindaddy.io' def search_tokens(symbol, **kwargs): params = {'symbol': symbol, **kwargs} response = requests.get( f'{BASE_URL}/api/v2/search', params=params, headers={'X-API-Key': API_KEY} ) response.raise_for_status() return response.json() # Basic search results = search_tokens('PEPE') print(f"Found {results['pagination']['total']} results") # Filtered search arb_results = search_tokens('DOGE', chain='arbitrum', status='unclaimed', pageSize=10) ``` ::: ## Get Token by Symbol and Chain ``` GET /api/v2/token/:symbol/:chain ``` Returns detailed token and registration information for a specific symbol on a specific chain. ### Path Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `symbol` | string | Yes | Token symbol | | `chain` | string | Yes | Chain key: `eth`, `arbitrum`, `base`, `polygon`, `bnb`, `avax`, `gnosis`, `solana` | ### Response Format ```json { "success": true, "chainId": 42161, "chainName": "Arbitrum", "token": { "address": "0x6982508145454ce325ddbe47a25d4ec3d2311933", "symbol": "PEPE", "name": "Pepe", "decimals": 18, "marketCap": 1000000, "volume24h": 50000, "priceUsd": 0.00000123, "liquidity": 200000, "holders": 5000 }, "crown": { "status": "claimed", "tokenId": 123, "owner": "0x1234567890abcdef1234567890abcdef12345678", "verificationMethod": "deployer" } } ``` ### Code Examples ::: code-group ```bash [curl] curl -H "X-API-Key: cd_live_YOUR_KEY_HERE" \ "https://api.chaindaddy.io/api/v2/token/PEPE/arbitrum" ``` ```javascript [JavaScript] async function getToken(symbol, chain) { const response = await fetch( `${BASE_URL}/api/v2/token/${symbol}/${chain}`, { headers: { 'X-API-Key': API_KEY } } ); return response.json(); } const token = await getToken('PEPE', 'arbitrum'); console.log(token.crown.status); // "claimed" ``` ```python [Python] def get_token(symbol, chain): response = requests.get( f'{BASE_URL}/api/v2/token/{symbol}/{chain}', headers={'X-API-Key': API_KEY} ) response.raise_for_status() return response.json() token = get_token('PEPE', 'arbitrum') print(token['crown']['status']) # "claimed" ``` ::: ## Common Recipes ### Check if a Symbol is Available Determine whether a symbol has an unclaimed registration on a specific chain: ::: code-group ```javascript [JavaScript] async function isSymbolAvailable(symbol, chain) { const data = await searchTokens(symbol, { chain }); const result = data.results.find(r => r.chainKey === chain); if (!result) return true; // No token on this chain return result.crown.status === 'available' || result.crown.status === 'unclaimed'; } const available = await isSymbolAvailable('MYDOGE', 'arbitrum'); if (available) { console.log('Symbol is available to claim!'); } ``` ```python [Python] def is_symbol_available(symbol, chain): data = search_tokens(symbol, chain=chain) results = [r for r in data['results'] if r['chainKey'] == chain] if not results: return True # No token on this chain return results[0]['crown']['status'] in ('available', 'unclaimed') if is_symbol_available('MYDOGE', 'arbitrum'): print('Symbol is available to claim!') ``` ::: ### Paginate Through All Results Iterate through all search results page by page: ::: code-group ```javascript [JavaScript] async function getAllResults(symbol) { const allResults = []; let page = 1; while (true) { const data = await searchTokens(symbol, { page: String(page), pageSize: '100' }); allResults.push(...data.results); if (!data.pagination.hasMore) break; page++; } return allResults; } ``` ```python [Python] def get_all_results(symbol): all_results = [] page = 1 while True: data = search_tokens(symbol, page=page, pageSize=100) all_results.extend(data['results']) if not data['pagination']['hasMore']: break page += 1 return all_results ``` ::: ### Filter by Registration Status Find all unclaimed tokens for a symbol to identify claiming opportunities: ::: code-group ```javascript [JavaScript] async function findClaimableTokens(symbol) { const data = await searchTokens(symbol, { status: 'unclaimed' }); return data.results.map(r => ({ chain: r.chainName, address: r.token.address, marketCap: r.token.marketCap, holders: r.token.holders })); } ``` ```python [Python] def find_claimable_tokens(symbol): data = search_tokens(symbol, status='unclaimed') return [{ 'chain': r['chainName'], 'address': r['token']['address'], 'market_cap': r['token']['marketCap'], 'holders': r['token']['holders'] } for r in data['results']] ``` ::: ## Error Responses | Status | Error | Description | |--------|-------|-------------| | 400 | `bad_request` | Missing `symbol` parameter or invalid length (1-20 chars) | | 429 | `rate_limit_exceeded` | Daily or per-second rate limit exceeded | See [Authentication](/api-reference/authentication) for rate limiting details and retry strategies. --- # Tokens API URL: https://docs.chaindaddy.io/api-reference/endpoints/tokens Category: api-reference # Token API Create tokens, export listing data, and access the verified Token List. ## Endpoints | Method | Path | Description | |--------|------|-------------| | `POST` | `/api/v2/factory/create` | Build token-creation transactions via the factory | | `POST` | `/api/v2/tokens/deploy` | Validate a token deployment order before checkout | | `GET` | `/api/v2/tokenlist` | Get verified tokens in Token List format | | `GET` | `/api/v2/tokenlist/export/{symbol}/{chain}` | Export listing data for a symbol on a chain | | `GET` | `/api/v2/config/fees` | Get the current fee schedule | | `GET` | `/api/v2/registration/fee` | Get the flat claim fee | ## Create Token ``` POST /api/v2/factory/create ``` Build unsigned token-creation transactions via the factory contract β€” one transaction per requested chain. Full supply is sent to the creator wallet. Your application signs and submits each transaction. ### Request Body | Field | Type | Required | Description | |-------|------|----------|-------------| | `symbol` | string | Yes | Token symbol | | `chains` | array | Yes | Target chains: `[{ "chainId": 42161, "chainName": "Arbitrum" }]` | | `creatorAddress` | string | Yes | Creator wallet address (receives full supply) | | `supply` | string | Yes | Total supply | | `decimals` | integer | No | Token decimals (default: 18) | | `mintable` | boolean | No | Allow future minting | | `burnable` | boolean | No | Allow burning | | `renounceAtLaunch` | boolean | No | Renounce ownership at launch | | `maxSupply` | string | No | Max supply cap (for mintable tokens) | | `metadata` | object | No | `{ name, logoUrl, bannerUrl, description }` | | `liquidityPercent` | integer | No | 1-100, % of supply for LP (atomic create+liquidity flow) | | `nativeAmount` | string | No | Native amount (wei string) for liquidity, required with `liquidityPercent` | | `lockDuration` | integer | No | Unix timestamp for LP unlock (requires liquidity fields) | ### Response Format ```json { "success": true, "transactions": [ { "chainId": 42161, "chainName": "Arbitrum", "transaction": { "to": "0x...", "data": "0x...", "value": "10000000000000000" }, "feeEstimate": { "gasLimit": "250000" } } ] } ``` | Field | Type | Description | |-------|------|-------------| | `success` | boolean | Whether the request was processed successfully | | `transactions` | array | One entry per requested chain | | `transactions[].transaction` | object | Unsigned transaction data to sign and submit | | `transactions[].feeEstimate` | object | Estimated gas/fees for the transaction | | `transactions[].error` | string | Per-chain build error, if any | ### Code Examples ::: code-group ```bash [curl] curl -X POST https://api.chaindaddy.io/api/v2/factory/create \ -H "X-API-Key: cd_live_abc123..." \ -H "Content-Type: application/json" \ -d '{ "symbol": "MTK", "chains": [{ "chainId": 42161, "chainName": "Arbitrum" }], "creatorAddress": "0x1234...5678", "supply": "1000000000", "decimals": 18, "metadata": { "name": "My Token" } }' ``` ```javascript [JavaScript] const API_KEY = 'cd_live_abc123...'; const BASE_URL = 'https://api.chaindaddy.io'; async function createToken(tokenConfig) { const response = await fetch(`${BASE_URL}/api/v2/factory/create`, { method: 'POST', headers: { 'X-API-Key': API_KEY, 'Content-Type': 'application/json', }, body: JSON.stringify(tokenConfig), }); const data = await response.json(); if (!data.success) throw new Error(data.error); // Sign and submit each per-chain transaction for (const entry of data.transactions) { if (entry.error) { console.error(entry.chainName, entry.error); continue; } const tx = await wallet.sendTransaction(entry.transaction); await tx.wait(); } return data; } await createToken({ symbol: 'MTK', chains: [{ chainId: 42161, chainName: 'Arbitrum' }], creatorAddress: '0x1234...5678', supply: '1000000000', decimals: 18, metadata: { name: 'My Token' }, }); ``` ```python [Python] import requests API_KEY = 'cd_live_abc123...' BASE_URL = 'https://api.chaindaddy.io' def create_token(token_config): response = requests.post( f"{BASE_URL}/api/v2/factory/create", headers={ "X-API-Key": API_KEY, "Content-Type": "application/json", }, json=token_config, ) response.raise_for_status() return response.json() result = create_token({ "symbol": "MTK", "chains": [{"chainId": 42161, "chainName": "Arbitrum"}], "creatorAddress": "0x1234...5678", "supply": "1000000000", "decimals": 18, "metadata": {"name": "My Token"}, }) print(f"Transactions to sign: {result['transactions']}") ``` ::: ::: warning Symbol Conflicts If the symbol is already claimed on a target chain, that chain's entry fails. Use the [Search API](/api-reference/endpoints/search) to check availability first. ::: --- ## Validate a Deployment Order ``` POST /api/v2/tokens/deploy ``` Validate a token deployment order (symbol format, name, chain support, supply/decimals bounds) before checkout. This endpoint validates only β€” it does not deploy anything. ### Request Body | Field | Type | Required | Description | |-------|------|----------|-------------| | `name` | string | Yes | Token name | | `symbol` | string | Yes | Token symbol (1-10 uppercase alphanumeric characters) | | `chain` | string | Yes | Target chain key (e.g. `arbitrum`) | | `supply` | integer | Yes | Total supply | | `decimals` | integer | Yes | Token decimals | | `mintable` | boolean | No | Allow future minting | | `burnable` | boolean | No | Allow burning | | `wallet_address` | string | Yes | Creator wallet address | ### Response Format ```json { "valid": true, "order_action": { "type": "token_create", "chain": "arbitrum" } } ``` | Field | Type | Description | |-------|------|-------------| | `valid` | boolean | Whether the order passes validation | | `order_action` | object | Normalized order action for the checkout pipeline | | `errors` | string[] | Validation errors, when `valid` is `false` | --- ## Export Listing Data ``` GET /api/v2/tokenlist/export/{symbol}/{chain} ``` Export registration/token metadata for listing applications. Requires a PRO subscription or higher (see the [API feature matrix](/api-reference/authentication#api-feature-matrix)). ### Parameters | Parameter | Location | Type | Required | Default | Description | |-----------|----------|------|----------|---------|-------------| | `symbol` | path | string | Yes | β€” | Token symbol | | `chain` | path | string | Yes | β€” | Chain key (e.g. `arbitrum`) | | `format` | query | string | No | `json` | Export format hint echoed in the response | Platform-specific formats have dedicated endpoints: | Method | Path | Format | |--------|------|--------| | `GET` | `/api/v2/tokenlist/cmc/{symbol}/{chain}` | CoinMarketCap listing format | | `GET` | `/api/v2/tokenlist/gecko/{symbol}/{chain}` | CoinGecko listing format | | `GET` | `/api/v2/tokenlist/dexscreener/{symbol}/{chain}` | DexScreener format | ### Response Format ```json { "symbol": "PEPE", "chain": "arbitrum", "format": "json", "data": { "name": "PEPE Token", "symbol": "PEPE", "description": "", "website": "", "twitter": "", "telegram": "", "discord": "", "logo": "", "contractAddress": "", "chainId": 42161 }, "extensions": { "verified": true, "crownId": 42 } } ``` | Field | Type | Description | |-------|------|-------------| | `data` | object | Listing metadata resolved from the registration | | `extensions.verified` | boolean | Whether an active registration backs this token | | `extensions.crownId` | integer | Registration ID when verified | ### Code Examples ::: code-group ```bash [curl] # Default JSON format curl "https://api.chaindaddy.io/api/v2/tokenlist/export/PEPE/arbitrum" \ -H "X-API-Key: cd_live_abc123..." # CoinMarketCap-specific format curl "https://api.chaindaddy.io/api/v2/tokenlist/cmc/PEPE/arbitrum" \ -H "X-API-Key: cd_live_abc123..." ``` ```javascript [JavaScript] async function exportListing(symbol, chain, format = 'json') { const url = new URL( `https://api.chaindaddy.io/api/v2/tokenlist/export/${symbol}/${chain}` ); url.searchParams.set('format', format); const response = await fetch(url, { headers: { 'X-API-Key': API_KEY }, }); if (!response.ok) throw new Error(`Export failed: ${response.status}`); return response.json(); } const listing = await exportListing('PEPE', 'arbitrum'); console.log(listing.extensions.verified); ``` ```python [Python] def export_listing(symbol, chain, fmt="json"): response = requests.get( f"{BASE_URL}/api/v2/tokenlist/export/{symbol}/{chain}", headers={"X-API-Key": API_KEY}, params={"format": fmt}, ) response.raise_for_status() return response.json() listing = export_listing("PEPE", "arbitrum") print(f"Verified: {listing['extensions']['verified']}") ``` ::: For guided, submission-ready templates (real submission URLs + field checklists per aggregator), use the [CLI](/api-reference/cli#listings): `chaindaddy listings export --symbol PEPE --platform cmc`. --- ## Token List ``` GET /api/v2/tokenlist ``` Returns verified token registrations in the Token List standard format for wallet and DEX auto-ingestion. ### Parameters | Parameter | Location | Type | Required | Description | |-----------|----------|------|----------|-------------| | `chainId` | query | integer | No | Filter to a single chain ID | | `symbol` | query | string | No | Filter to specific symbols (repeatable) | ### Response Format ```json { "name": "Verified Tokens", "timestamp": "2026-01-23T00:00:00.000Z", "version": { "major": 1, "minor": 0, "patch": 0 }, "keywords": ["verified", "crown", "registry"], "tokens": [ { "chainId": 42161, "address": "0x6982508145454ce325ddbe47a25d4ec3d2311933", "name": "Pepe", "symbol": "PEPE", "decimals": 18, "logoURI": "https://example.com/logo.png", "extensions": { "crownId": 42 } } ] } ``` | Field | Type | Description | |-------|------|-------------| | `name` | string | List name | | `timestamp` | string | Last update time (ISO 8601) | | `version` | object | Semantic version (`major.minor.patch`) | | `keywords` | string[] | List tags | | `tokens` | array | Array of token entries (Token List standard fields + `extensions`) | Related: `GET /api/v2/tokenlist/address/{address}` scopes the list to tokens owned by a wallet. ### Code Examples ::: code-group ```bash [curl] # Full list curl -H "X-API-Key: cd_live_abc123..." \ "https://api.chaindaddy.io/api/v2/tokenlist" # Arbitrum only curl -H "X-API-Key: cd_live_abc123..." \ "https://api.chaindaddy.io/api/v2/tokenlist?chainId=42161" ``` ```javascript [JavaScript] async function getTokenList(chainId) { const url = new URL('https://api.chaindaddy.io/api/v2/tokenlist'); if (chainId) url.searchParams.set('chainId', String(chainId)); const response = await fetch(url, { headers: { 'X-API-Key': API_KEY } }); const list = await response.json(); console.log(`${list.tokens.length} verified tokens`); return list.tokens; } const arbTokens = await getTokenList(42161); ``` ```python [Python] def get_token_list(chain_id=None): params = {"chainId": chain_id} if chain_id else {} response = requests.get( f"{BASE_URL}/api/v2/tokenlist", headers={"X-API-Key": API_KEY}, params=params, ) response.raise_for_status() return response.json()["tokens"] arb_tokens = get_token_list(chain_id=42161) print(f"Found {len(arb_tokens)} Arbitrum tokens") ``` ::: --- ## Get Fees ``` GET /api/v2/config/fees ``` Returns the current fee schedule for platform operations, driven by live pricing config. ### Response Format ```json { "crownFee": 15, "createFee": 5, "whaleMultiplier": 1, "linkPrice": 10, "expiredClaimPrice": 25, "bundles": { "duo": { "chains": 2, "price": 36, "savings": 4 }, "tri": { "chains": 3, "price": 54, "savings": 6 }, "quad": { "chains": 4, "price": 72, "savings": 8 }, "allChain": { "chains": 5, "price": 90, "savings": 10 }, "allChainEth": { "chains": 6, "price": 175, "savings": 25 } }, "subscriptionTiers": { "pro": { "monthly": 5, "yearly": 47.88 } } } ``` | Field | Type | Description | |-------|------|-------------| | `crownFee` | number | Registration claim fee (USD) | | `createFee` | number | Per-chain token creation fee (USD) | | `linkPrice` | number | Legacy field β€” cross-chain linking is automatic and free, nothing is charged. See [Cross-Chain Linking](/token/cross-chain) | | `expiredClaimPrice` | number | Fee to reclaim an expired registration (USD) | | `bundles` | object | Multi-chain bundle pricing: each entry has `chains`, `price`, `savings` | | `subscriptionTiers` | object | Monthly/yearly USD price per plan tier | ::: tip Don't hardcode prices Values come from live pricing config and change over time β€” always read this endpoint (it is cached for 5 minutes) or see the [pricing docs](/pricing/plans) rather than hardcoding amounts. For the flat claim fee alone, `GET /api/v2/registration/fee` returns `{ baseFeeUsd, multiplier, totalFeeUsd, currency }`. ::: --- ## Common Recipes ### Create a Token and Check Status ::: code-group ```javascript [JavaScript] async function createAndMonitor(config) { const chain = 'arbitrum'; // 1. Check if symbol is available const search = await fetch( `${BASE_URL}/api/v2/search?symbol=${config.symbol}&chain=${chain}`, { headers: { 'X-API-Key': API_KEY } } ); const searchData = await search.json(); const existing = searchData.results.find(r => r.crown?.status === 'claimed'); if (existing) throw new Error('Symbol already claimed on this chain'); // 2. Build the creation transaction(s) const create = await fetch(`${BASE_URL}/api/v2/factory/create`, { method: 'POST', headers: { 'X-API-Key': API_KEY, 'Content-Type': 'application/json', }, body: JSON.stringify({ symbol: config.symbol, chains: [{ chainId: 42161, chainName: 'Arbitrum' }], creatorAddress: config.creatorAddress, supply: config.supply, metadata: { name: config.name }, }), }); const { transactions } = await create.json(); // 3. Sign and submit const tx = await wallet.sendTransaction(transactions[0].transaction); await tx.wait(); // 4. Verify via Token List const list = await fetch(`${BASE_URL}/api/v2/tokenlist?chainId=42161`, { headers: { 'X-API-Key': API_KEY }, }); const { tokens } = await list.json(); const found = tokens.find(t => t.symbol === config.symbol); console.log(found ? 'Listed in Token List' : 'Pending β€” list refreshes periodically'); } ``` ::: ### Export Listing Data for Multiple Platforms ::: code-group ```python [Python] import requests import json def export_all_formats(symbol, chain): endpoints = { "json": f"{BASE_URL}/api/v2/tokenlist/export/{symbol}/{chain}", "cmc": f"{BASE_URL}/api/v2/tokenlist/cmc/{symbol}/{chain}", "gecko": f"{BASE_URL}/api/v2/tokenlist/gecko/{symbol}/{chain}", "dexscreener": f"{BASE_URL}/api/v2/tokenlist/dexscreener/{symbol}/{chain}", } exports = {} for fmt, url in endpoints.items(): response = requests.get(url, headers={"X-API-Key": API_KEY}) if response.ok: exports[fmt] = response.json() with open(f"{symbol}_{fmt}.json", "w") as f: json.dump(response.json(), f, indent=2) return exports exports = export_all_formats("PEPE", "arbitrum") print(f"Exported {len(exports)} formats") ``` ::: --- ## Error Responses | Status | Code | Description | |--------|------|-------------| | `400` | `INVALID_PARAMS` | Missing or invalid request parameters | | `403` | `FORBIDDEN` | Invalid API key, insufficient tier, or missing PRO subscription (export) | | `404` | `NOT_FOUND` | Symbol not found (export only) | | `409` | `ALREADY_CLAIMED` | Symbol already claimed on target chain | | `429` | `RATE_LIMITED` | Rate limit exceeded | See [Authentication](/api-reference/authentication) for details on error handling and retry strategies. --- # API Explorer URL: https://docs.chaindaddy.io/api-reference/explorer Category: api-reference # API Explorer Interactive API reference powered by the OpenAPI 3.0 specification. Use **Try It Out** to make live requests against the production API at `https://api.chaindaddy.io`. ## Authentication To test authenticated endpoints, click the **Authorize** button and enter your API key in the format: ``` cd_live_your_api_key_here ``` Get a key from the [API dashboard](https://chaindaddy.io/_api). See [Authentication](/api-reference/authentication) for key format and tiers. ::: warning Live Requests There is no sandbox β€” requests made here run against production and count toward your API key's daily quota and rate limit. Read endpoints are safe to try; write endpoints only return unsigned transaction data, so nothing happens on-chain until you sign and submit it yourself. ::: --- # SDKs URL: https://docs.chaindaddy.io/api-reference/sdks Category: api-reference # SDKs **The REST API is the primary integration surface.** It works from any language, and everything in this documentation β€” search, registration status, claims, token creation, webhooks β€” is expressed as plain HTTPS endpoints with API-key authentication. ::: warning No `@chaindaddy/sdk` package Earlier drafts of these docs described `@chaindaddy/sdk` (JavaScript), `chaindaddy` (Python), and a Go client. Those packages do not exist β€” do not `npm install` or `pip install` them. Use the REST API below, the [CLI](/api-reference/cli) for shell/CI workflows, or the TypeScript SDK once it reaches public release. ::: ## TypeScript SDK (beta) An official TypeScript SDK exists and is currently **in beta while it is being rebranded** β€” the package name and install instructions will be published with the public release. It wraps the protocol read surface with typed helpers: | Capability | What it does | |------------|--------------| | `search(...)` | Search symbols across chains | | `getCrown(...)` | Fetch a registration by id | | `getSymbol(...)` | Resolve a symbol's registration state | | `getTokenList(...)` | Fetch the verified Token List | | `getDeal(...)` / `getDealsForCrown(...)` | Read ownership-transfer deals | | `createEvmProvider(...)` | Construct an EVM provider wired to supported chains | Want early access? Join the developer beta at [chaindaddy.io/_developer](https://chaindaddy.io/_developer). ## Using the REST API directly Grab an API key from the [API dashboard](https://chaindaddy.io/_api), send it in the `X-API-Key` header, and call `https://api.chaindaddy.io`. Full endpoint documentation: [Search](/api-reference/endpoints/search), [Registrations](/api-reference/endpoints/registrations), [Tokens](/api-reference/endpoints/tokens), [Claimable](/api-reference/endpoints/claimable), [Webhooks](/api-reference/webhooks). ### Minimal typed client (TypeScript) ```typescript const BASE_URL = 'https://api.chaindaddy.io'; const API_KEY = process.env.CHAINDADDY_API_KEY!; async function api(path: string, init: RequestInit = {}): Promise { const res = await fetch(`${BASE_URL}${path}`, { ...init, headers: { 'X-API-Key': API_KEY, 'Content-Type': 'application/json', ...init.headers, }, }); if (res.status === 429) { const retryAfter = parseInt(res.headers.get('Retry-After') ?? '1', 10); await new Promise((r) => setTimeout(r, retryAfter * 1000)); return api(path, init); } if (!res.ok) throw new Error(`API error ${res.status}: ${await res.text()}`); return res.json() as Promise; } // Search a symbol across chains const results = await api<{ results: any[] }>('/api/v2/search?symbol=DOGE&chain=arbitrum'); // Registration status for a symbol on a chain const status = await api('/api/v2/registration/DOGE/arbitrum'); // Heartbeat health const heartbeat = await api('/api/v2/heartbeat/DOGE/arbitrum'); ``` ### Python ```python import os import time import requests BASE_URL = "https://api.chaindaddy.io" SESSION = requests.Session() SESSION.headers.update({"X-API-Key": os.environ["CHAINDADDY_API_KEY"]}) def api(path, **kwargs): while True: res = SESSION.request(kwargs.pop("method", "GET"), f"{BASE_URL}{path}", **kwargs) if res.status_code == 429: time.sleep(int(res.headers.get("Retry-After", "1"))) continue res.raise_for_status() return res.json() results = api("/api/v2/search", params={"symbol": "DOGE", "chain": "arbitrum"}) status = api("/api/v2/registration/DOGE/arbitrum") heartbeat = api("/api/v2/heartbeat/DOGE/arbitrum") ``` ### Other languages Any HTTP client works β€” there are no language-specific requirements beyond: 1. Send `X-API-Key: cd_live_…` on every request 2. Honor `Retry-After` on `429` responses (see [rate limiting](/api-reference/authentication#rate-limiting)) 3. Treat write endpoints as transaction builders: they return **unsigned transaction data** that you sign and broadcast with your own wallet/RPC tooling ## Common Patterns ### Check symbol availability ```typescript const data = await api<{ results: any[] }>( '/api/v2/search?symbol=MYNEWTOKEN&chain=arbitrum' ); const onChain = data.results.find((r) => r.chainKey === 'arbitrum'); const isAvailable = !onChain || ['available', 'unclaimed'].includes(onChain.crown.status); ``` ### Monitor registration health ```typescript const hb = await api<{ score: number; status: string }>( '/api/v2/heartbeat/DOGE/arbitrum' ); if (hb.score < 60) { console.log(`DOGE on arbitrum is at risk (score: ${hb.score})`); } ``` ### Claim a registration The claim pipeline is a four-step REST flow (message β†’ sign β†’ verify β†’ claim) β€” see the [full walkthrough](/api-reference/endpoints/registrations#claim-a-registration) in the Registration API reference. ## Shell / CI For scripts and CI pipelines, prefer the [CLI](/api-reference/cli) β€” it wraps the same REST API with wallet management, `--json` output, and stable exit codes: ```bash npm install -g @chaindaddy/cli chaindaddy status --symbol DOGE --chain arbitrum --json ``` --- # Webhooks URL: https://docs.chaindaddy.io/api-reference/webhooks Category: api-reference # Webhooks Receive real-time notifications when token events occur. Webhooks push event data to your server as they happen, eliminating the need to poll for changes. ::: tip Developer+ Tier Required Webhooks are available on the Developer and Partner tiers. See [Authentication](/api-reference/authentication#rate-limiting) for the full tier matrix. ::: A delivery in one picture β€” see [Retry Policy](#retry-policy) for the details: ![Sequence diagram of webhook delivery: the dispatcher POSTs the event payload with X-Webhook headers to your HTTPS endpoint; a 2xx response within 5 seconds acknowledges delivery; failures are retried after 1 minute, 5 minutes, 30 minutes, 2 hours, and 12 hours, after which the delivery is marked exhausted; 3 consecutive failed deliveries auto-disable the webhook](/diagrams/webhook-delivery-light.svg){.light-only} ![Sequence diagram of webhook delivery: the dispatcher POSTs the event payload with X-Webhook headers to your HTTPS endpoint; a 2xx response within 5 seconds acknowledges delivery; failures are retried after 1 minute, 5 minutes, 30 minutes, 2 hours, and 12 hours, after which the delivery is marked exhausted; 3 consecutive failed deliveries auto-disable the webhook](/diagrams/webhook-delivery-dark.svg){.dark-only} ## Events ### Registration Events | Event | Description | |-------|-------------| | `token.minted` | A new token registration has been claimed for a symbol on a chain | | `token.released` | A token owner has voluntarily released their registration | | `token.expired` | A registration has expired due to inactivity and is now claimable | ### Heartbeat Events | Event | Description | |-------|-------------| | `heartbeat.warning` | Token heartbeat score dropped below warning threshold | | `heartbeat.critical` | Token heartbeat score reached critical level | | `heartbeat.recovered` | Token heartbeat score recovered to healthy level | | `heartbeat.change` | Token heartbeat status transitioned (e.g. healthy β†’ warning) | ### Holder & Trading Events | Event | Description | |-------|-------------| | `holder.new` | A new significant holder detected for a token | | `trade.large` | A large trade occurred (>5% volume or >$10k) | | `concentration.alert` | A single wallet's token concentration exceeded threshold | | `milestone.reached` | Token reached a holder count milestone | ### Alert Events | Event | Description | |-------|-------------| | `alert.triggered` | A health alert has fired | | `alert.acknowledged` | An alert has been acknowledged by the token owner | | `alert.resolved` | An alert has been resolved (manually or auto-recovered) | ### Profile & Subscription Events | Event | Description | |-------|-------------| | `profile.updated` | Token profile metadata was updated | | `subscription.upgraded` | User plan tier was upgraded | | `subscription.downgraded` | User plan tier was downgraded | ### Usage & Quota Events | Event | Description | |-------|-------------| | `usage.threshold` | API usage crossed 80% or 90% of your daily quota (generic β€” use the `quota.*` variants to filter by level) | | `quota.threshold_warning` | API usage crossed **80%** of your daily quota. Fires at most once per day | | `quota.exceeded` | API usage crossed **90%** of your daily quota. Fires at most once per day | ### Community & Interest Events | Event | Description | |-------|-------------| | `community.member_joined` | A wallet joined a token's community for the first time (holder subscription, gated-link unlock, etc.) | | `community.member_left` | A wallet was removed from a token's community (owner-initiated delete or self-unsubscribe) | | `interest.expressed` | Someone expressed interest in a token deal or feature | ### Operational Events | Event | Description | |-------|-------------| | `ci.autofix.failed` | A CI auto-fix attempt failed (internal ops signal for app developers) | ### Event Discovery Fetch the authoritative list of subscribable event types (with descriptions) at runtime: ``` GET /api/v2/webhooks/events ``` Returns `{ "events": [{ "type": "token.minted", "description": "…" }, …] }`. Use this to build subscription UIs or to defensively validate event names before registering. ## Setup ### 1. Register a Webhook Endpoint ``` POST /api/v2/webhooks ``` ```json { "url": "https://example.com/webhooks/chaindaddy", "events": ["token.minted", "heartbeat.warning", "holder.new"], "filter": { "crown_ids": [123, 456], "chains": ["eip155:42161", "eip155:8453"] } } ``` | Field | Type | Required | Description | |-------|------|----------|-------------| | `url` | string | Yes | Your HTTPS endpoint that receives POST requests | | `events` | string[] | Yes | Event types to subscribe to | | `filter` | object | No | Optional filter to scope events to specific tokens or chains | | `filter.crown_ids` | int[] | No | Only receive events for these token IDs (field name kept for API compatibility). Omit for all tokens | | `filter.chains` | string[] | No | Only receive events for these chains (e.g. `eip155:42161`). Omit for all chains | The response includes a `secret` field, save this immediately. It is only shown once and is used to verify webhook signatures. ::: warning HTTPS Required Webhook endpoints must use HTTPS. HTTP endpoints are rejected during registration. ::: **Webhook limits per tier:** | Tier | Max Webhooks | |------|-------------| | Developer | 5 | | Partner | 25 | ### 2. Verify Payload Signatures Every webhook request includes an `X-Webhook-Signature` header containing an HMAC-SHA256 signature of the raw request body, signed with your webhook secret. ::: code-group ```javascript [JavaScript] const crypto = require('crypto'); function verifyWebhookSignature(payload, signature, secret) { const expected = crypto .createHmac('sha256', secret) .update(payload) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expected) ); } // Express middleware example app.post('/webhooks/chaindaddy', express.raw({ type: 'application/json' }), (req, res) => { const signature = req.headers['x-webhook-signature']; const isValid = verifyWebhookSignature( req.body, signature, process.env.WEBHOOK_SECRET ); if (!isValid) { return res.status(401).json({ error: 'Invalid signature' }); } const event = JSON.parse(req.body); console.log(`Received ${event.type}`, event.data); res.status(200).json({ received: true }); }); ``` ```python [Python] import hmac import hashlib from flask import Flask, request, jsonify app = Flask(__name__) def verify_signature(payload, signature, secret): expected = hmac.new( secret.encode(), payload.encode(), hashlib.sha256 ).hexdigest() return hmac.compare_digest(signature, expected) @app.route('/webhooks/chaindaddy', methods=['POST']) def handle_webhook(): signature = request.headers.get('X-Webhook-Signature') is_valid = verify_signature( request.get_data(as_text=True), signature, os.environ['WEBHOOK_SECRET'] ) if not is_valid: return jsonify({'error': 'Invalid signature'}), 401 event = request.json print(f'Received {event["type"]}', event['data']) return jsonify({'received': True}), 200 ``` ```go [Go] func verifySignature(payload []byte, signature, secret string) bool { h := hmac.New(sha256.New, []byte(secret)) h.Write(payload) expected := hex.EncodeToString(h.Sum(nil)) return hmac.Equal([]byte(signature), []byte(expected)) } ``` ::: ### 3. Respond with 2xx Your endpoint must respond with a `2xx` status code within **5 seconds** to acknowledge receipt. Any other status code or timeout triggers a retry. ## Payload Format All webhook payloads share a common envelope: ```json { "id": "evt_token.minted_1708617600000000000", "type": "token.minted", "created_at": "2026-02-22T12:00:00Z", "data": { ... } } ``` | Field | Type | Description | |-------|------|-------------| | `id` | string | Unique event ID (use for deduplication) | | `type` | string | Event type identifier | | `created_at` | string | ISO 8601 timestamp of when the event was created | | `data` | object | Event-specific payload (see below) | ### HTTP Headers Every webhook delivery includes these headers: | Header | Description | |--------|-------------| | `Content-Type` | `application/json` | | `X-Webhook-Signature` | HMAC-SHA256 hex digest of the request body | | `X-Webhook-Event` | Event type (e.g. `token.minted`) | | `X-Webhook-Delivery` | Unique delivery ID (same as `id` in payload) | | `X-Webhook-Timestamp` | ISO 8601 timestamp of the event | | `User-Agent` | `ChainDaddy-Webhook/1.0` | ## Event Payloads ### token.minted Fired when a new token registration is claimed for a symbol on a chain. ```json { "id": "evt_token.minted_1708617600000000000", "type": "token.minted", "created_at": "2026-02-22T12:00:00Z", "data": { "crown_id": "42", "symbol": "DOGE", "chain": "eip155:42161", "owner": "0x1234567890abcdef1234567890abcdef12345678", "tx_hash": "0xabcdef..." } } ``` | Field | Type | Description | |-------|------|-------------| | `crown_id` | string | Token ID (field name preserved for API compatibility) | | `symbol` | string | Token symbol claimed | | `chain` | string | Chain identifier (e.g. `eip155:42161`) | | `owner` | string | Wallet address of the new token owner | | `tx_hash` | string | Transaction hash of the mint | ### token.released Fired when a token owner voluntarily releases their registration. ```json { "data": { "crown_id": "42", "symbol": "DOGE", "chain": "eip155:42161", "previous_owner": "0x1234..." } } ``` | Field | Type | Description | |-------|------|-------------| | `crown_id` | string | Token ID (field name preserved for API compatibility) | | `symbol` | string | Token symbol now available | | `chain` | string | Chain identifier | | `previous_owner` | string | Wallet that released the registration | ### token.expired Fired when a registration expires due to inactivity and becomes claimable. ```json { "data": { "crown_id": "42", "symbol": "DOGE", "chain": "eip155:42161", "previous_owner": "0x1234..." } } ``` | Field | Type | Description | |-------|------|-------------| | `crown_id` | string | Token ID (field name preserved for API compatibility) | | `symbol` | string | Token symbol | | `chain` | string | Chain identifier | | `previous_owner` | string | Previous owner whose registration expired | ### heartbeat.warning Fired when a token's heartbeat score drops below the warning threshold. ```json { "data": { "crown_id": "42", "symbol": "DOGE", "chain": "eip155:42161", "score": 55, "threshold": 60 } } ``` | Field | Type | Description | |-------|------|-------------| | `crown_id` | string | Token ID (field name preserved for API compatibility) | | `symbol` | string | Token symbol | | `chain` | string | Chain identifier | | `score` | number | Current heartbeat score | | `threshold` | number | Warning threshold that was crossed | ### heartbeat.critical Fired when a token's heartbeat score reaches critical level. ```json { "data": { "crown_id": "42", "symbol": "DOGE", "chain": "eip155:42161", "score": 25, "days_to_inactive": 3 } } ``` | Field | Type | Description | |-------|------|-------------| | `crown_id` | string | Token ID (field name preserved for API compatibility) | | `symbol` | string | Token symbol | | `chain` | string | Chain identifier | | `score` | number | Current heartbeat score | | `days_to_inactive` | number | Estimated days until the registration goes inactive | ### heartbeat.recovered Fired when a token's heartbeat score recovers to healthy level. ```json { "data": { "crown_id": "42", "symbol": "DOGE", "chain": "eip155:42161", "score": 85, "previous_score": 45 } } ``` | Field | Type | Description | |-------|------|-------------| | `crown_id` | string | Token ID (field name preserved for API compatibility) | | `symbol` | string | Token symbol | | `chain` | string | Chain identifier | | `score` | number | Current (recovered) heartbeat score | | `previous_score` | number | Score before recovery | ### heartbeat.change Fired on any heartbeat status transition (e.g. healthy β†’ warning, warning β†’ critical). ```json { "data": { "crown_id": "42", "symbol": "DOGE", "chain": "eip155:42161", "previous_status": "healthy", "new_status": "warning", "current_score": 58, "timestamp": "2026-02-22T12:00:00Z" } } ``` | Field | Type | Description | |-------|------|-------------| | `crown_id` | string | Token ID (field name preserved for API compatibility) | | `symbol` | string | Token symbol | | `chain` | string | Chain identifier | | `previous_status` | string | Status before transition | | `new_status` | string | Status after transition | | `current_score` | number | Current heartbeat score | | `timestamp` | string | ISO 8601 timestamp of the transition | ### holder.new Fired when a new significant holder is detected for a registered token. ```json { "data": { "crown_id": "42", "symbol": "DOGE", "chain": "eip155:42161", "holder_address": "0xabcd...", "timestamp": "2026-02-22T12:00:00Z" } } ``` | Field | Type | Description | |-------|------|-------------| | `crown_id` | string | Token ID (field name preserved for API compatibility) | | `symbol` | string | Token symbol | | `chain` | string | Chain identifier | | `holder_address` | string | Address of the new holder | | `timestamp` | string | ISO 8601 timestamp | ### trade.large Fired when a large trade occurs (>5% of daily volume or >$10k). ```json { "data": { "crown_id": "42", "symbol": "DOGE", "chain": "eip155:42161", "trade_volume_usd": 15000.50, "direction": "buy", "timestamp": "2026-02-22T12:00:00Z" } } ``` | Field | Type | Description | |-------|------|-------------| | `crown_id` | string | Token ID (field name preserved for API compatibility) | | `symbol` | string | Token symbol | | `chain` | string | Chain identifier | | `trade_volume_usd` | number | Trade volume in USD | | `direction` | string | Trade direction (`buy` or `sell`) | | `timestamp` | string | ISO 8601 timestamp | ### concentration.alert Fired when a single wallet's token concentration exceeds the threshold. ```json { "data": { "crown_id": "42", "symbol": "DOGE", "chain": "eip155:42161", "concentration_percent": 82.5, "previous_concentration": 70.0, "threshold": 75.0, "timestamp": "2026-02-22T12:00:00Z" } } ``` | Field | Type | Description | |-------|------|-------------| | `crown_id` | string | Token ID (field name preserved for API compatibility) | | `symbol` | string | Token symbol | | `chain` | string | Chain identifier | | `concentration_percent` | number | Current concentration percentage | | `previous_concentration` | number | Previous concentration percentage | | `threshold` | number | Threshold that was exceeded | | `timestamp` | string | ISO 8601 timestamp | ### milestone.reached Fired when a token reaches a holder count milestone (e.g. 100, 500, 1000 holders). ```json { "data": { "crown_id": "42", "symbol": "DOGE", "chain": "eip155:42161", "milestone_type": "holder_count", "milestone_value": 1000, "previous_value": 999, "timestamp": "2026-02-22T12:00:00Z" } } ``` | Field | Type | Description | |-------|------|-------------| | `crown_id` | string | Token ID (field name preserved for API compatibility) | | `symbol` | string | Token symbol | | `chain` | string | Chain identifier | | `milestone_type` | string | Type of milestone reached | | `milestone_value` | number | Milestone threshold crossed | | `previous_value` | number | Value before crossing milestone | | `timestamp` | string | ISO 8601 timestamp | ### alert.triggered Fired when a health alert is triggered for a crown. The `data` payload varies by alert type and includes `title`, `body`, `action_url`, `action_label`, `symbol`, and optional `crown_id` / `chain_id` fields. ### alert.acknowledged Fired when an alert is acknowledged by the token owner. ```json { "data": { "instance_id": "alert_abc123", "wallet_address": "0x1234...", "alert_type": "heartbeat_critical", "crown_symbol": "DOGE", "timestamp": "2026-02-22T12:00:00Z" } } ``` | Field | Type | Description | |-------|------|-------------| | `instance_id` | string | Alert instance ID | | `wallet_address` | string | Wallet that acknowledged the alert | | `alert_type` | string | Type of alert (e.g. `heartbeat_critical`) | | `crown_symbol` | string | Symbol of the affected token | | `timestamp` | string | ISO 8601 timestamp | ### alert.resolved Fired when an alert is resolved (manually or by auto-recovery). ```json { "data": { "instance_id": "alert_abc123", "wallet_address": "0x1234...", "alert_type": "heartbeat_critical", "crown_symbol": "DOGE", "reason": "manual", "timestamp": "2026-02-22T12:00:00Z" } } ``` | Field | Type | Description | |-------|------|-------------| | `instance_id` | string | Alert instance ID | | `wallet_address` | string | Wallet that owns the alert | | `alert_type` | string | Type of alert | | `crown_symbol` | string | Symbol of the affected token | | `reason` | string | Resolution reason (e.g. `manual`, `auto_recovered`) | | `timestamp` | string | ISO 8601 timestamp | ### profile.updated Fired when a token's profile metadata is updated. ```json { "data": { "crown_id": "42", "symbol": "DOGE", "chain": "eip155:42161", "updated_fields": ["description", "avatar", "links"] } } ``` | Field | Type | Description | |-------|------|-------------| | `crown_id` | string | Token ID (field name preserved for API compatibility) | | `symbol` | string | Token symbol | | `chain` | string | Chain identifier | | `updated_fields` | string[] | List of fields that changed | ### subscription.upgraded Fired when a user's plan tier is upgraded. ```json { "data": { "wallet": "0x1234...", "previous_tier": "free", "new_tier": "developer" } } ``` | Field | Type | Description | |-------|------|-------------| | `wallet` | string | Wallet address | | `previous_tier` | string | Tier before upgrade | | `new_tier` | string | Tier after upgrade | ### subscription.downgraded Fired when a user's plan tier is downgraded. ```json { "data": { "wallet": "0x1234...", "previous_tier": "developer", "new_tier": "free" } } ``` | Field | Type | Description | |-------|------|-------------| | `wallet` | string | Wallet address | | `previous_tier` | string | Tier before downgrade | | `new_tier` | string | Tier after downgrade | ## Filtering Webhook subscriptions support optional filtering to scope events to specific tokens or chains. This reduces noise and lets you build targeted integrations. ### Per-Token Filtering Subscribe to events for specific tokens only: ```json { "url": "https://example.com/webhook", "events": ["heartbeat.warning", "heartbeat.critical"], "filter": { "crown_ids": [42, 108] } } ``` This webhook only fires for heartbeat events on token IDs 42 and 108. ### Per-Chain Filtering Subscribe to events on specific chains only: ```json { "url": "https://example.com/webhook", "events": ["token.minted", "holder.new"], "filter": { "chains": ["eip155:42161", "eip155:8453"] } } ``` This webhook only fires for minting and new holder events on Arbitrum and Base. ### Combined Filtering Combine both filters for precise targeting: ```json { "filter": { "crown_ids": [42], "chains": ["eip155:42161"] } } ``` Omitting a filter field (or omitting the `filter` object entirely) means no filtering on that dimension, you receive events for all tokens and/or all chains. ::: tip Events without token context (e.g. `subscription.upgraded`, `subscription.downgraded`) are always delivered regardless of token/chain filters. ::: ## Retry Policy The initial delivery is immediate. Failed deliveries are retried up to 5 times with exponential backoff: | Retry | Delay | Cumulative Time | |-------|-------|-----------------| | 1 | 1 minute | 1 minute | | 2 | 5 minutes | 6 minutes | | 3 | 30 minutes | 36 minutes | | 4 | 2 hours | ~2.5 hours | | 5 (final) | 12 hours | ~14.5 hours | After all attempts fail, the delivery is marked as `exhausted` and logged in your delivery history. A delivery is considered failed if: - Your endpoint returns a non-2xx status code - The connection times out (5-second limit) - DNS resolution or TLS handshake fails **Auto-disable:** After 3 consecutive failed deliveries across any events, your webhook is automatically disabled to prevent further failures. Use the reactivate endpoint to re-enable it after fixing the issue. ::: warning Duplicate Events Events may be delivered more than once during retries. Use the `id` field for deduplication in your handler. ::: ## Testing Locally ### Using a Tunnel Service Forward webhook traffic to your local development server using an HTTPS tunnel: ::: code-group ```bash [ngrok] # Start tunnel to local port 3000 ngrok http 3000 # Copy the https://xxxx.ngrok.io URL and use it as the "url" # when registering via POST /api/v2/webhooks ``` ```bash [localtunnel] # Start tunnel to local port 3000 npx localtunnel --port 3000 # Copy the https://xxxx.loca.lt URL and use it as the "url" # when registering via POST /api/v2/webhooks ``` ::: ### Using the Test Endpoint Send a test event to verify your endpoint receives and processes webhooks correctly: ``` POST /api/v2/webhooks/{id}/test ``` This queues a real delivery through the webhook pipeline with a test payload. Your endpoint receives a `token.minted` event with sample data, delivered with a valid HMAC signature. ### Manual cURL Testing Simulate a webhook delivery to your local endpoint: ```bash curl -X POST http://localhost:3000/webhooks/chaindaddy \ -H "Content-Type: application/json" \ -H "X-Webhook-Signature: test_signature_skip_verification" \ -H "X-Webhook-Event: token.minted" \ -d '{ "id": "evt_token.minted_test", "type": "token.minted", "created_at": "2026-02-22T12:00:00Z", "data": { "crown_id": "1", "symbol": "TEST", "chain": "eip155:421614", "owner": "0x0000000000000000000000000000000000000001", "tx_hash": "0x0000000000000000000000000000000000000000000000000000000000000000" } }' ``` ## Managing Webhooks ### List Event Types ``` GET /api/v2/webhooks/events ``` Returns every subscribable event type with a description. See [Event Discovery](#event-discovery). ### List Webhooks ``` GET /api/v2/webhooks ``` Returns all webhook subscriptions for the authenticated wallet, including filter configuration and delivery stats. ### Get Webhook ``` GET /api/v2/webhooks/{id} ``` ### Create Webhook ``` POST /api/v2/webhooks ``` ```json { "url": "https://example.com/webhook", "events": ["token.minted", "heartbeat.warning"], "filter": { "crown_ids": [42], "chains": ["eip155:42161"] } } ``` ### Update Webhook ``` PATCH /api/v2/webhooks/{id} ``` Update the endpoint URL, subscribed events, active status, or filters: ```json { "url": "https://new-endpoint.example.com/webhook", "events": ["token.minted", "token.released"], "active": true, "filter": { "crown_ids": [42, 108], "chains": ["eip155:42161"] } } ``` ### Delete Webhook ``` DELETE /api/v2/webhooks/{id} ``` ### Reactivate Webhook ``` POST /api/v2/webhooks/{id}/reactivate ``` Re-enables a webhook that was auto-disabled due to consecutive delivery failures. Resets the failure counter. ### View Delivery History ``` GET /api/v2/webhooks/{id}/deliveries?limit=50&offset=0 ``` Returns delivery attempts with status (`delivered`, `failed`, `exhausted`), timestamps, status codes, and error messages. Limit range: 20-100 (default: 20). ### Send Test Event ``` POST /api/v2/webhooks/{id}/test ``` Queues a test delivery through the full webhook pipeline to verify your endpoint. ## Best Practices - **Verify signatures**: Always validate the `X-Webhook-Signature` header before processing - **Respond quickly**: Return 2xx immediately, then process events asynchronously via a queue - **Handle duplicates**: Store processed event IDs and skip duplicates - **Use filters**: Scope webhooks to specific tokens or chains to reduce noise - **Monitor delivery health**: Check delivery history for persistent failures - **Subscribe selectively**: Only subscribe to events you need - **Set up alerting**: Configure your own alerts for repeated delivery failures --- # Airdrops URL: https://docs.chaindaddy.io/creator-tools/airdrops Category: creator-tools # Airdrops Airdrops let you distribute your token to a list of recipients or via an open claim link, without handing custody of your supply to anyone. You keep the tokens in your own wallet and approve a spending allowance; recipients claim, and the tokens transfer straight from your wallet to theirs. ::: tip Non-custodial by design Chain Daddy never holds or mints your airdrop supply. You approve an allowance to the distributor wallet, and the system pulls exactly the claimed amount from your wallet per claim. Revoke the allowance any time to stop distribution. ::: ## How It Works 1. You create a campaign and choose a mode: **Allowlist** or **First-come-first-serve (FCFS)**. 2. You set the token, the per-claim amount, and a total budget. 3. You approve a spending allowance from your funding wallet to the **distributor address** shown in the campaign β€” an ERC-20 `approve` on EVM chains, an SPL token delegate on Solana. 4. You activate the campaign and share its claim link. 5. A recipient connects their wallet, proves ownership with a signature, and the token transfers from your wallet to theirs. No tokens move until someone claims, and each claim pulls only that recipient's amount. ## Choosing a Mode | Mode | Best for | How recipients qualify | |------|----------|------------------------| | **Allowlist** | Rewarding a known set of wallets or social accounts | You upload the list; only those identities can claim (with optional per-recipient amounts) | | **FCFS** | Open campaigns, faucets, community growth | Anyone with the link can claim a fixed amount until the budget runs out, subject to an optional anti-sybil gate | ## Creating an Airdrop Airdrops live next to Community in your Token Manager β€” switch to the **Airdrops** tab with the toggle at the top, then create a campaign. ![The Token Manager's Community|Airdrops toggle β€” switch to Airdrops to create and manage campaigns](/screenshots/auto/manager-community--desktop--light.png) 1. Navigate to your **Token Manager** page 2. Open the **Airdrops** tab (toggle at the top of the Community view) 3. Click **Create Airdrop** 4. Configure the campaign: - **Name**: Display name shown on the claim page (required) - **Mode**: Allowlist or FCFS (required) - **Chain**: The chain your token lives on (required) - **Token address**: The ERC-20 contract address of the token you're distributing (required) - **Amount per claim**: How much each recipient receives (required for FCFS; the default for allowlist entries with no per-recipient amount) - **Total budget**: The maximum total you're committing to distribute (required) - **Funding wallet**: The wallet that holds the tokens and will grant the allowance (required) - **Description**: Optional context shown on the claim page - **Gas cap** (FCFS, optional): auto-pause the campaign once a set amount of network gas (in the chain's native coin) has been spent distributing it β€” a spend ceiling for open-ended campaigns - **Eligibility gate** (FCFS, optional): require a verified social account and/or a minimum token holding to claim β€” see [Eligibility Gates](#eligibility-gates-fcfs) 5. Click **Save** The campaign is created in **draft** status. It is invisible to the public until you activate it. ## Funding the Distributor In the non-custodial model, you fund a campaign by approving a spending allowance β€” not by sending tokens to Chain Daddy. 1. Open the campaign. It displays the **distributor address** to approve. 2. From your **funding wallet**, grant the distributor address an allowance of at least your total budget (in the token's base units): `approve` on your token contract on EVM chains, or approve the distributor as your token account's **delegate** on Solana. The campaign's funding panel has a one-click approval for both. 3. Confirm the allowance landed. The campaign health panel shows whether your funding wallet's balance and allowance cover the budget. ::: warning Keep enough balance **and** allowance in the funding wallet to cover outstanding claims. If either falls below a claim amount, that claim fails and the campaign **auto-pauses** so you're alerted before more claims fail. Top up and re-activate to resume. ::: ## Eligibility Gates (FCFS) FCFS campaigns are open to anyone with the link, so you can attach an eligibility gate to filter out bots and repeat claimers: - **Verified social**: the claimant must claim with a wallet that has a [verified social account](/token/social-verification) attached. This is the strongest gate β€” wallets are free to create in bulk, but aged social accounts are not. - **Minimum token hold** (EVM chains): the claimant's wallet must hold at least a set amount of a token you choose, on a chain you choose. ::: warning Minimum hold is best-effort The minimum-hold check is a point-in-time balance read. A determined claimer can borrow tokens just long enough to pass it, so treat it as a speed bump, not a hard guarantee. When sybil resistance really matters, use the verified-social gate (optionally combined with min-hold) and keep per-claim amounts modest. ::: Every campaign also gets built-in protections regardless of gates: one claim per wallet, one claim per social identity, and per-IP rate limiting. With no gate configured, an active FCFS campaign is an **open faucet** β€” anyone with the link can claim until the budget runs out. That can be exactly right for a growth campaign; just size the budget (and gas cap) accordingly. ## Uploading a Recipient List (Allowlist mode) For allowlist campaigns, upload the recipients who are allowed to claim: 1. Open the campaign and go to the **Allowlist** section 2. Upload a CSV of recipients. Each row is one identity: - A **wallet address**, or a **social handle** (with its platform) - An optional **amount** for that recipient (base units). Leave blank to use the campaign's default per-claim amount 3. Save the upload You can upload up to 10,000 entries per upload, and upload more than once to grow the list. Re-uploading the same identity updates its amount. ## Activating and Sharing 1. Make sure the campaign is funded (budget set, per-claim amount set, allowance approved) 2. Set the campaign status to **active** 3. Share the **claim link** from the campaign. Recipients open it, connect their wallet, and claim. You can **pause** an active campaign at any time to stop new claims, then **activate** it again later. Mark it **completed** or **cancelled** when you're done. ## Claimant Experience When a recipient opens your claim link: 1. They see the campaign name, the token, and the amount they can claim 2. They connect their wallet and sign a message to prove they own it (no gas, no transaction to sign for the claim itself) 3. The system checks eligibility: - **Allowlist**: their wallet or social identity must be on your list - **FCFS**: the budget must not be exhausted, and they must pass any anti-sybil gate you set (for example, a minimum token-hold requirement) 4. If eligible, the token transfers from your wallet to theirs, and they see the transaction hash Each recipient can claim **once**. A wallet can claim at most once per campaign, and a social identity can claim at most once even if the recipient tries a different wallet. ## Reading Campaign Health The campaign panel and the Analytics tab show a few numbers worth understanding: | Stat | Meaning | |------|---------| | **Total budget** | The most this campaign will ever distribute. | | **Claimed** | Tokens already confirmed on-chain to claimants. | | **Reserved** | Tokens set aside for claims still in flight β€” accepted but not yet confirmed on-chain. Each reservation either becomes Claimed or is released back to the budget if the claim fails. | | **Remaining** | Budget minus claimed and reserved β€” what new claimants can still get. | | **Claims / unique claimants** | How many claims have been made, and by how many distinct wallets. | | **Claim rate** | Of claims started, the share that completed. A falling rate usually means an underfunded wallet, or an eligibility gate doing its job. | The health panel also checks your funding live: it compares your funding wallet's **balance** and **allowance** against the remaining budget, so you can top up before claims start failing. ## Gas and the Gas Cap Chain Daddy's distributor pays the network gas for every distribution. Claimants sign a free message β€” no transaction on their side β€” and your only gas cost is the one-time `approve` from the funding wallet. For FCFS campaigns you can set an optional **gas cap**: once that much of the chain's native coin has been spent distributing your campaign, it auto-pauses (the same way an underfunded campaign does). This keeps an open-ended campaign from running longer than you intended. Leave it empty and distribution continues while the budget lasts. ## Claim Statuses and Troubleshooting A claim moves through these statuses: | Status | Meaning | |--------|---------| | **Pending** | The claim was accepted and budget reserved; the transfer is about to be sent. | | **Submitted** | The transfer transaction is on its way to the chain. Most claims confirm within a minute. | | **Confirmed** | The transfer landed on-chain β€” the claimant has the tokens, and the claim page links the transaction. | | **Failed** | The transfer could not be completed. The reserved amount is released back to the budget, and the claimant can try again. | **For claimants:** - *"Not eligible"* β€” on allowlist campaigns, your wallet or social identity isn't on the operator's list (ask them to add you). On FCFS, an eligibility gate wasn't met or the budget is exhausted. - *"Already claimed"* β€” each wallet and each social identity can claim once per campaign, even from a different wallet. - *Stuck on submitted* β€” the network is busy; the claim confirms automatically once the transaction lands. If it ultimately fails, the claim is released and you can try again. - *Campaign paused* β€” the operator paused it (often to top up funding). Try again later. **For operators:** - *Campaign auto-paused* β€” your funding wallet's balance or allowance dropped below a claim amount, or the gas cap was reached. Top up / re-approve (or raise the cap), then set the campaign active again. - *Claims failing on one campaign only* β€” double-check the token address and decimals on that campaign; a wrong decimals setting moves the wrong magnitude. ## Tips and Limits | Aspect | Detail | |--------|--------| | Custody | Non-custodial β€” tokens stay in your funding wallet until claimed | | Claims per recipient | One per wallet, and one per social identity, per campaign | | Allowlist size | Up to 10,000 entries per upload (upload repeatedly for more) | | Budget guard | Claims can never exceed your total budget; the distributor reserves each claim atomically | | Underfunding | A claim that exceeds your available balance/allowance fails and auto-pauses the campaign | | Gas | Chain Daddy pays the distribution gas; you only pay to approve the allowance. FCFS campaigns can set a [gas cap](#gas-and-the-gas-cap) that auto-pauses when reached | | Supported chains | Arbitrum, Avalanche, Base, Polygon, BNB Chain, Ethereum, Gnosis (ERC-20) and Solana (SPL) | ::: tip Revoke to stop Because distribution is allowance-based, you can stop all future claims instantly by revoking the distributor's allowance on your token contract, or by pausing the campaign. ::: ## FAQ
Do I send my tokens to Chain Daddy? No. Your tokens stay in your own wallet until the moment a claim is confirmed. You grant the distributor address a spending allowance capped at your budget, and each claim transfers directly from your wallet to the claimant. Revoking the allowance stops everything instantly.
As a claimant, is anything at risk when I claim? No. You sign a short message that proves you control your wallet β€” a signature is free, moves nothing, and grants no permissions over your funds. The token transfer itself is sent and paid for by the distributor; you never submit a transaction or approve anything.
Why do I have to sign a message to claim? The signature proves the claim request really comes from the owner of the receiving wallet, and it is bound to this specific campaign β€” it can't be reused anywhere else. Without it, anyone could claim tokens into someone else's address (or pretend to be you).
What happens if my funding wallet runs low mid-campaign? The next claim that can't be covered fails safely and the campaign auto-pauses so no further claims are attempted. Top up the wallet (or re-approve a larger allowance) and set the campaign active again β€” nothing is lost, and the failed claimant can claim again.
Can I run an airdrop for a token on Solana? Yes. Solana airdrops work the same non-custodial way as EVM ones: instead of an ERC-20 allowance, your funding wallet approves the distributor as an SPL **token delegate** for up to your budget, and each claim transfers straight from your wallet to the claimant. Pick Solana as the campaign's chain and the funding panel walks you through the delegate approval.
--- # Community Gating (Discord & Telegram) URL: https://docs.chaindaddy.io/creator-tools/community-gating Category: creator-tools # Community Gating (Discord & Telegram) Community gating restricts a Discord channel or a Telegram group/channel to verified holders of your token. A Chain Daddy bot checks each member's on-chain balance and grants or removes access automatically, with no manual allow-lists and no sharing of wallet data beyond a balance check. ::: tip PRO Feature Community gating requires a [PRO](/pricing/plans) subscription. Pro allows 2 gated Discord servers and 2 gated Telegram chats per token; Pro+ allows 5 each. ::: ## Finding it Open your token manager and tap **Community** in the bottom navigation, then find the **Token Gating** card. Discord roles, Telegram membership, and the access tiers that drive them are all managed from here. ![The Community tab in the token manager β€” the Token Gating card sits alongside holder notifications and access tiers](/screenshots/auto/manager-community--desktop--light.png) ## How it works The flow is the same on both platforms β€” define who qualifies, connect your community, then map the two together: 1. **Define an access tier** β€” the token, chain, and minimum balance a holder must meet to get in. 2. **Connect your community.** For Discord, click **Connect Discord Server** and enter your **Server ID** (Chain Daddy fetches the server name for you). To find it, enable *Developer Mode* in Discord β†’ Settings β†’ Advanced, then right-click your server icon β†’ *Copy Server ID*. ![The Connect Discord Server dialog β€” paste your Server ID after enabling Developer Mode and copying it from your server](/screenshots/connect-discord-dialog.png) 3. **Map the tier to access.** Once the server is connected, add a rule that ties a tier to a place in your community: - **Discord** β†’ the bot assigns a **role**; you restrict channels to that role with normal Discord permissions. - **Telegram** β†’ the bot controls **membership** of a private group or channel: it approves join requests from qualifying holders and removes anyone who drops below the threshold. Holders prove ownership of a wallet once, and the bot keeps their access in sync as their balance changes. It's all managed from the **Token Gating** card on your **Community** tab. ![The Community tab's Token Gating card β€” define hold-to-access tiers, then connect a Discord server or Telegram group to gate it by those tiers](/screenshots/community-token-gating.png) --- ## Access tiers Everything gates on **access tiers** β€” a named hold-to-access level. Create one from the **Access Tiers** card, then map it to a Discord role or Telegram chat below. ![Create Access Tier β€” tier name, description, icon, color, and gating criteria (chain + minimum balance), with an OR option for alternates](/screenshots/access-tier-create.png) - **Tier Name** and **Description** β€” what the tier is called and represents (e.g. *Top community*). - **Icon** and **Color** β€” a badge to distinguish the tier in your community. - **Gating Criteria** β€” the **chain** and **minimum balance** a holder must hold to qualify (e.g. 100 CHAP on Arbitrum). Use **Add alternate criterion (OR)** to admit holders who meet *any* of several conditions β€” for example 100 on Arbitrum **or** 100 on Base. --- ## Discord setup 1. **Invite the bot.** In the Token Gating section, open the Discord card and use the **bot invite link** to add the Chain Daddy bot to your server. Grant it **Manage Roles** when prompted. 2. **Connect your server.** Click **Connect Discord Server** and enter your **Server ID** (Chain Daddy fetches the server name for you). To find the Server ID, enable *Developer Mode* (Discord β†’ Settings β†’ Advanced), then right-click your server icon β†’ *Copy Server ID*. 3. **Add a role mapping.** Click **Add**, pick (or create) a Discord role, and map it to an [access tier](#access-tiers). 4. **Restrict your channels.** In Discord β†’ *Server Settings β†’ Channels*, set each private channel's permissions so only the mapped role can view it. The bot adds/removes the role; Discord enforces the channel access. Once connected, the Discord card lists your **role mappings** (with a bot invite link if you still need to add the bot): ![The connected Discord card β€” an empty Role Mappings list with an Add button and a bot invite link](/screenshots/discord-connected.png) Click **Add** to map a Discord **role** to an [access tier](#access-tiers): ![Add Role Mapping β€” pick a Discord role and the access tier that grants it](/screenshots/discord-add-mapping.png) The mapping then appears on the card, and the bot assigns that role to holders who qualify: ![A live Discord role mapping β€” "@chain-daddy-gate-bot β†’ hold 100+ CHAP on arbitrum", with edit and remove controls](/screenshots/discord-mapping-live.png) --- ## Telegram setup Telegram has no roles, so access **is** membership of the private group or channel. Add the gate bot as an admin and it approves join requests from qualifying holders. 1. **Add the bot as an admin.** Add **@ChainDaddyVerifyBot** to your private group or channel as an **Administrator**, with permission to *Add members* (invite via link) and *Ban users* (needed to remove members who no longer qualify). For groups you can use the **Add bot to a group** link in the Connect dialog; for channels, add it from the channel's *Administrators* screen. 2. **Enable join-request approval.** In the group/channel settings β†’ *Members*, turn on **Approve new members**. This turns the invite link into join requests the bot can gate. 3. **Connect your chat.** When you make the bot an admin it posts the numeric **Chat ID** in the chat. Click **Connect Telegram Group / Channel** and paste that Chat ID (or an `@username`). Chain Daddy fetches the chat title for you. ![Connect Telegram Group / Channel β€” paste your Chat ID (or @username); the dialog reminds you to make @ChainDaddyVerifyBot an admin with add-members + ban rights and enable "Approve new members"](/screenshots/telegram-connect.png) 4. **Add a rule.** Click **Add**, give the tier a label (e.g. *Holders*, *Whales*) and set the token condition(s). A member is admitted if they satisfy **any** enabled rule. Once connected, the Telegram card shows your chat β€” with a reminder until the bot is a full admin β€” and an empty rules list: ![The connected Telegram card β€” a reminder to add the bot as an admin, with an empty Gating Rules list](/screenshots/telegram-connected.png) Click **Add** to map an [access tier](#access-tiers) to membership: give the rule a label and pick the tier. ![Add Gating Rule β€” a rule label and the access tier that grants membership](/screenshots/telegram-add-rule.png) Your rule then appears on the card, and qualifying holders are admitted automatically: ![A live Telegram gating rule β€” "Top community β†’ hold 100+ CHAP on arbitrum", with edit and remove controls](/screenshots/telegram-rule-live.png) --- ## Member experience 1. A holder opens your group's invite link and **requests to join** (or runs `/verify` in the group / clicks a gated link). 2. The bot sends a one-time **Verify wallet** link. The holder connects a wallet and signs a message. Only a balance check happens; no funds move and no personal data is collected. 3. If they hold enough, they're **admitted automatically**. If their balance later drops below the threshold, the bot removes them on its next re-check. For Discord, the same verification assigns the mapped role; channel access follows your Discord permissions. --- ## Tips & limits - **Supported chains:** Ethereum, Arbitrum, Base, Polygon, BNB Chain, Avalanche, Gnosis, and Solana. - **Tiers first:** create an access tier (token + minimum balance) before adding a rule. Rules map a tier/condition to a role (Discord) or to chat membership (Telegram). - **Re-verification:** balances are re-checked periodically; access is kept in sync automatically. - **Use cases:** alpha channels, VIP/whale rooms, holder-only announcements, early access, and whitelist coordination. --- # Ownership Deals URL: https://docs.chaindaddy.io/creator-tools/deals Category: creator-tools # Ownership Deals Deals are the only way to transfer your token's verified registration to a new owner. Every deal is announced on-chain 30 days before it happens, giving token holders time to make informed decisions. Both parties sign cryptographically. The transfer executes automatically with no intermediary. ## Why Use Chain Daddy Deals? Traditional crypto project acquisitions rely on lawyers, escrow agents, and trust between strangers. Chain Daddy replaces all of that with on-chain enforcement. | What you get | How it works | |---|---| | **30-day public notice** | Every deal is visible on-chain for 30 days before execution. Holders see it coming. No advisor offers this. | | **Cryptographic consent** | Both parties sign on-chain. The buyer's signature proves mutual agreement. No disputes. | | **Automatic transfer** | The release-and-register mechanism transfers verified ownership without trusting either party. No escrow needed. | | **Public record** | Every deal is permanently on-chain. Legitimate projects point to their deal history as proof. | | **$30K max total fees** | Facilitation ($20K cap) + protocol contribution ($10K cap). Traditional M&A advisory charges $50K-$200K on a $2M deal. | | **50% launch discount** | The first 10 deals pay half the facilitation fee. | ## Deal Types | Type | Use Case | What Happens to Holders | |------|----------|------------------------| | **Buyout Offer** | Buyer acquires the token project | Holders can redeem tokens for ETH/stablecoins | | **Migration** | Two tokens merge into one | Holders swap old tokens for new tokens | | **Project Acquisition** | Project changes hands | No token change; ownership/admin transfers | ### Buyout Offer The buyer acquires the token and provides a redemption pool so existing holders can exit at a set rate. - Buyer deploys a redemption contract and funds it - Holders send tokens to redeem for ETH or stablecoins - Redemption window remains open for minimum 30 days after the seller releases the registration ### Migration Two token projects merge. Holders swap their old tokens for new tokens at an agreed ratio. - Buyer deploys a swap contract with new tokens deposited - Holders swap old tokens for new tokens at the published ratio - Swap window remains open for minimum 30 days after the seller releases the registration ### Project Acquisition The project changes hands without affecting the token itself. The verified owner transfers token admin/ownership to the buyer. - Seller transfers token admin role to buyer's address - Payment handled directly between parties (P2P or escrow) - Token holders are unaffected ## Making an Offer A buyer opens a deal from the token's page (**Make Offer**) and picks a deal type. For a buyout they set the offer amount and currency, verify they hold the funds, and specify the holder redemption terms β€” the rate and token holders can redeem for after the buyout is accepted: ![The buyout offer form β€” offer amount, currency, and holder redemption terms](/screenshots/deals-make-offer.png) Once submitted, the offer is signed and sent to the current owner for review. ## How Deals Work ``` 1. ANNOUNCE -> Deal posted on-chain (30-day countdown starts) 2. EXECUTE -> Both parties fulfill terms during notice period 3. RELEASE -> Seller releases their registration after notice period ends 4. REGISTER -> Buyer files a fresh registration (60-day window) ``` **Step 1: Announce.** The current verified owner submits a deal with the buyer's wallet address, deal type, terms document, and the buyer's signature proving consent. An on-chain event notifies holders and a deal banner appears on the token page. **Step 2: Fulfill terms.** During the 30-day notice period, both parties complete their obligations: the buyer funds a redemption pool (buyout offer), deploys a swap contract (migration), or the seller transfers admin access (project acquisition). **Step 3: Release.** After the notice period, the seller releases their on-chain registration β€” this is irreversible. ::: warning Irreversible Once released, the deal cannot be cancelled. Only proceed when all terms are satisfied. ::: **Step 4: Register.** The buyer files a fresh registration in their own wallet. They have 60 days to do so. The registration resets to a clean state. ## Reviewing an Offer When someone offers to acquire your token, it shows up in your deals and you're notified. Open it to see the full terms β€” amount, payment method, buyer, the buyer's message, and the fee breakdown β€” then **Accept** or **Reject**: ![A received buyout offer β€” terms, buyer's message, fee breakdown, and Accept / Reject](/screenshots/deals-accept.png) Accepting announces the deal on-chain and starts the 30-day notice period. Rejecting closes it with no on-chain action. ### Staying in the Loop Deal activity β€” new offers, acceptances, and token alerts β€” surfaces in the notifications panel (the bell in the top bar): ![The notifications panel β€” deal offers, acceptances, and token alerts](/screenshots/deals-notifications.png) ## Fees ### What You Pay Chain Daddy uses a sliding scale, so larger deals pay a lower percentage. Each rate applies only to the portion of the deal in that range, like tax brackets. | Deal Value | Rate | |---|---| | First $25,000 | 5% | | $25,001 to $100,000 | 3% | | $100,001 to $500,000 | 2% | | Above $500,000 | 1% | **Hard cap: $20,000.** No deal ever pays more than $20,000 in facilitation fees, regardless of size. There is also a 2% protocol contribution, capped at $10,000, that funds ongoing protocol maintenance and ecosystem development. Combined, your maximum total fee is $30,000 on any deal. **Launch discount:** The first 10 deals get 50% off the facilitation fee. ::: tip How the sliding scale works On a $50,000 deal: the first $25K is at 5% ($1,250) and the next $25K is at 3% ($750). Total: $2,000 facilitation + $1,000 protocol = $3,000 (6.0% effective rate). ::: ### Fee Examples | Deal Size | Facilitation | Protocol (2%, max $10K) | Total | Effective Rate | |---|---|---|---|---| | $5,000 | $250 | $100 | $350 | 7.0% | | $25,000 | $1,250 | $500 | $1,750 | 7.0% | | $50,000 | $2,000 | $1,000 | $3,000 | 6.0% | | $100,000 | $3,500 | $2,000 | $5,500 | 5.5% | | $500,000 | $11,500 | $10,000 (cap) | $21,500 | 4.3% | | $1,000,000 | $16,500 | $10,000 (cap) | $26,500 | 2.7% | | $2,000,000 | $20,000 (cap) | $10,000 (cap) | $30,000 | 1.5% | ### Compared to Traditional Alternatives | Service | Typical fee on a $1M deal | Timeline | |---|---|---| | M&A advisory firm | $50,000 to $100,000 | 3 to 12 months | | Escrow service | $10,000 to $30,000 | 1 to 3 months | | Chain Daddy | $26,500 | 30 days notice + 60 days claim | ### Other Fees | Action | Fee | |--------|-----| | Announce deal | Free | | Cancel deal | Free (before release only) | | Release registration | Gas only | | Buyer's new registration | Standard platform fee β€” see [Registration & Creation Pricing](/pricing/registration) | ## Cancellation The seller can cancel an announced deal at any time before releasing their registration. - The registration remains with the seller as if nothing happened - Cannot cancel after release ## Expired Deals If the buyer fails to register within 60 days after the seller releases: 1. The deal expires 2. Anyone can claim the ticker at the standard platform fee β€” see [Registration & Creation Pricing](/pricing/registration) 3. First-come-first-served ::: danger Buyer Risk If you are the designated buyer, register promptly after the seller releases. After 60 days, anyone can take the ticker. ::: ## What Happens After a Deal - The seller's registration is permanently released and burned on-chain - The buyer files a new registration under their own wallet - All metadata and managers are cleared - Health score resets with a 30-day grace period ## Holder Protections | Protection | How It Works | |-----------|-------------| | 30-day notice | Holders see the deal announcement and can exit before transfer | | On-chain terms | Deal terms are on IPFS, immutable | | Mutual consent | Buyer signs a cryptographic message proving they agree | | Public events | All deal actions emit events for monitoring | | No hidden deals | Only one active deal per registration at a time | ## Constraints - One active deal per registration - Registrations are permanently bound to your wallet; deals are the only transfer mechanism - Both parties must opt in - No on-chain escrow for payments; parties handle payment directly - No admin overrides or reversals ## Edge Cases **Seller announces but never releases:** Deal stays open. Seller can cancel anytime. **Registration goes inactive during notice period:** Deal continues. Buyer files their new registration and can revive activity. **Buyer's wallet is compromised:** Seller cancels and re-announces with a new buyer address. Must be before release. **Lost wallet after release:** Deal expires after 60 days and the ticker becomes available to anyone at the standard platform fee. --- # Holder Snapshot Export URL: https://docs.chaindaddy.io/creator-tools/holder-export Category: creator-tools # Holder Snapshot Export ::: tip PRO Feature Holder Snapshot Export is available to PRO subscribers. [View plan tiers](/pricing/plans). ::: Export a point-in-time snapshot of your token's holder list. Use it for [airdrops](/creator-tools/airdrops), governance snapshots, community analysis, or any workflow that needs a verified list of token holders. ## What's Included Each export captures: | Field | Description | |-------|-------------| | `wallet_address` | Holder's wallet address | | `balance` | Token balance at time of snapshot | | `percentage` | Percentage of total supply held | | `chain` | Chain the tokens are held on | | `first_seen` | Date the wallet first acquired tokens | ## CSV Format Exports are delivered as CSV files with the following structure: ```csv wallet_address,balance,percentage,chain,first_seen 0x1a2b3c...def,1000000,2.50,arbitrum,2025-03-15 0x4d5e6f...abc,500000,1.25,arbitrum,2025-04-02 7Hk9mN...xyz,250000,0.63,solana,2025-05-10 ``` - File naming: `{SYMBOL}_{CHAIN}_holders_{YYYY-MM-DD}.csv` - Encoding: UTF-8 - Delimiter: Comma-separated - Header row included - Sorted by balance descending ## How to Export 1. Navigate to your token's **Manager Profile** 2. Click **Export Holders** in the tools section 3. Select the chain (or all chains for multi-chain registrations) 4. Click **Generate Snapshot** 5. Download the CSV file when ready ![The Verified Holders list in the Community tab β€” each holder's wallet, the chains their holdings were verified on, and when, with Export / Upload tools in the header](/screenshots/community-holder-snapshot.png) ::: warning Processing Time Large holder lists (10,000+ addresses) may take up to 60 seconds to generate. ::: ## Limits | Constraint | Value | |-----------|-------| | Exports per day | Varies by plan β€” see [Token Plans](/pricing/plans#plan-comparison) | | Minimum holders for export | 1 | | Maximum rows per file | 100,000 | | Data freshness | Real-time at time of request | ## Common Use Cases ### Airdrop Distribution Export your holder list and use it as an airdrop allowlist. The `balance` and `percentage` fields let you calculate proportional distributions β€” then run the distribution itself with [Airdrops](/creator-tools/airdrops), which pulls from your wallet non-custodially as holders claim. ### Governance Snapshots Capture holder balances at a specific point in time for on-chain or off-chain governance votes. ### Community Analysis Track holder growth over time by comparing exports from different dates. Identify your largest holders and newest community members. ### Cross-Chain Aggregation For tokens registered on multiple chains, export all chains at once to get a unified view of your holder base across networks. ## Multi-Chain Exports If your token is registered across multiple chains, you can: - Export a **single chain** for chain-specific operations - Export **all chains** for a unified holder list Multi-chain exports include the `chain` column to distinguish which network each holder is on. Duplicate wallets across chains appear as separate rows. ## Data Privacy - Only public on-chain data is exported (wallet addresses and balances) - No personal information is included - Exports are available only to the verified owner or designated manager --- # Holder Notifications URL: https://docs.chaindaddy.io/creator-tools/holder-notifications Category: creator-tools # Holder Notifications Holder notifications let verified token owners send messages directly to their token holders. Notifications are included with every plan tier, no add-ons required. Recipients must hold a minimum balance to receive messages, ensuring only genuine community members are reached. ## Finding it Open your token manager and tap **Community** in the bottom navigation β€” that's the hub for your holders. Each access tier has a **Notify Holders** (megaphone) button that opens the broadcast composer, pre-targeted to that tier's audience. ![The Community tab in the token manager β€” access tiers with a Notify Holders action, alongside holder gating](/screenshots/auto/manager-community--desktop--light.png) ## How It Works 1. **The verified owner** composes a notification from a tier's notification button 2. **Chain Daddy** confirms the sender is the registered owner of that ticker 3. **Recipients** are filtered by on-chain balance verification ($100+ of the token) 4. **Message** is delivered through available channels in priority order ![The broadcast composer β€” title, rich-text body, delivery channels (In-App, Email, Push, SMS, XMTP), an optional schedule, and a wallet-signature step so holders can trust the message came from the owner](/screenshots/holder-notifications-compose.png) ::: tip Free for Community Members Receiving holder notifications is free for any wallet holding $100+ of the token. No signup required, balance is verified on-chain. ::: ## Tier Limits Notification capacity is included with every tier: | Tier | Notifications/Week | Announcements | Updates | Alerts | Member Cap | |------|----------------|---------------|---------|--------|------------| | **Free** | 1 | 2/week | 4/week | Unlimited | 10,000 | | **PRO** | Unlimited | 4/week | 8/week | Unlimited | 50,000 | | **Developer+** | Unlimited | Unlimited | Unlimited | Unlimited | Unlimited | Member cap refers to the maximum number of verified holders who can receive each notification. If your token has more holders than your tier allows, the most recent verifications are prioritized. See [Token Plans](/pricing/plans) for full pricing details. ## Channel Priority Messages reach holders through these channels, based on each recipient's preferences: 1. **In-App**: Always delivered (default, cannot be disabled) 2. **Web push**: Browser notifications (if the holder enabled push) 3. **Email**: If the holder has verified an email address 4. **SMS**: For holders who added a phone number Recipients configure their preferred channels in their account settings. The **in-app inbox always receives the message**, so nothing is ever lost even if a holder has no other channel set up. ::: info No Discord or Telegram delivery Chain Daddy does **not** deliver holder notifications to Discord or Telegram DMs. Discord and Telegram are used only for [community gating](/creator-tools/community-gating) (token-gated access) β€” not as notification channels. To echo your token's *events* into a Discord channel you control, use [Discord alert forwarding](/alerts/#discord-alerts). Wallet-to-wallet messaging (XMTP) is rolling out; until it's live it falls back to email. ::: ## Verification Expiry Holder verification is valid for **24 hours**. After expiry: - Recipients must re-verify their balance to receive the next broadcast - This prevents sending to wallets that have sold their tokens - Verification happens automatically when the recipient visits Chain Daddy ::: warning If a holder sells their tokens between verification checks, they won't receive subsequent broadcasts until they re-acquire the minimum balance. ::: ## Sending a Broadcast ### Step 1: Open Access Tiers Navigate to **Token Manager > Community**. Your holders and access tiers are displayed here. ### Step 2: Click Broadcast on a Tier Each access tier card has a megaphone icon. Click it to open the notification compose modal pre-targeted to that tier's audience. ### Step 3: Compose Message Fill in the notification details: | Field | Description | Limit | |-------|-------------|-------| | **Type** | Update or Alert | β€” | | **Audience Tiers** | Select which tiers receive the message (pre-filled from the tier you clicked) | Multi-select | | **Channels** | In-App (always on), plus Push, Email, and SMS | Multi-select | | **Title** | Message headline | 100 characters | | **Message** | Message content | 1,000 characters | | **Image URL** (optional) | HTTPS image URL to include | Valid HTTPS URL | | **Link URL** (optional) | URL to include with the message | Valid HTTPS URL | ### Step 4: Send Review your message and click **Send**. The broadcast is signed with your wallet to verify ownership, then delivered to all matching holders. ## Best Practices - **Keep messages concise**: short updates perform better across all channels - **Use links**: drive holders to your site or announcement page for details - **Respect frequency**: even if your tier allows it, avoid over-messaging - **Target specific tiers**: use tier targeting to reach the right audience segment - **Time zone awareness**: normal priority messages respect recipient quiet hours (10pm, 8am local) ## Scheduled Notifications {#scheduled-broadcasts} Pro+ and above can schedule notifications for future delivery. When composing, toggle **Schedule for later** and set the date and time (at least 5 minutes ahead) β€” the platform sends it automatically. Scheduled notifications can be reviewed, edited, or cancelled from the notifications list until they send. --- # Creator Tools URL: https://docs.chaindaddy.io/creator-tools/ Category: creator-tools # Creator Tools Once your token is registered, creator tools help you manage its public presence: engage your community, gate content for holders, export data, and embed widgets. New to Chain Daddy? Start with [Create a Token](/getting-started/create-a-token) or [Claim an Existing Token](/getting-started/claim-an-existing-token). ## Getting around your token manager Everything below lives in your **token manager**. On any of your token pages, a floating bar at the bottom switches between the three main areas, with a **Widgets** pill and a quick-actions menu beside it: ![The token manager's bottom navigation β€” Page, Community, and Health, with the Widgets pill and its βŒƒ actions menu](/screenshots/manager-bottom-nav.png) - **Page** β€” your public token page: edit metadata, [theme](/token/themes), and [featured links](/token/themes#featured-links). See [Token Management](/token/token-management). - **Community** β€” your holders: [Holder Notifications](/creator-tools/holder-notifications), [Community Gating](/creator-tools/community-gating) (Discord & Telegram), and [Airdrops](/creator-tools/airdrops). - **Health** β€” your token's [Analytics](/analytics/): holder growth, pageviews, and your [health score](/analytics/#health-score). - **Widgets** (the pill) β€” add and arrange [widgets](/creator-tools/integrations) on your token page, like Market Data, Price Chart, and Community Polls. - **Actions menu** (the βŒƒ caret) β€” quick actions: **Notify Holders** ([holder notifications](/creator-tools/holder-notifications)), **New Poll** ([community polls](/creator-tools/integrations)), and **Add Content** ([featured content](/token/themes)). ## Guides - **[Alerts & Notifications](/alerts/)**: Where messages reach you, and how to turn each channel on. - **[Holder Notifications](/creator-tools/holder-notifications)**: Send verified messages directly to your token holders. - **[Community Gating](/creator-tools/community-gating)**: Gate Discord channels and Telegram groups to verified holders. - **[Token-Gated Links](/creator-tools/token-gated-links)**: Share links only verified token holders can open. - **[Airdrops](/creator-tools/airdrops)**: Distribute your token to an allowlist or an open claim link β€” non-custodially, straight from your own wallet. - **[Holder Snapshot Export](/creator-tools/holder-export)**: Download holder addresses and balances as CSV or JSON. - **[Listing Export](/creator-tools/listing-export)**: Export your token data in standard Token List format for wallets and exchanges. - **[Analytics](/analytics/)**: Track holder growth, pageviews, engagement, and your health score. - **[Ownership Deals](/creator-tools/deals)**: Facilitated, on-chain ownership transfers with built-in holder protections. - **[Apps & Integrations](/creator-tools/integrations)**: Install apps and widgets for your token page β€” Market Data, Community Polls, Price Chart, and Activity Feed are live. --- # Apps & Integrations URL: https://docs.chaindaddy.io/creator-tools/integrations Category: creator-tools # Apps & Integrations Your token page is extensible in two directions: **apps** add functionality to the page itself, and your **verified registration data** (contract address, chain, symbol, decimals) plugs into any external tool that works with token holdings β€” no manual lookups, no copy errors. ## Apps on Your Token Page Apps are widgets that render directly on your public token page. Browse and install them from **Token Manager β†’ Apps**. ![The App Directory in Token Manager β†’ Apps β€” each app shows its size, tier, and page-budget cost, with an Add button to install it on your token page](/screenshots/apps-directory.png) **Live today:** | App | What it does | |-----|-------------| | **Token Header** | The hero section β€” name, logo, verified links, and the Trade button | | **Market Data** | Live price, volume, market cap, holder count, and price momentum | | **Price Chart** | Embedded live DEX chart for your token's top trading pair | | **Activity Feed** | Recent holder notifications, media, and poll activity in one stream | | **Community Polls** | Token-weighted polls your holders vote on directly from the page | | **Content** | Rich content blocks β€” announcements, embedded media, custom HTML | More apps are available in the **App Directory** (open it from the Apps tab). Installing community-built third-party apps requires [Pro+](/pricing/plans); the apps above are built in. How many apps fit on your page depends on your plan's widget space β€” see [Token Plans](/pricing/plans#widget-space). ### Community Polls Polls are live. Create one from your token manager β€” the **New Poll** action in the βŒƒ menu beside the bottom nav β€” and holders vote right from your token page. Results update in real time and also appear in the Activity Feed. ![The Create Poll dialog β€” title, description, options, and duration, with a live preview](/screenshots/poll-create.png) **Fields:** - **Title** / **Description** β€” the question and any context for voters. - **Options** β€” two or more choices; use **Add Option** for more. - **Duration** β€” how long voting stays open, from 1 to 30 days. Two controls at the top of the dialog decide *how* the poll runs: - **Voting basis** (default **Off-Chain**) β€” how votes are counted. *Off-Chain* weights each vote by the wallet's token balance at a **snapshot** taken when the poll is created β€” free, no gas. Switch to *On-Chain (All)* or a specific chain to record votes on-chain instead. ![The voting-basis dropdown β€” Off-Chain, On-Chain (All), or a single chain](/screenshots/poll-voting-basis.png) - **Audience** (default **Token holders**) β€” who may vote. Leave it at *None (Token holders)* so any holder can vote, or pick an [access tier](/creator-tools/community-gating#access-tiers) such as *Top community* to restrict voting to that tier. ![The audience dropdown β€” all token holders, or a specific access tier](/screenshots/poll-audience.png) A live **preview** shows exactly how the poll will read on your page before you publish: ![The Create Poll preview β€” the question and options as holders will see them](/screenshots/poll-duration-preview.png) Hit **Create Poll** and it's live for your holders: ![Poll Created β€” the poll is now live for your token's holders](/screenshots/poll-created.png) ## Let Visitors Buy Your Token Every token page with a live market ships with a **Trade** button β€” visitors swap into your token right on the page, without leaving to find a DEX: - **EVM chains**: an embedded swap interface with aggregated routing - **Solana**: an embedded Jupiter-powered swap - **Low on gas?** Visitors can bridge gas to the right chain without leaving the flow No setup required β€” the Trade button appears automatically once your token has a tradable market. *The Trade button opens an embedded swap pre-targeted at your token β€” visitors never leave the page.* ## Embeddable Widgets for Your Own Site Copy-paste widgets for websites, docs, and apps outside Chain Daddy β€” a buy widget, tip links and a tip widget, streamer tip-alert overlays, and a holder count badge β€” are **coming soon**. ## Use Your Verified Data Anywhere Third-party tools that gate access, run campaigns, or tally votes by token holdings all need the same handful of verified facts about your token. Chain Daddy is the source of truth for them: | Your tool needs | Where to get it | |-----------------|-----------------| | Contract address, chain ID, symbol, decimals, token standard | Your token page β€” every field is verified on-chain at registration | | Holder gating for Discord or Telegram | Built in β€” no third-party bot needed. See [Community Gating](/creator-tools/community-gating) | | A gated URL (docs, downloads, calls, chats) | [Token-Gated Links](/creator-tools/token-gated-links) check live holder balances on every visit | | A point-in-time holder allowlist (campaigns, eligibility, snapshots) | [Holder Snapshot Export](/creator-tools/holder-export) β€” CSV or JSON | | Wallet & exchange metadata ingestion | [Listing Export](/creator-tools/listing-export) β€” standard Token List JSON | | Token distribution to an allowlist or claim link | [Airdrops](/creator-tools/airdrops) β€” non-custodial, from your own wallet | Because the data comes from your on-chain registration, anything you configure downstream inherits its accuracy β€” when you update metadata on Chain Daddy, exports and gates stay consistent. ## Tips - Keep your token metadata up to date β€” exports and gates pull from your registration's verified data - Test gated links and community gating with a small group before rolling out to your full community - Use a [holder snapshot export](/creator-tools/holder-export) for one-time eligibility lists; use [token-gated links](/creator-tools/token-gated-links) when access should track live balances --- # Listing Export URL: https://docs.chaindaddy.io/creator-tools/listing-export Category: creator-tools # Listing Export Export your registered token's metadata as pre-filled listing data for major platforms, or let them pull directly from the Token List standard endpoint. ## How It Works Your token page stores all the metadata that listing platforms require: name, ticker, description, logo, social links, and contract address. Listing Export packages this data in two ways: 1. **Token List Standard**: An auto-published JSON feed that platforms can adopt directly 2. **Manual Export**: Copy-paste formatted data for platforms that require form submissions ## Export Flow Follow these steps to export your token listing data: ### Step 1: Open Chain Admin Settings Open the **chain switcher** in the top bar of your Token Manager and click the **gear icon** to open that chain's admin settings β€” the same panel that holds Roles, Liquidity, and the Danger Zone (see [Chain Admin Settings](/token/token-management#chain-admin-settings)). ![The chain switcher β€” the gear icon (circled) opens that chain's admin settings](/screenshots/admin-chain-selector-gear.png) ### Step 2: Open Export Listing Data In the **Listing Export** section of the admin panel, click **Export Listing Data**. ![The Export Listing Data control in the chain admin panel](/screenshots/listing-export-button.png) ### Step 3: Select Format Choose your target platform from the export modal. Each option shows which fields will be included. ![Export format selection](/screenshots/listing-export-formats.png) ### Step 4: Copy or Download - **Copy All**: Copies all fields to clipboard in the platform's expected format - **Copy Individual**: Copy specific fields one at a time - **Open Platform**: Direct link to the platform's submission form ### Step 5: Submit Paste the copied data into the platform's listing form. Most fields will map directly. ::: warning Some platforms have minimum requirements (daily volume, holder count, liquidity) that must be met independently. The export provides the data, eligibility is determined by the platform. ::: ## Token List Standard All active registrations are automatically published to a Token List endpoint following the industry-standard format used by wallets, exchanges, and aggregators. ### Endpoints Base URL: `https://api.chaindaddy.io` | Endpoint | Description | |----------|-------------| | `GET /api/v2/tokenlist` | All verified tokens across all chains (token-list format) | | `GET /api/v2/tokenlist?chainId=1` | Ethereum tokens only | | `GET /api/v2/tokenlist?chainId=42161` | Arbitrum tokens only | | `GET /api/v2/tokenlist?chainId=8453` | Base tokens only | | `GET /api/v2/tokenlist?chainId=137` | Polygon tokens only | | `GET /api/v2/tokenlist?chainId=56` | BNB Chain tokens only | | `GET /api/v2/tokenlist?chainId=43114` | Avalanche tokens only | | `GET /api/v2/tokenlist?chainId=100` | Gnosis tokens only | Solana entries are included in the all-chains list. You can also filter by symbol with `?symbols=ABC,XYZ`. ### What's Included Each token entry contains: | Field | Source | |-------|--------| | `symbol` | Registered ticker | | `name` | Registered display name | | `address` | Token contract address | | `chainId` | Network identifier | | `decimals` | On-chain token decimals | | `logoURI` | Token logo URL | | `tags` | Category tags (verified, meme, active) | **Extensions** (additional metadata): | Field | Description | |-------|-------------| | `crownId` | On-chain registration ID (the soulbound NFT token ID) | | `heartbeatScore` | Activity score (0-100) | | `status` | active, inactive, or grace_period | | `verifiedAt` | Ownership verification timestamp | | `profileUrl` | Link to public token page | | `website` | Official project website | | Social links | X, Telegram, Discord URLs | ### Inclusion Criteria Tokens appear in the list when: - Registration is active (not released or inactive) - Token contract address is set (not registration-only) - Health score β‰₯ 30 - Not flagged for dispute The list updates every 5 minutes and follows semantic versioning. ## Manual Export Formats For platforms that require form submissions, the export modal provides pre-filled data in platform-specific formats. ### Supported Platforms | Platform Type | Fields Exported | Notes | |---------------|-----------------|-------| | Exchange aggregator | Name, ticker, description, logo, social links | Fastest listing path | | Price tracker (large) | Project name, ticker, description, contract, website, socials | May require volume thresholds | | Price tracker (mid-tier) | Logo, description, website, social links | Lower listing requirements | Each format pre-fills the exact fields that platform requires from your registration metadata. ::: tip PRO Feature Verified owners on PRO subscriptions get a **Verified** badge that listing platforms tend to weight as a stronger trust signal. ::: ## Token List vs Manual Export | | Token List | Manual Export | |---|---|---| | **Effort** | Zero (automatic) | Per-platform submission | | **Reach** | All platforms that adopt the list | One platform at a time | | **Speed** | Instant (5-min cache) | Depends on platform review | | **Maintenance** | Metadata syncs automatically | Re-export if details change | | **Best for** | Wallet/exchange visibility | Major aggregator listings | ## Tips - Complete your token metadata before exporting β€” missing fields result in incomplete submissions - The Token List endpoint is the recommended approach for most use cases - Platforms adopting the Token List will display your token automatically with no action required - Keep your health score healthy (above 60) to stay well clear of the Token List inclusion threshold - [Cross-chain linking](/token/cross-chain) ensures all chain registrations appear in the list ## Related - [Token Management](/token/token-management): Edit your token metadata - [Cross-Chain](/token/cross-chain): Link tokens across chains - [Token Plans](/pricing/plans): PRO badge benefits --- # Token-Gated Links URL: https://docs.chaindaddy.io/creator-tools/token-gated-links Category: creator-tools # Token-Gated Links Token-gated links are URLs that only verified holders of your token can access. Use them to share exclusive content, private communities, or gated resources with your token holders. ::: tip PRO Feature Token-gated links require a [PRO](/pricing/plans) subscription. The number of gated links per token varies by plan β€” see the [tier comparison](/pricing/plans#plan-comparison). ::: ## How It Works 1. You create a gated link and pick the [access tier](/creator-tools/community-gating#access-tiers) (chain + minimum balance) that gates it 2. Visitors click the link on your public token page 3. They connect their wallet and prove they hold the required amount 4. If verified, they're redirected to the destination URL Verification checks the visitor's on-chain balance in real time. No personal data is collected, only wallet balance is confirmed. ## Creating a Token-Gated Link ![The Create Gated Link form β€” title, teaser preview, the access tier that gates it, an optional redirect URL and expiry, and a Pro custom slug](/screenshots/gated-link-create.png) 1. Navigate to your **Token Manager** page 2. Scroll to the **Token-Gated Links** section 3. Click **Add Gated Link** 4. Configure the link: - **Title** (required): the headline shown on your token page. - **Teaser** (optional): preview text visitors see before they unlock. - **Access Tier** (required): the [access tier](/creator-tools/community-gating#access-tiers) that gates it β€” its chain and minimum-balance criteria show right below the picker. - **Redirect URL** (optional): where verified holders land after unlocking. - **Expires** (optional): an auto-expiry date for the link. - **Custom Slug** ([Pro](/pricing/plans)): a branded URL slug instead of the random one. 5. Click **Create Link**. Once created, the link appears on the **Token-Gated Links** card with its shareable URLs β€” your `chaindaddy.io/_g/…` link and the matching `TICKER.crown.info/_g/…` vanity link β€” plus live view and unlock counts: ![A created gated link β€” its two shareable URLs with view and unlock stats, and edit / disable controls](/screenshots/gated-link-created.png) ## Configuration Options | Field | Required | Notes | |-------|----------|-------| | Title | Yes | The link's headline on your token page | | Teaser | No | Preview text shown before unlocking | | Access Tier | Yes | The [access tier](/creator-tools/community-gating#access-tiers) (chain + minimum balance) a visitor must satisfy | | Redirect URL | No | Where holders are sent after verification (HTTPS) | | Expires | No | Optional auto-expiry date | | Custom Slug | No ([Pro](/pricing/plans)) | A branded URL slug | ::: warning Only use HTTPS URLs for destinations. HTTP links are rejected for security. ::: ## Editing a Link 1. Click the **edit icon** next to any gated link in your Token Manager 2. Modify the fields as needed 3. Click **Save** Changes take effect immediately. Existing verified sessions are not affected. ## Removing a Link 1. Click the **delete icon** next to the gated link 2. Confirm the deletion in the dialog Removed links are no longer accessible from your public token page. ## Limits | Aspect | Limit | |--------|-------| | Links per token | Varies by plan β€” see [Token Plans](/pricing/plans#plan-comparison) | | Minimum balance | 1 token | | Verification expiry | 24 hours | | Supported chains | All (Ethereum, Arbitrum, Base, Polygon, BNB Chain, Avalanche, Gnosis, Solana) | After 24 hours, visitors must re-verify their balance to access the link again. ## Use Cases - **Exclusive Discord or Telegram**: Gate access to private community channels - **Alpha channels**: Share trading insights only with holders - **Private content**: Gated blog posts, documents, or media - **Early access**: Give holders first access to new features or products - **Whitelist spots**: Reserve participation in launches for existing holders ## Visitor Experience When a visitor clicks a token-gated link on your token page: 1. A verification modal appears asking them to connect their wallet 2. The system checks their on-chain balance for your token on the relevant chain 3. If they hold the minimum required amount, they're redirected to the destination 4. If they don't hold enough, they see a message with the required amount and a link to acquire the token Verification is stateless, no accounts are created and no cookies are stored beyond the 24-hour session. --- # Actions API URL: https://docs.chaindaddy.io/developer/actions Category: developer # Actions API The Action API lets runners interact with the platform, store data, send notifications, update metadata, and more. All requests are authenticated with the same HMAC secret used for webhooks. ## Authentication Sign outgoing requests the same way the platform signs webhooks: 1. Serialize the request body as JSON 2. Compute HMAC-SHA256 using your hex-decoded webhook secret 3. Include the hex signature in the `X-App-Signature` header ```typescript import { createHmac } from 'node:crypto'; function sign(secret: string, body: string): string { const key = Buffer.from(secret, 'hex'); return createHmac('sha256', key).update(body, 'utf8').digest('hex'); } const body = JSON.stringify({ key: 'lastCheck', value: '2025-01-15' }); const signature = sign(process.env.WEBHOOK_SECRET!, body); const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-App-ID': 'my-app', 'X-App-Signature': signature, }, body, }); ``` ## Base URL All action endpoints follow this pattern: ``` POST /api/v2/apps/{appId}/registrations/{id}/actions/{action} ``` ## Response Format Every action returns a standard response: ```json { "success": true, "action_id": "act-550e8400", "status": "completed", "data": { ... } } ``` For dangerous actions that require approval: ```json { "success": true, "action_id": "act-550e8400", "status": "pending_approval", "approval_id": "apr-550e8400" } ``` ## Storage Scoped key-value storage for persisting state between event invocations. Each app gets isolated storage per token. **Limits:** 100 keys per app per token, 10KB per value, 500KB total. ### Set a Value ``` POST .../actions/apps.storage.set ``` ```json { "key": "lastAlert", "value": "{\"price\":0.10,\"time\":\"2025-01-15\"}" } ``` ### Get a Value ``` GET .../actions/apps.storage.get?key=lastAlert ``` Response: ```json { "success": true, "data": { "key": "lastAlert", "value": "{\"price\":0.10}" } } ``` ### List Keys ``` GET .../actions/apps.storage.list ``` Response: ```json { "success": true, "data": { "keys": ["lastAlert", "config", "state"] } } ``` ### Delete a Key ``` DELETE .../actions/apps.storage.delete?key=lastAlert ``` ## Notifications Send notifications to the token owner's dashboard. ``` POST .../actions/notifications.send ``` ```json { "title": "Price Alert", "body": "DOGE crossed $0.10 threshold", "severity": "info", "actionUrl": "/doge/arbitrum" } ``` | Field | Type | Limit | Required | |-------|------|-------|----------| | `title` | string | 100 chars | Yes | | `body` | string | 500 chars | Yes | | `severity` | string | `info`, `warning`, `critical` | No (default: `info`) | | `actionUrl` | string | Internal path | No | ## Metadata Update token metadata extensions. Requires `crown:metadata:write` scope (the scope name keeps the historical `crown:` prefix on the wire). ``` POST .../actions/crown.metadata.update ``` ```json { "metadata": { "myApp_score": 95, "myApp_lastSync": "2025-01-15T10:00:00Z" } } ``` Metadata is merged with existing values. Keys should be namespaced with your app ID to avoid conflicts. ## Config Update app configuration. Requires `apps:config:write` scope. ``` POST .../actions/apps.config.update ``` ```json { "config": { "alertPrice": 0.15, "alertDirection": "above" } } ``` ## Dangerous Actions These actions always require explicit approval from the token owner via the dashboard. ### Initiate Transfer ``` POST .../actions/crown.transfer.initiate ``` ```json { "targetAddress": "0x5678...efgh", "reason": "Migration to new wallet" } ``` Returns `status: "pending_approval"` with an `approval_id`. The token owner must approve in their dashboard within 24 hours. ### Manage Apps ``` POST .../actions/crown.apps.manage ``` ```json { "action": "enable", "appId": "another-app", "config": { "setting": "value" } } ``` ## Rate Limits Actions are rate-limited per runner with sliding windows: | Category | Limit | Scopes | |----------|-------|--------| | Read | 60/minute | `crown:read`, `market:read`, `apps:read` | | Write | 30/minute | `crown:metadata:write`, `apps:config:write` | | Storage | 120/minute | `apps:storage:write` (set, get, list, delete) | | Notifications | 30/minute | `notifications:send` | | Dangerous | 5/minute | `crown:transfer:initiate`, `crown:apps:manage` | ### Rate Limit Headers Every response includes rate limit headers: | Header | Description | |--------|-------------| | `X-RateLimit-Limit` | Maximum requests in the current window | | `X-RateLimit-Remaining` | Requests remaining | | `X-RateLimit-Reset` | UTC epoch seconds when the window resets | | `Retry-After` | Seconds to wait (only on 429 responses) | ### Handling 429 Responses When rate limited, wait for the `Retry-After` duration before retrying: ```typescript const response = await fetch(url, { ... }); if (response.status === 429) { const retryAfter = parseInt(response.headers.get('Retry-After') || '5'); await new Promise(r => setTimeout(r, retryAfter * 1000)); // Retry the request } ``` The SDK's `createActionClient` handles this automatically with configurable retry limits. ## Using the SDK The SDK provides a typed client that handles signing and rate limiting: ```typescript import { createActionClient } from '@chaindaddy/apps/runner'; const client = createActionClient({ apiBaseUrl: 'https://api.chaindaddy.io', appId: 'my-app', secret: process.env.WEBHOOK_SECRET!, maxRetries: 3, // Auto-retry on 429 }); // Storage await client.storage.set('doge.arb', 'key', 'value'); const value = await client.storage.get('doge.arb', 'key'); const keys = await client.storage.list('doge.arb'); await client.storage.delete('doge.arb', 'key'); // Notifications await client.notifications.send('doge.arb', { title: 'Alert', body: 'Something happened', severity: 'warning', }); // Metadata await client.metadata.update('doge.arb', { score: 95 }); // Dangerous (returns approval_id) const result = await client.dangerous.initiateTransfer('doge.arb', '0x...', 'Reason'); ``` --- # Event Reference URL: https://docs.chaindaddy.io/developer/events Category: developer # Event Reference The platform delivers events to your runner via HTTPS POST requests. Every event is wrapped in a standard envelope and signed with HMAC-SHA256. Events are delivered to runners whose manifest subscribes to the event β€” the platform filters every dispatch against your manifest's `runner.events` list. Both the legacy short `app.*` and canonical wire `token.app.*` forms match each other, and an **empty events list receives everything** (back-compat). `test.ping` from runner verification is always delivered regardless of the list. See [Event Subscriptions](/developer/runners#event-subscriptions). ## Event Envelope Every event delivered to your runner has this structure: ```json { "eventId": "550e8400-e29b-41d4-a716-446655440000", "eventType": "token.claimed", "timestamp": "2025-01-15T10:30:00Z", "appId": "my-app", "crownId": "doge.arb", "chainId": "arb", "crownConfig": { "threshold": 0.05, "channel": "#alerts" }, "payload": { ... } } ``` | Field | Type | Description | |-------|------|-------------| | `eventId` | string | Unique UUID. Use for [idempotency](/developer/runners#idempotency). | | `eventType` | string | One of the event types below | | `timestamp` | string | ISO 8601 when the event was generated | | `appId` | string | Your app ID | | `crownId` | string | Token registration identifier (e.g., `doge.arb`). Wire field keeps the historical `crown` prefix for compatibility. | | `chainId` | string | Chain key (e.g., `arb`, `sol`) | | `crownConfig` | object | Per-(token, app) user configuration. Set by the token owner via `PUT /api/v2/registration/{id}/apps/{appId}/config`. May be empty `{}` if not configured. Not present on `test.ping` delivery. | | `payload` | object | Event-specific data | ## HTTP Headers Each webhook request includes these headers: | Header | Description | |--------|-------------| | `Content-Type` | `application/json` | | `X-App-Event-ID` | Same as `eventId` in the body | | `X-App-Event-Type` | Same as `eventType` in the body | | `X-App-Timestamp` | Same as `timestamp` in the body | | `X-App-Signature` | HMAC-SHA256 hex signature of the body | ## Expected Response Your runner must respond with: ```json { "status": "ok" } ``` Or on error: ```json { "status": "error", "message": "Description of what went wrong" } ``` ::: warning Timeout Runners must respond within the configured `timeout` (default 30 seconds). Responses after the timeout are treated as failures. ::: ## Event Types ::: info Implementation Status Only `token.app.enabled`, `token.app.disabled`, `token.app.configured`, and `test.ping` are currently dispatched in production. The other event types below are part of the planned event catalog and are tagged **Status: Planned**. See [Forward Compatibility](#forward-compatibility) for how to subscribe defensively. ::: ### Registration Lifecycle #### `token.claimed` ::: warning Status: Planned Not emitted yet. ::: A token registration was created. ```json { "symbol": "DOGE", "chainKey": "arb", "ownerAddress": "0x1234...abcd", "tokenAddress": "0xabcd...1234", "tokenId": 42 } ``` #### `token.updated` ::: warning Status: Planned Not emitted yet. ::: Token registration metadata was changed. ```json { "symbol": "DOGE", "chainKey": "arb", "changedFields": ["description", "tags", "socialLinks"] } ``` #### `token.transferred` ::: warning Status: Planned Not emitted yet. ::: Token registration ownership transferred via the deal system. ```json { "symbol": "DOGE", "chainKey": "arb", "previousOwner": "0x1234...abcd", "newOwner": "0x5678...efgh", "dealId": "deal-550e8400" } ``` ### Heartbeat #### `token.heartbeat.warning` ::: warning Status: Planned Not emitted yet. ::: Heartbeat score dropped below the threshold. ```json { "symbol": "DOGE", "chainKey": "arb", "currentScore": 55, "threshold": 60, "daysBelowThreshold": 5 } ``` #### `token.heartbeat.inactive` ::: warning Status: Planned Not emitted yet. ::: Token registration became inactive due to low heartbeat score. ```json { "symbol": "DOGE", "chainKey": "arb", "finalScore": 42, "ownerAddress": "0x1234...abcd", "claimable": true } ``` ### App Lifecycle #### `token.app.enabled` ::: tip Status: Live Dispatched from the developer handler when a token owner enables an app. ::: Your app was enabled on a token. ```json { "symbol": "my-app", "chainKey": "", "enabledBy": "0x1234...abcd", "config": {} } ``` Known caveats: - `symbol` is currently the **app's name** (not the token's ticker symbol). Derive the token symbol from the envelope's `crownId` or look it up via the public API. - `chainKey` is emitted as an empty string. Use the envelope's `chainId` for chain routing. - `config` is currently the empty object; per-(token, app) config is delivered via the envelope's `crownConfig` field on subsequent events. #### `token.app.disabled` ::: tip Status: Live Dispatched from the developer handler when a token owner disables an app. ::: Your app was disabled on a token. ```json { "symbol": "my-app", "chainKey": "", "disabledBy": "0x1234...abcd" } ``` Same `symbol`/`chainKey` caveats as `token.app.enabled`. #### `token.app.configured` ::: tip Status: Live Dispatched on every per-(token, app) config write (`PUT /api/v2/registration/{id}/apps/{appId}/config`). ::: App settings changed by the token owner. ```json { "crownId": "42", "chainKey": "arb", "newConfig": { "alertPrice": 0.15 } } ``` | Field | Type | Description | |-------|------|-------------| | `crownId` | string | Token registration ID the config belongs to | | `chainKey` | string | Chain identifier | | `newConfig` | object | The freshly-written config, echoed so runners can act on the change without a separate GET round-trip | Known caveats: - The payload carries only the **new** config β€” `previousConfig` and `configuredBy` are not included. Keep your own last-seen copy if you need to diff. - Subsequent events for the token also deliver the current config via the envelope's `crownConfig` field. ### Market #### `market.price.threshold` ::: warning Status: Planned Not emitted yet. ::: Token price crossed a configured threshold. ```json { "symbol": "DOGE", "chainKey": "arb", "currentPrice": 0.105, "thresholdPrice": 0.10, "direction": "above", "previousPrice": 0.098 } ``` #### `market.volume.spike` ::: warning Status: Planned Not emitted yet. ::: Unusual trading volume detected. ```json { "symbol": "DOGE", "chainKey": "arb", "currentVolume": 5000000, "averageVolume": 1200000, "spikeMultiplier": 4.17 } ``` ### Schedule #### `schedule.tick` ::: warning Status: Planned Not emitted yet. ::: Scheduled cron execution. ```json { "schedule": "0 */6 * * *", "scheduledAt": "2025-01-15T12:00:00Z", "tickNumber": 42 } ``` ::: tip Cron Format Use standard 5-field cron syntax: `minute hour day-of-month month day-of-week`. Example: `0 */6 * * *` runs every 6 hours. ::: ### Test #### `test.ping` ::: tip Status: Live Dispatched during runner verification. Note: the `test.ping` envelope does NOT include `crownConfig`, only real events do. ::: Test event sent during [runner verification](/developer/runners#verification). ```json { "message": "Runner connectivity verification" } ``` ## Retry Policy If your runner returns an error or doesn't respond in time, the platform retries with exponential backoff: | Attempt | Delay | |---------|-------| | 1st retry | 1 minute | | 2nd retry | 5 minutes | | 3rd retry | 30 minutes | After all retries fail, the delivery is marked as failed. ::: warning Circuit Breaker After 10 consecutive delivery failures, the platform opens a circuit breaker and stops delivering events. Use the [verify endpoint](/developer/runners#verification) to reset it. ::: ## Forward Compatibility Your runner should handle unknown event types gracefully. When you receive an event type you don't recognize, log it and return `{"status":"ok"}`. This ensures your runner continues working as new event types are added. --- # Developer Getting Started URL: https://docs.chaindaddy.io/developer/getting-started Category: developer # Getting Started Ship your first app in three steps: install the CLI, scaffold the project, package and submit. Chain Daddy hosts the compiled bundle; your source stays on your machine. ``` $ npm install -g @chaindaddy/cli $ chaindaddy app login # one-time: signs a wallet challenge β†’ API key $ chaindaddy app init widget alice-labs/yield-tracker $ cd yield-tracker $ npm install $ npm run build && npm run pack && npm run sign && npm run submit βœ“ Submitted alice-labs/yield-tracker@0.1.0 (submission id 01J5GA…) βœ“ approved ``` That's it. No CDN to set up. No manifest URLs to hand-edit. No mystery review queue. The CLI does the build, packaging, signing, and submission. Chain Daddy scans, hosts, and approves. ## Prerequisites - **Node.js 18+** - **A registered developer account**: sign up at [chaindaddy.io/_developer](https://chaindaddy.io/_developer) and complete KYC (~5 min). KYC is required to ship apps; the CLI itself works without it. - **An active subscription** (Developer or Partner) for app submissions. ## Install the CLI ```bash npm install -g @chaindaddy/cli chaindaddy --version # 0.3.0 or later ``` The CLI handles two concerns: ticker registration ops (`chaindaddy create`, `chaindaddy profile`, etc.) and app development under `chaindaddy app …`. ## Authenticate Two paths, depending on your setup: ### Interactive (developer laptop) ```bash chaindaddy wallet init # create a local keystore (one-time) chaindaddy app login # picks a wallet, signs a challenge, stores the API key ``` The login command: 1. Asks Chain Daddy for a single-use challenge bound to your wallet 2. Decrypts your local keystore (asks for the password) 3. Signs the challenge with your wallet 4. Receives a `cd_live_…` API key in return, stored at `~/.chaindaddy/credentials.json` (0600) ### Non-interactive (CI, agents) Generate an API key from the developer portal or via `chaindaddy app key create`, then export it: ```bash export CROWN_API_KEY=cd_live_… ``` That one value serves as both the bearer for authenticated requests and the HMAC secret for signing `.crown` packages. ## Scaffold Pick your app type: | Type | What it is | When to use it | |------|------------|----------------| | `widget` | A React component rendered on a token page | UI elements (charts, badges, dashboards) | | `headless` | A webhook runner that reacts to events | Background tasks (alerts, integrations) | | `full` | Both | UI + reactive backend logic | ```bash chaindaddy app init widget alice-labs/yield-tracker cd yield-tracker npm install ``` Project layout: ``` yield-tracker/ β”œβ”€β”€ capp.json # the app manifest (validate with `chaindaddy app validate`) β”œβ”€β”€ src/index.tsx # widget root component β”œβ”€β”€ assets/ # icons, screenshots β”œβ”€β”€ package.json β”œβ”€β”€ tsconfig.json └── README.md ``` The manifest describes the app, its id, version, the token data it consumes, and the permissions it needs. The npm scripts in `package.json` wrap the CLI: ```json "scripts": { "build": "chaindaddy app build", "validate": "chaindaddy app validate", "scan": "chaindaddy app scan", "pack": "chaindaddy app pack", "sign": "chaindaddy app sign", "submit": "chaindaddy app submit --watch" } ``` ## Build, scan, pack, sign, submit ```bash npm run validate # JSON Schema check npm run build # esbuild to dist/bundle.js npm run scan # same security/size checks Chain Daddy runs npm run pack # produce dist/yield-tracker-0.1.0.crown npm run sign # sign the package with your API key npm run submit # upload, then watch the scan log ``` The `submit` step uploads a single `.crown` archive containing your manifest, bundle, runner config (if any), and assets. Chain Daddy: 1. Verifies the archive is well-formed and integrity-checked (every file is SHA-256 hashed inside the package). 2. Re-validates the manifest against the schema. 3. Runs the same security scanner you ran locally with `scan`. 4. Stores `bundle.js` and assets at `apps.chaindaddy.io/{appId}/{version}/...` with immutable cache headers. 5. Records the submission for human review. You'll see scan events stream by in real time: ``` [INFO] package_extract extracted 142 KB package (sha256 8f3c…) [INFO] package_signature signature verified (keyId=cd_live_…) [INFO] csp_scan no CSP violations [INFO] security_scan 0 critical, 0 high, 0 medium, 0 low [INFO] accessibility_scan score=98, 0 issues [INFO] bundle_size bundle is 142337 bytes (uncompressed) [INFO] auto_check_complete auto-check status: passed βœ“ approved ``` A non-zero exit code means something failed: | Exit code | What happened | Next step | |-----------|---------------|-----------| | `0` | Submitted and (with `--watch`) approved | Done, your app is live at `chaindaddy.io/apps/{slug}` | | `1` | User error (bad flag, malformed input) | Read the error message, fix the input | | `2` | System error (filesystem, network, OS-level) | Check the environment, retry | | `3` | Validation failure (schema, scan, server rejected) | Read the JSON details and fix | | `4` | Auth failed | Re-run `chaindaddy app login` | | `5` | Server error | Check status page, retry | ## Try it on one of your tokens Before requesting publication, install your app on one of your own tokens for dev preview: ```bash chaindaddy app tokens # list tokens you own chaindaddy app install alice-labs/yield-tracker --on 42 chaindaddy app preview alice-labs/yield-tracker --on 42 # open the URL printed above ``` Dev-preview installs are only visible to you. When you're satisfied: ```bash chaindaddy app request-publish ``` That moves the submission into the human-review queue. ## Add a headless runner To react to platform events (price thresholds, schedules, app lifecycle), add a runner: ```bash chaindaddy app init headless alice-labs/eod-snapshot cd eod-snapshot ``` The scaffold includes a minimal Node HTTP server using the runner SDK. Deploy it to any HTTPS endpoint (Cloudflare Workers, AWS Lambda, your own VPS) and update `runner.config.json` with the endpoint URL. For runner-specific guidance (idempotency, signature verification, retries, the Action API), see the [Runner SDK reference](/developer/runners). ## Next steps - [App manifest reference](/developer/manifest): every field - [Widget development](/developer/widgets): props, themes, lifecycle - [Runner development](/developer/runners): event handlers, the Action API - [Submission pipeline](/developer/submission): what Chain Daddy does with your package - [Event reference](/developer/events): all platform event types - [Security model](./security.md): sandbox, signing, permission scopes ## Troubleshooting | Symptom | Likely cause | Fix | |---------|--------------|-----| | `auth: no developer token found` | Not logged in, env vars unset | `chaindaddy app login` or export `CROWN_API_KEY` | | `PACKAGE_TOO_LARGE` | `.crown` > 8 MB | Trim assets; bundle without source maps | | `PACKAGE_BUNDLE_HASH_MISMATCH` | Manifest edited after `pack` | Re-run `pack` and `sign` | | `KYC verification is required` | Account not KYC'd | Complete KYC at [chaindaddy.io/_developer](https://chaindaddy.io/_developer) | | `active developer subscription required` | Free tier; submissions need a paid plan | Upgrade at [chaindaddy.io/_developer](https://chaindaddy.io/_developer) | | Submission stuck at `pending` for >5 min | Auto-checks queued behind other work | `chaindaddy app logs --follow` to see live progress | --- # App Development URL: https://docs.chaindaddy.io/developer/ Category: developer # App Development Build apps that extend token pages with custom widgets, automated workflows, and data integrations. ## Developer Beta Program We're opening the app platform to third-party developers in a **limited-time beta**. During the beta you can build, test, and publish widgets and runners against the live platform, and beta contributors get a **founding-developer discount** on the paid Developer tier when it launches. ### What you get - **Founding-developer pricing**: a discount on the Developer plan, locked in for as long as you keep your seat active, applied automatically the day the plan opens for sale. - **Direct channel to the core team**: a dedicated `#developer-beta` channel on our Discord for API questions, ship-blocking bugs, and early previews of unreleased endpoints. - **A bug board that the core team watches**: issues you report through the `#developer-beta` channel go to the top of the triage queue. - **Monetization (shipping during the beta)**: charge holders for premium apps and offer paid subscriptions to your widgets; beta participants help us validate revenue-share rates and lock in a better split than the public launch rate. - **Publish to the directory**: beta widgets show up in the App Directory with a `Beta` badge so token owners know they're getting early access. ### How to join Sign up at the [Developer Portal](https://chaindaddy.io/_developer) (replaces the Developer-plan upgrade button while the beta is running). We're accepting developers on a rolling basis; expect a response within a week. A `developerId` and KYC are required before your first widget goes live. The signup captures what you need, handle, portfolio, which widget type you want to build first. ### How to publish The fastest path to ship is the CLI-driven `.crown` package pipeline. Chain Daddy hosts your bundle on its CDN, scans it for security and policy issues, and reviews it. Your source code stays private. ```bash npm install -g @chaindaddy/cli chaindaddy app login # signs a wallet challenge, gets an API key chaindaddy app init widget alice/yield-tracker cd yield-tracker npm install npm run build && npm run pack && npm run sign && npm run submit ``` See [Getting Started](/developer/getting-started) for the full flow. Submissions require an active Developer or Partner subscription. Reference example projects are bundled with the `chaindaddy app init` scaffold, use `--template widget`, `--template headless`, or `--template full` to start from a working baseline. ### Resources | What | Where | |------|-------| | Developer Portal (signup, keys, KYC) | [chaindaddy.io/_developer](https://chaindaddy.io/_developer) | | Discord (`#developer-beta`) | Invite in the signup response | | Widget types | Type definitions ship with the `chaindaddy app init` scaffold (`@chaindaddy/apps/types/widget`) | | Runner SDK | `@chaindaddy/apps/runner` β€” see [Building Runners](/developer/runners) | | Security model | [Security & Auth](/developer/security) | ## What Are Apps? Apps are installable add-ons that token owners install on their pages. They come in three types: | Type | Description | Example | |------|-------------|---------| | **Widget** | Visual React component rendered on the profile page | Market data chart, social feed | | **Headless** | Backend runner that reacts to platform events via webhooks | Price alerts, auto-posting, analytics | | **Full** | Both a widget and a headless runner | Dashboard with live data sync | ## Architecture ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Chain Daddy Platform β”‚ β”‚ β”‚ β”‚ Events Action API β”‚ β”‚ ──────> Your Runner ──────> Storage / Notify β”‚ β”‚ (your infra) β”‚ β”‚ β”‚ β”‚ Props β”‚ β”‚ ──────> Your Widget ──────> Actions (navigate, β”‚ β”‚ (React component) clipboard, toast) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` **Widgets** receive structured data via props and render inside the host page. They never call APIs directly, the platform provides all data they need. **Runners** are HTTPS endpoints you host. The platform delivers events via webhooks (signed with HMAC-SHA256), and runners can call back via the Action API to store data, send notifications, or request approvals. ## Quick Links - **[Getting Started](/developer/getting-started)**: Ship your first app in 10 minutes via the CLI - **[Submission Pipeline](/developer/submission)**: How `.crown` packages flow through Chain Daddy - **[App Manifest](/developer/manifest)**: Full manifest reference - **[Building Runners](/developer/runners)**: Deploy runners on Lambda, Express, or Workers - **[Event Reference](/developer/events)**: All platform event types - **[Actions API](/developer/actions)**: Storage, notifications, metadata, and approvals - **[Widget Development](/developer/widgets)**: React components, props, themes - **[Security & Auth](/developer/security)**: HMAC signing, scopes, rate limits ## SDK & Examples The SDK provides TypeScript helpers for building runners: ```bash npm install @chaindaddy/apps ``` ```typescript import { createWebhookHandler, createActionClient, withIdempotency, MemoryStore, } from '@chaindaddy/apps/runner'; ``` Reference implementations for AWS Lambda, Express, and Cloudflare Workers are bundled with the `chaindaddy app init` scaffold β€” see [Building Runners](/developer/runners#reference-implementations). ## Coming Soon Planned platform features (App Marketplace, Zapier integration, and more) are tracked on the [Roadmap](/developer/roadmap). Custom domain mapping for token pages (Pro+ and above) is also planned for a future release. --- # App Manifest URL: https://docs.chaindaddy.io/developer/manifest Category: developer # App Manifest Every app is defined by a `capp.json` manifest file. This document is the complete reference for all manifest fields. ## Required Fields These fields are required for all app types: | Field | Type | Description | |-------|------|-------------| | `id` | string | Unique identifier. Lowercase alphanumeric + hyphens, 3-64 chars. Pattern: `/^[a-z0-9][a-z0-9-]{2,63}$/` | | `name` | string | Human-readable display name (1-128 chars) | | `version` | string | Semantic version (`major.minor.patch`) | | `author` | object | `{ name, url?, developerId }` | | `description` | string | Short description (1-512 chars) | | `category` | string | One of: `market`, `social`, `analytics`, `utility`, `media`, `governance`, `custom` | | `requiredData` | array | Data scopes the app needs | | `permissions` | array | Platform permissions requested | | `minPlatformVersion` | string | Minimum platform version (semver) | | `license` | string | SPDX license identifier | ## App Type The `type` field determines what components your app has: | Type | Widget | Runner | Default | |------|--------|--------|---------| | `widget` | Required | Not allowed | Yes | | `headless` | Not allowed | Required | No | | `full` | Required | Required | No | When `type` is omitted, it defaults to `widget` for backwards compatibility. ## Widget Fields Required when `type` is `widget` or `full`: | Field | Type | Description | |-------|------|-------------| | `entryComponent` | string | Named export from the bundle (valid JS identifier) | | `bundleUrl` | string | HTTPS URL to the JS bundle (empty string for built-in) | | `bundleHash` | string | SHA-256 hex hash (empty string for built-in) | | `bundleSize` | number | Bundle size in bytes (max 512,000) | ## Runner Section Required when `type` is `headless` or `full`: ```json { "runner": { "endpointUrl": "https://your-server.example.com/webhook", "authType": "hmac-sha256", "events": ["token.claimed", "market.price.threshold"], "healthCheckPath": "/health", "timeout": 30, "schedule": "0 */6 * * *", "retryPolicy": { "maxRetries": 3, "backoffMs": [1000, 5000, 30000] }, "actions": ["apps:storage:write", "notifications:send"] } } ``` | Field | Type | Required | Description | |-------|------|----------|-------------| | `endpointUrl` | string | Yes | HTTPS URL for webhook delivery | | `authType` | string | Yes | `hmac-sha256`, `bearer`, or `custom-header` | | `events` | array | Yes | Event types to subscribe to (at least one) | | `healthCheckPath` | string | No | Path for health checks (e.g., `/health`) | | `timeout` | number | No | Response timeout in seconds (5-300, default 30) | | `schedule` | string | No | Cron expression for `schedule.tick` events | | `retryPolicy` | object | No | `{ maxRetries, backoffMs[] }` | | `actions` | array | No | Action scopes the runner requires | ## Optional Fields | Field | Type | Description | |-------|------|-------------| | `icon` | string | URL to app icon | | `configSchema` | object | JSON Schema (draft-07) for configurable settings | | `supportedChains` | array | Chain keys supported (omit for all chains) | | `tags` | array | Freeform tags for search/filtering | | `repositoryUrl` | string | URL to source repository | ## Data Scopes Declare what token data your app needs. Scope names keep the `crown:` prefix on the wire so existing platform code accepts the same manifests, the scopes describe data about the token registration. | Scope | Description | |-------|-------------| | `profile:basic` | Symbol, name, description, tags | | `profile:social` | Social links, verifications | | `market:price` | Price, volume, market cap | | `market:holders` | Holder count, holder stats | | `crown:ownership` | Token owner address, registration status | | `crown:metadata` | Token metadata extensions | | `crown:identity` | ENS/SNS, social identities | | `chain:info` | Chain ID, name, explorer URL | ## Widget Permissions Permissions for browser/platform capabilities: | Permission | Description | |------------|-------------| | `fetch:self-api` | Fetch to the platform's own API | | `storage:local` | Scoped localStorage for the widget | | `clipboard:write` | Write to system clipboard | | `navigate:internal` | Client-side navigation | ## Action Scopes Permissions for runner-to-platform actions: | Scope | Category | Approval | |-------|----------|----------| | `crown:read` | Read | Never | | `market:read` | Read | Never | | `apps:read` | Read | Never | | `crown:metadata:write` | Write | Configurable | | `apps:config:write` | Write | Configurable | | `apps:storage:write` | Write | Never | | `notifications:send` | Write | Never | | `crown:transfer:initiate` | Dangerous | Always | | `crown:apps:manage` | Dangerous | Always | ## Complete Examples ::: code-group ```json [Widget App] { "id": "market-chart", "name": "Market Chart", "version": "1.0.0", "author": { "name": "Dev Co", "developerId": "dev-123" }, "description": "Interactive price chart for token pages", "type": "widget", "entryComponent": "MarketChart", "bundleUrl": "https://cdn.example.com/market-chart/1.0.0/bundle.js", "bundleHash": "abc123def456...", "bundleSize": 45000, "category": "market", "requiredData": ["market:price", "profile:basic"], "permissions": [], "minPlatformVersion": "1.0.0", "license": "MIT" } ``` ```json [Headless App] { "id": "price-alerter", "name": "Price Alerter", "version": "1.0.0", "author": { "name": "Dev Co", "developerId": "dev-123" }, "description": "Sends notifications when price thresholds are crossed", "type": "headless", "category": "analytics", "requiredData": ["market:price"], "permissions": [], "minPlatformVersion": "1.0.0", "license": "MIT", "runner": { "endpointUrl": "https://runner.example.com/webhook", "authType": "hmac-sha256", "events": ["market.price.threshold", "app.enabled"], "healthCheckPath": "/health", "actions": ["apps:storage:write", "notifications:send"] } } ``` ::: ::: warning Subscription names vs. delivered event names The manifest schema's `runner.events` enum uses the short names `app.enabled`, `app.disabled`, and `app.configured` β€” these are what `chaindaddy app validate` and `chaindaddy app pack` accept (`token.app.enabled` is rejected by the schema). The envelope delivered to your endpoint, however, carries the full event name in its `eventType` field: `token.app.enabled`, `token.app.disabled`, `token.app.configured`. Subscribe with the short names; match on the full names in your handler. See the [Event Reference](/developer/events#event-types). ::: ## Validation Validate your manifest using the SDK: ```typescript import { validateManifest } from '@chaindaddy/apps/runner'; const manifest = JSON.parse(fs.readFileSync('capp.json', 'utf8')); const result = validateManifest(manifest); if (!result.valid) { console.error('Manifest errors:', result.errors); } ``` The same JSON Schema is used by `chaindaddy app validate` and can be fetched from the API at `GET /api/v2/developer/schema/app-manifest` (authenticated). ## Submitting Your App The supported submission path is the `chaindaddy` CLI. Do **not** hand-POST `capp.json` to a backend endpoint β€” the modern submit flow takes a signed `.crown` archive (the manifest + bundle + signature) via multipart upload, not raw manifest JSON. ```bash chaindaddy app validate # local schema check against the JSON Schema above chaindaddy app pack # builds .crown (manifest + bundle + META.json) chaindaddy app sign # signs the package with your developer key chaindaddy app submit # uploads to POST /api/v2/developer/apps/packages ``` `chaindaddy app submit` reads the field names from your `capp.json` as written in this document (camelCase: `entryComponent`, `minPlatformVersion`, `author.developerId`, `repositoryUrl`). The backend's package handler reads those same camelCase fields directly from the embedded manifest β€” no rewriting required. ::: warning Legacy JSON endpoint The older `POST /api/v2/developer/apps/submit` JSON endpoint still exists for the E2E test harness and pre-CLI integrations. It parses a snake_case subset of fields (`entry_point`, `min_crown_version`, `author.wallet`) into its internal validator. New integrations should use the CLI / `/api/v2/developer/apps/packages` path documented above β€” the legacy endpoint is not maintained against the JSON Schema and will reject manifests authored to this document. ::: --- # Paid Apps URL: https://docs.chaindaddy.io/developer/paid-apps Category: developer # Paid Apps Developers on the **Developer** and **Partner** tiers can publish paid apps and earn a revenue share on every active subscription. Holders pay through Chain Daddy's checkout and the platform handles entitlement, renewals, and payouts. ## Eligibility | Tier | Paid apps | Rev share | |------|:---------:|-----------| | Free / Pro / Pro+ | β€” | β€” | | **Developer** | Yes | Standard rate | | **Partner** | Yes | Premium rate | See [Token Plans](/pricing/plans) for the full feature matrix. ## How it works 1. **Build your app** following the [Apps SDK](/developer/getting-started). Mark it as paid in the manifest. 2. **Publish** to the App Directory once approved. Holders see your app in the marketplace. 3. **Holders subscribe** through Chain Daddy's checkout, recurring billing, cancellation, and entitlement are handled by the platform. 4. **You get paid** monthly via the configured payout method (bank transfer or stablecoin) net of the platform's revenue share. ## Revenue share rates The standard share applies to the **Developer** tier; **Partner** tier earns a higher share on the same product. Exact percentages are published in the developer dashboard and reviewed quarterly. ::: tip Coming Soon The full payout pipeline is rolling out alongside the developer beta program. [Apply at the Developer Portal](https://chaindaddy.io/_developer) for early access and founding-developer rates. ::: ## Related docs - [Token Plans](/pricing/plans): feature matrix and pricing - [Developer Getting Started](/developer/getting-started): build your first app - [Widget development](/developer/widgets): packaging widgets for the directory --- # Roadmap URL: https://docs.chaindaddy.io/developer/roadmap Category: developer # Roadmap Chain Daddy ships continuously β€” features move from this list into the product as they're ready, without fixed dates. For what's available today (and on which plan), see [Token Plans](/pricing/plans). ## Coming Soon | Feature | Description | |---------|-------------| | **SEO Settings** | Meta tag customization, Open Graph controls, and indexing settings for token pages | | **Email & Subscriber Collection** | Opt-in email capture on your token page for updates and announcements | | **GA & Pixel Tracking** | Connect Google Analytics or ad pixels to your token page | | **Embed Analytics** | Track impressions, clicks, and engagement on your embedded widgets | | **Custom Domain Mapping** | Serve your token page from your own domain | | **App Marketplace** | Browse and install community-built apps directly from your dashboard | | **Zapier Integration** | Connect Chain Daddy events to 5,000+ apps for automated workflows | | **Paid Apps** | Sell app subscriptions to token owners with revenue share | | **Content Subscriptions** | Charge holders a recurring fee for premium content on your token page | The **Developer** and **Partner** plans are in closed beta and open in rolling waves β€” [apply for the beta](https://chaindaddy.io/_developer) or read the [Developer Beta Program overview](/developer/getting-started). --- Priorities are driven by community feedback. Have a feature request? Post it in the [feature-requests channel on Discord](https://discord.gg/ayeCfghA5z) or email [feedback@chaindaddy.io](mailto:feedback@chaindaddy.io). --- # Building Runners URL: https://docs.chaindaddy.io/developer/runners Category: developer # Building Runners Runners are HTTPS endpoints you host that receive platform events via webhooks. This guide covers setup, deployment, and best practices. ## How Runners Work 1. You register a runner endpoint with the platform 2. The platform sends signed webhooks when events your manifest subscribes to occur (see [Event Subscriptions](#event-subscriptions)) 3. Your runner verifies the signature, processes the event, and responds 4. Optionally, your runner calls the [Action API](/developer/actions) to interact with the platform ![Sequence diagram of the runner round-trip: the platform delivers a signed event to runners whose manifest subscribes to it, with an empty subscription list receiving everything; the runner verifies the HMAC signature, dedupes by eventId, and processes the event, then optionally calls the Action API with its own signed request, which is checked against scopes and rate limits; test.ping is always delivered](/diagrams/runner-roundtrip-light.svg){.light-only} ![Sequence diagram of the runner round-trip: the platform delivers a signed event to runners whose manifest subscribes to it, with an empty subscription list receiving everything; the runner verifies the HMAC signature, dedupes by eventId, and processes the event, then optionally calls the Action API with its own signed request, which is checked against scopes and rate limits; test.ping is always delivered](/diagrams/runner-roundtrip-dark.svg){.dark-only} ## Authenticating to the Developer API All `/api/v2/developer/*` endpoints (including runner management below) require a **bearer token** on `Authorization: Bearer `. Two ways to get one: - **Web session (JWT)**: sign in with your wallet at [chaindaddy.io/_developer](https://chaindaddy.io/_developer). The dashboard authenticates every developer API call with the session JWT it obtains from the wallet sign-in flow (`GET /api/v2/auth/nonce` β†’ `POST /api/v2/auth/login/siwe`). If you are scripting against these endpoints directly, reuse that flow to mint a session token. - **CLI login**: run `chaindaddy app login` β€” it signs a single-use wallet challenge (`POST /api/v2/developer/auth/cli-challenge` β†’ `POST /api/v2/developer/auth/cli-token`) and stores the returned credential, which the CLI then sends as its bearer token. The examples below show a JWT. In practice, most developers never call these endpoints by hand β€” `chaindaddy app init headless` scaffolds the runner and registers it for you. ## Runner Registration Register your runner via the API: ```bash curl -X POST "https://api.chaindaddy.io/api/v2/developer/apps/{appId}/runners" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "endpointUrl": "https://your-server.example.com/webhook", "authType": "hmac-sha256", "healthCheckPath": "/health" }' ``` The events your runner receives are NOT part of this registration call β€” they come from your app manifest's `runner.events` list (see [Event Subscriptions](#event-subscriptions)). **Response:** ```json { "id": "runner-uuid", "appId": "my-app", "endpointUrl": "https://your-server.example.com/webhook", "authType": "hmac-sha256", "webhookSecret": "a1b2c3d4e5f6...", "healthStatus": "unknown", "createdAt": "2025-01-15T10:00:00Z" } ``` ::: warning Save the Secret The `webhookSecret` is only returned once. Store it securely as an environment variable. ::: ## Event Subscriptions Events are delivered to runners whose manifest subscribes to the event: the platform filters every dispatch against the `runner.events` list in your app's live (latest approved) manifest. - Both the legacy short form (`app.enabled`, `app.disabled`, `app.configured`) and the canonical wire form (`token.app.enabled`, `token.app.disabled`, `token.app.configured`) match each other β€” declare either and you receive the canonical wire event. - An **empty or absent** `events` list receives **everything** (back-compat for manifests written before filtering). - A non-empty list receives **only** the events it names (after alias normalization). All other event types require an exact name match β€” see the [Event Reference](/developer/events) for names. - `test.ping` sent by the [verify endpoint](#verification) is always delivered regardless of your subscription list β€” it's a connectivity check, not a platform event. - Apps without an approved submission yet (dev-preview installs) are not filtered: all events are delivered. To change your subscriptions, submit a new app version with an updated `runner.events` list β€” the filter follows the latest approved manifest. ## Management API All endpoints require `Authorization: Bearer ` (see [Authenticating to the Developer API](#authenticating-to-the-developer-api)). | Method | Endpoint | Description | |--------|----------|-------------| | POST | `/api/v2/developer/apps/{appId}/runners` | Register a new runner | | GET | `/api/v2/developer/apps/{appId}/runners` | List all runners | | DELETE | `/api/v2/developer/apps/{appId}/runners/{runnerId}` | Delete a runner | | POST | `/api/v2/developer/apps/{appId}/runners/{runnerId}/verify` | Verify connectivity | ## Verification After registering, verify your runner is reachable: ```bash curl -X POST "https://api.chaindaddy.io/api/v2/developer/apps/{appId}/runners/{runnerId}/verify" \ -H "Authorization: Bearer " ``` This sends a `test.ping` event to your endpoint. If your runner responds with `{"status":"ok"}`, its health status updates to `healthy`. Verification also resets the circuit breaker if it was open due to consecutive failures. ## HMAC Signature Verification For `hmac-sha256` auth, the platform signs each request body. Your runner must verify the signature before processing. **Algorithm:** 1. Hex-decode the webhook secret into bytes 2. Compute HMAC-SHA256 of the raw request body using the secret 3. Compare the hex digest with the `X-App-Signature` header 4. Use constant-time comparison to prevent timing attacks ::: code-group ```typescript [Node.js] import { createHmac, timingSafeEqual } from 'node:crypto'; function verifySignature(secret: string, body: string, signature: string): boolean { const key = Buffer.from(secret, 'hex'); const expected = createHmac('sha256', key).update(body, 'utf8').digest('hex'); if (expected.length !== signature.length) return false; return timingSafeEqual(Buffer.from(expected), Buffer.from(signature)); } ``` ```typescript [Cloudflare Workers] async function verifySignature(secret: string, body: string, signature: string): Promise { const key = hexToBytes(secret); const cryptoKey = await crypto.subtle.importKey( 'raw', key.buffer, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign'] ); const sig = await crypto.subtle.sign('HMAC', cryptoKey, new TextEncoder().encode(body)); const expected = bytesToHex(new Uint8Array(sig)); // Constant-time comparison if (expected.length !== signature.length) return false; let result = 0; for (let i = 0; i < expected.length; i++) { result |= expected.charCodeAt(i) ^ signature.charCodeAt(i); } return result === 0; } ``` ::: ## Health Check If you declared `healthCheckPath` in your manifest, the platform periodically pings: ``` GET {endpointUrl}{healthCheckPath} ``` Expected response: ```json { "status": "healthy", "version": "1.0.0" } ``` | Status | Meaning | |--------|---------| | `healthy` | Runner is operational | | `degraded` | Runner is working but with reduced capacity | | `unhealthy` | Runner cannot process events | ## Idempotency Events may be delivered more than once. Use the `eventId` field to deduplicate: 1. Before processing, check if `eventId` has been seen before 2. If yes, return `{"status":"ok","message":"duplicate event, skipped"}` 3. If no, process the event, then store the `eventId` with a 24-hour TTL **Using the SDK:** ```typescript import { withIdempotency, MemoryStore } from '@chaindaddy/apps/runner'; const store = new MemoryStore(); // Use DynamoDB/Redis in production const handler = withIdempotency(async (event) => { // Your logic here... return { status: 'ok' }; }, store); ``` **DynamoDB (Lambda):** Use conditional `PutItem` with `attribute_not_exists` for atomic dedup. **KV (Workers):** Check `kv.get(eventId)` before processing, then `kv.put(eventId, '1', { expirationTtl: 86400 })`. ## Reference Implementations Complete, deployable starter templates are available: ### AWS Lambda SAM template with API Gateway, Lambda (Node.js 20), and DynamoDB for idempotency. ```bash cd examples/lambda-runner npm install sam build sam deploy --parameter-overrides WebhookSecret=YOUR_SECRET ``` ### Express + Docker Express server with Dockerfile for containerized deployment. ```bash cd examples/express-runner npm install cp .env.example .env # Configure your secret npm run dev # Development with auto-reload docker-compose up # Production via Docker ``` ### Cloudflare Worker Worker with KV namespace for idempotency. ```bash cd examples/cloudflare-runner npm install wrangler secret put WEBHOOK_SECRET wrangler kv namespace create IDEMPOTENCY wrangler deploy ``` All three example projects ship with the `chaindaddy app init headless` scaffold (also available with the developer beta β€” sign up at [chaindaddy.io/_developer](https://chaindaddy.io/_developer)). ## Environment Variables All runner examples use consistent environment variables: | Variable | Description | |----------|-------------| | `WEBHOOK_SECRET` | Hex-encoded secret from runner registration | | `APP_ID` | Your app identifier | | `API_BASE_URL` | Platform API URL (default: `https://api.chaindaddy.io`) | --- # Security & Auth URL: https://docs.chaindaddy.io/developer/security Category: developer # Security & Auth The app system uses a bidirectional authentication model: the platform signs events sent to your runner, and your runner signs actions sent to the platform. The same key material is used in both directions. ## Authentication Methods ### HMAC-SHA256 (Recommended) The platform generates a shared secret during runner registration. Both sides use it for signing. **Inbound (platform -> runner):** 1. Platform computes `HMAC-SHA256(secret, requestBody)` 2. Hex signature is sent in `X-App-Signature` header 3. Runner verifies by computing the same HMAC and comparing **Outbound (runner -> platform):** 1. Runner computes `HMAC-SHA256(secret, requestBody)` 2. Hex signature is sent in `X-App-Signature` header 3. Platform verifies the signature ### Bearer Token Developer provides a static token during registration. The platform sends it as `Authorization: Bearer {token}`. ### Custom Header Developer specifies a header name and value during registration. The platform includes it on every request. ::: tip Recommendation Use `hmac-sha256` for the strongest security. It provides integrity verification (the body hasn't been tampered with) and authentication (the request came from the platform). ::: ## Permission Scopes Actions are organized into three tiers based on their impact: ### Read Scopes Read-only access. Never requires approval. | Scope | Description | |-------|-------------| | `crown:read` | Read token page data (registration, market, social, etc.) | | `market:read` | Read market data | | `apps:read` | Read app configurations | ### Write Scopes Modify data. Some may require approval based on token owner settings. | Scope | Description | Approval | |-------|-------------|----------| | `crown:metadata:write` | Update token metadata | Configurable | | `apps:config:write` | Update app config | Configurable | | `apps:storage:write` | Read/write app storage | Never | | `notifications:send` | Send notifications | Never | ### Dangerous Scopes High-impact actions. Always require explicit token owner approval. | Scope | Description | |-------|-------------| | `crown:transfer:initiate` | Initiate registration ownership transfer | | `crown:apps:manage` | Enable/disable apps on a token | ## Approval Flow When a runner requests a dangerous action: 1. **Runner** sends the action request 2. **Platform** creates a pending approval and returns `approval_id` 3. **Token owner** sees the approval in their dashboard 4. **Token owner** approves or denies within 24 hours 5. If approved, the platform executes the action 6. If denied or expired, the action is discarded ::: warning Expiry Pending approvals expire after 24 hours. The runner must re-request expired actions. ::: ## Audit Logging Every action attempt is logged: - **Scope:** 100% of action API calls (successful and failed) - **Retention:** 90 days - **Immutable:** Logs cannot be modified or deleted Token owners can view the audit log in their dashboard or via the API: ``` GET /api/v2/registration/{id}/app-actions ``` **Authentication required**: this endpoint is gated by the platform's wallet session auth β€” send `Authorization: Bearer ` for the token owner's or a manager's signed-in session. (An unauthenticated or wrong-wallet request returns `401`/`403`; the action log reveals pending approvals, which is why it is not public.) Query parameters: | Parameter | Description | |-----------|-------------| | `appId` | Filter by app | | `action` | Filter by action type | | `status` | Filter by status (`completed`, `pending`, `denied`, `failed`) | | `since` | ISO 8601 start date | | `limit` | Max results (default 50) | ## Rate Limiting Actions are rate-limited per runner with sliding windows, by category (Read / Write / Storage / Notifications / Dangerous). The limits, the rate-limit response headers, and 429 handling are documented in the [Actions API](/developer/actions#rate-limits). ### Abuse Detection The platform tracks rate limit violations. After 10 violations within 5 minutes, the runner is automatically suspended. Contact support to re-enable a suspended runner. ## Storage Isolation App storage is strictly isolated: - App A **cannot** read App B's storage - Storage keys are scoped to `(app_id, crown_id, key)` tuples, `crown_id` is the platform's internal id for a token registration - Each app gets its own quota per token β€” quota amounts and per-request size limits are listed in the [Actions API](/developer/actions#storage) Request bodies to the Action API are capped at 1 MB. ## Best Practices 1. **Always verify signatures** before processing webhooks 2. **Use constant-time comparison** for signature verification (prevent timing attacks) 3. **Implement idempotency**: events may be delivered more than once 4. **Handle unknown events gracefully**: log and return `ok` 5. **Namespace metadata keys** with your app ID (e.g., `myApp_score`) 6. **Store secrets securely**: use environment variables or secrets managers, never commit them 7. **Respect rate limits**: read `Retry-After` headers and back off accordingly --- # Submitting an App URL: https://docs.chaindaddy.io/developer/submission Category: developer # Submitting an App Package your app locally, sign it, upload a single `.crown` artifact, and Chain Daddy scans, hosts, and reviews it. The CLI handles every step, `pack`, `sign`, `submit`. ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” pack β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” sign β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” submit β”‚ manifest + β”œβ”€β”€β”€β”€β”€β”€β”€β”€β–Ίβ”‚ signed .crown β”œβ”€β”€β”€β”€β”€β”€β”€β”€β–Ίβ”‚ signed + replay- β”œβ”€β”€β”€β”€β”€β”€β”€β”€β–Ί Chain Daddy β”‚ bundle + assets β”‚ β”‚ archive (8 MB max) β”‚ β”‚ protected artifact β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` You don't host the bundle. Chain Daddy extracts it from the package and serves it from `apps.chaindaddy.io/{appId}/{version}/bundle.js` with immutable caching. Your source code stays on your laptop or in your private git repo. > The `.crown` archive contains the app manifest, the compiled bundle, > a runner config (if any), and assets, all integrity-checked. --- ## Prerequisites - A registered developer account with a verified KYC status - An active Developer or Partner subscription - The `@chaindaddy/cli` CLI installed (`npm install -g @chaindaddy/cli`) - An API key (run `chaindaddy app key create --save`) Use the `.crown` flow described below. --- ## Step 1: Build ```bash chaindaddy app build # widgets only, bundles src/index.tsx to dist/bundle.js ``` The CLI's default bundler is esbuild with `react` and `react-dom` declared as externals, minification on, source maps off. If you need a custom build, run your own bundler and skip to step 2 with `chaindaddy app pack --bundle path/to/bundle.js`. --- ## Step 2: Package ```bash chaindaddy app pack ``` Produces a `.crown` file at `dist/{slug}-{version}.crown`. The package contains: | Entry | Required for | Purpose | |-------|--------------|---------| | `META.json` | always | format version, SDK version, build environment | | `manifest.json` | always | the schema-validated app manifest (named `capp.json` in your source tree) | | `bundle.js` | widget, full | your compiled widget | | `runner.config.json` | headless, full | runner registration payload | | `assets/**` | optional | icons, screenshots, cover image | | `HASHES.json` | always | SHA-256 of every other entry | | `signature.json` | after `sign` | HMAC over manifest + HASHES | The `pack` step is reproducible by default, running it twice on the same source produces byte-identical archives. Disable with `--no-reproducible` if you want real timestamps for debugging. The archive follows the `.capp` package format spec (the format's internal name); the full spec document is available with the developer beta β€” sign up at [chaindaddy.io/_developer](https://chaindaddy.io/_developer). Use `chaindaddy app inspect ` to see exactly what a built archive contains. --- ## Step 3: Sign ```bash chaindaddy app sign dist/yield-tracker-0.1.0.crown --in-place ``` Signing computes an HMAC-SHA256 over a canonical payload (the manifest, the HASHES.json, plus identity fields) using your API key secret. The signature is added as `signature.json` inside the same archive. Why sign: 1. **Authenticity**: Chain Daddy records the signature so we can prove *which* of your keys uploaded the artifact. 2. **Replay protection**: `signedAt` is checked against the server clock (24 h window, 5 min skew). Reusing the same `signedPayloadSha256` within the window is also rejected. 3. **Required at ingest**: unsigned packages are rejected. Run `sign` between `pack` and `submit`. You can sign in an environment that has the secret (your laptop, a CI secret store) and upload from one that doesn't (a sandbox runner): the secret never has to travel with the package. --- ## Step 4: Submit ```bash chaindaddy app submit dist/yield-tracker-0.1.0.crown --watch ``` Chain Daddy runs (in order): 1. **Pre-checks**: size ≀ 8 MB, MIME is zip, safe extract (no path traversal, no symlinks), well-formed entries. 2. **Cross-checks**: `META.appId` == `manifest.id`, `HASHES.json` matches every file, `appSha256` matches the Merkle summary, `bundleHash` matches `bundle.js`. 3. **Signature**: replay window check + HMAC verification. The server recovers your API key secret from its encrypted-at-rest store (sealed at issue time with AES-256-GCM) and re-computes the HMAC over a canonical payload. A mismatch returns `PACKAGE_SIGNATURE_MISMATCH`; an unknown key returns `PACKAGE_UNKNOWN_KEY` (rotate the key to fix). 4. **Manifest schema**: the same JSON Schema the CLI uses. 5. **Auto-checks**: CSP scan, accessibility scan, security risk scan (sandbox escapes, prototype pollution, XSS sinks, data exfiltration, wallet bypass), standards conformance, tier-cap enforcement. 6. **Bundle upload**: `bundle.js` and `assets/**` are uploaded to `apps.chaindaddy.io/{appId}/{version}/...` with immutable cache headers. 7. **Manifest rewrite**: `bundleUrl`, `bundleHash`, `bundleSize` are overwritten with the platform-assigned values. 8. **Submission record**: created in `pending` status. The developer can install on their own tokens for preview testing. When ready, `chaindaddy app request-publish ` moves it into the human-review queue. The submission then moves through this lifecycle: ![State diagram of the submission lifecycle: a submitted app starts in pending; a failed scanner check moves it to auto_check_failed, where you fix, bump the version, and submit a new package; request-publish moves it to in_review, where the reviewer signs off, moving it to approved and then published, or rejects it, moving it to review_failed; a withdrawn submission ends as rejected](/diagrams/submission-states-light.svg){.light-only} ![State diagram of the submission lifecycle: a submitted app starts in pending; a failed scanner check moves it to auto_check_failed, where you fix, bump the version, and submit a new package; request-publish moves it to in_review, where the reviewer signs off, moving it to approved and then published, or rejects it, moving it to review_failed; a withdrawn submission ends as rejected](/diagrams/submission-states-dark.svg){.dark-only} `--watch` streams the scan log to your terminal and exits when the submission reaches a terminal state: | Status | Meaning | |--------|---------| | `pending` | Submitted; auto-checks running OR dev iterating in preview | | `in_review` | Developer requested publish; in the human-review queue | | `approved` | Auto-checks passed; reviewer signed off | | `published` | Live in the registry; users can install on their tokens | | `auto_check_failed` | The bundle failed a scanner check; see `app logs ` | | `review_failed` | A human reviewer rejected the submission | | `rejected` | Withdrawn | --- ## Step 5: Iterate If auto-checks fail, the scan log tells you exactly which rule fired: ``` [INFO] package_extract extracted 142 KB package (sha256 8f3c…) [INFO] package_signature signature verified (keyId=cd_live_3f7c…) [ERROR] csp_scan 1 CSP errors found [INFO] accessibility_scan score=92, 1 issues [INFO] security_scan 0 critical, 0 high, 2 medium, 0 low [INFO] standards_conformance 0 findings [INFO] bundle_size bundle is 142337 bytes (uncompressed) [INFO] auto_check_complete auto-check status: failed ``` Read the structured details: ```bash chaindaddy app status --json | jq '.auto_check_results' ``` Then fix, bump the patch version, and re-run from step 1. The version bump is required, duplicate (appId, version) pairs are rejected. --- ## Endpoint reference The CLI exists so you don't have to call these directly, but for tools that integrate at a lower level: | Method | Path | Auth | Purpose | |--------|------|------|---------| | `POST` | `/api/v2/developer/auth/cli-challenge` | none | get a challenge to sign with your wallet | | `POST` | `/api/v2/developer/auth/cli-token` | wallet signature | exchange a signed challenge for an API key | | `POST` | `/api/v2/developer/apps/packages` | bearer + multipart | upload a signed `.crown` | | `GET` | `/api/v2/developer/apps/submissions/{id}` | bearer | fetch submission state | | `GET` | `/api/v2/developer/apps/submissions/{id}/scan-log` | bearer | fetch (or stream with `?stream=1`) scan events | | `POST` | `/api/v2/developer/apps/submissions/{id}/request-publish` | bearer | move pending β†’ in_review | | `POST` | `/api/v2/developer/keys` | bearer | mint a new API key | | `GET` | `/api/v2/developer/keys` | bearer | list keys | | `POST` | `/api/v2/developer/keys/{id}/rotate` | bearer | rotate a key | | `DELETE` | `/api/v2/developer/keys/{id}` | bearer | revoke a key | Bearer-protected endpoints require a wallet session token on `Authorization: Bearer …` β€” the web dashboard uses its sign-in session (JWT), and the CLI uses the credential minted by the challenge β†’ token flow above (stored by `chaindaddy app login`). --- ## Why use the .crown flow? - **No bundle hosting.** Chain Daddy serves the bundle from its CDN. - **Integrity guaranteed.** No more "your CDN cached a stale bundle and the manifest hash drifted" bugs. - **Reproducible builds.** Two CI runs of the same commit produce the same package bytes. - **Replay protection** via signed timestamps. - **Your source stays on your machine.** Only the compiled bundle is uploaded. - **Agent-friendly.** One artifact, one command, one exit code. A legacy JSON endpoint (`POST /api/v2/developer/apps/submit`) remains online for tools built before the package format shipped. --- ## See also - [`chaindaddy app` CLI reference](/api-reference/cli) (or read the source in the CLI package) - [Security model](./security.md): sandbox, runner auth, permission scopes - [Getting Started](./getting-started.md): the happy path from zero --- # Widget Development URL: https://docs.chaindaddy.io/developer/widgets Category: developer # Widget Development Widgets are React components that render on token pages. They receive structured data via props and never call APIs directly. ## Architecture - Rendered directly in the host page React tree (not iframes) - Receive all data via props, no direct API calls - SHA-256 integrity verification before execution - Sandboxed globals (`eval`, `Function`, `document.cookie` blocked) - Scoped localStorage (prefixed per widget ID) - DOM containment via MutationObserver ## Widget Props Every widget receives `AppWidgetProps`: ```typescript interface AppWidgetProps> { appData: AppDataContext; // Token data for the current page settings: TSettings; // Widget-specific config widgetId: string; // Your widget ID isOwner: boolean; // Whether the viewer owns this token connectedAddress: string | null; // Viewer's wallet address chainKey: string; // Chain key (e.g., "arb") theme: AppWidgetTheme; // Host page colors onAction: (action) => void; // Dispatch actions to the host breakpoint?: 'compact' | 'standard' | 'wide'; } ``` ## Token Data The `appData` object provides structured token data: ```typescript interface AppDataContext { symbol: string; // "DOGE" tokenName: string | null; description: string | null; tags: string[]; chainKey: string; // "arb" chainId: number | string; chainName: string; // "Arbitrum One" tokenAddress: string | null; owner: string | null; // Token owner's wallet address status: string; // "active", "at-risk", "inactive" tokenId: number | null; market: { price: number | null; volume24h: number | null; marketCap: number | null; holders: number | null; totalSupply: number | null; circulatingSupply: number | null; liquidity?: number | null; txns24h?: number | null; priceChange1h?: number | null; priceChange6h?: number | null; priceChange24h?: number | null; sparkline7d?: number[] | null; }; socialLinks: { website: string | null; xdotcom: string | null; telegram: string | null; discord: string | null; github: string | null; whitepaper: string | null; }; verifications: { ... }; // Per-platform verification records metadata: Record; } ``` The full type definition ships with the SDK β€” import it from `@chaindaddy/apps/types/widget` in a project scaffolded by `chaindaddy app init widget`. ## Theme Match the host page's styling using the theme object: ```typescript interface AppWidgetTheme { mode: 'light' | 'dark'; accentColor: string; backgroundColor: string; cardBackground: string; textPrimary: string; textSecondary: string; textMuted: string; borderColor: string; } ``` ## Actions Dispatch actions to the host platform via `onAction()`: ```typescript // Navigate within the platform (token pages live at /{symbol}/{chain}) onAction({ type: 'navigate', path: '/doge/arbitrum' }); // Copy text to clipboard onAction({ type: 'clipboard', text: 'DOGE' }); // Fire an analytics event onAction({ type: 'track', event: 'widget_clicked', data: { section: 'price' } }); // Show a toast notification onAction({ type: 'toast', message: 'Copied!', variant: 'success' }); // Open a platform modal onAction({ type: 'modal', modal: 'holders', data: { symbol: 'DOGE' } }); ``` The full action union (`AppWidgetAction`) also covers `api-call`, `connect-wallet`, `sign-typed-data`, `transaction`, and `quote` β€” each shape is declared in `@chaindaddy/apps/types/widget`, bundled with the `chaindaddy app init widget` scaffold. ## Responsive Design Widgets receive a `breakpoint` prop based on their container width: | Breakpoint | Description | |------------|-------------| | `compact` | Narrow container (sidebar, mobile) | | `standard` | Default width | | `wide` | Full-width container | Adapt your layout based on the breakpoint: ```tsx export function MyWidget({ appData, breakpoint }: AppWidgetProps) { if (breakpoint === 'compact') { return ; } return ; } ``` ## Configurable Settings Define a `configSchema` in your manifest to let token owners customize your widget: ```json { "configSchema": { "type": "object", "properties": { "showVolume": { "type": "boolean", "description": "Show 24h trading volume", "default": true }, "alertPrice": { "type": "number", "description": "Price alert threshold" } } } } ``` Access settings via the `settings` prop: ```tsx export function MyWidget({ appData, settings }: AppWidgetProps) { return (

Price: ${appData.market.price}

{settings.showVolume &&

Volume: ${appData.market.volume24h}

}
); } ``` ## Lifecycle Hooks Widgets can optionally implement lifecycle hooks: ```typescript interface AppWidgetLifecycleHooks { onWidgetMount?(context): void | Promise; onWidgetUnmount?(context): void; onDataUpdate?(prevData, nextData): void; onSettingsChange?(prevSettings, nextSettings): void; onVisibilityChange?(visible: boolean): void; } ``` The lifecycle context (`WidgetLifecycleContext`) provides `widgetId`, `appData`, `scopedStorage`, and an `abortController` for async cleanup. ## SSR Compatibility Widgets can export a `renderStatic()` function for server-side rendering: ```typescript export function renderStatic(appData: AppDataContext): string { return `
Price
${appData.market.price ?? 'N/A'}
Volume
${appData.market.volume24h ?? 'N/A'}
`; } ``` ## Building Your Widget Widgets must compile to a single JavaScript bundle: 1. Under 500 KB 2. Export the component matching `entryComponent` as a named export 3. Do not import React, it's provided by the host as an external 4. Do not use `eval()`, `new Function()`, or access `document.cookie` Example esbuild config: ```javascript import { build } from 'esbuild'; await build({ entryPoints: ['src/index.tsx'], bundle: true, format: 'esm', outfile: 'dist/bundle.js', external: ['react', 'react-dom', 'react/jsx-runtime'], minify: true, }); ``` ## Minimal Example ```tsx import type { AppWidgetProps } from '@chaindaddy/apps/types/widget'; interface MySettings { showVolume?: boolean; } export function MyWidget({ appData, settings, theme, onAction, }: AppWidgetProps) { return (

{appData.symbol}

Price: ${appData.market.price?.toFixed(6) ?? 'N/A'}

{settings.showVolume && (

Volume: ${appData.market.volume24h?.toLocaleString() ?? 'N/A'}

)}
); } ``` ## Security Model | Layer | Enforcement | |-------|-------------| | Bundle integrity | SHA-256 hash verified before execution | | Bundle size | Rejected if > 500 KB | | Sandboxed globals | `eval`, `Function`, `document.cookie`, `sessionStorage` blocked | | Scoped storage | `localStorage` keys prefixed with widget ID | | Fetch restriction | Only `/api/` paths with `fetch:self-api` permission | | DOM containment | Modifications outside widget container are prevented | | CSP | Script sources locked to known CDN domains | ## White-Label Embedding {#white-label} Partner tier and above can embed widgets without Chain Daddy branding. White-label mode removes the "Powered by Chain Daddy" footer and platform attribution from all embedded widgets and overlays. To enable white-label mode, set `branding: false` in your widget configuration: ```typescript { widgetId: 'your-widget-id', branding: false, // Partner tier required } ``` ## Custom Branding {#branding} Developer tier and above can customize widget branding with their own colors, logo, and call-to-action text. Custom branding overrides the default Chain Daddy styling while keeping the widget functional. Configure branding in your widget settings: ```typescript { branding: { logo: 'https://your-domain.com/logo.png', primaryColor: '#FF6B00', ctaText: 'Buy on YourDEX', } } ``` --- # FAQ URL: https://docs.chaindaddy.io/faq Category: general # Frequently Asked Questions ## Registration & Ownership
What is a token registration? A registration is a verified on-chain credential proving you own a specific token name on a specific chain. It's recorded on the same chain your project uses and serves as the authoritative record of name ownership. *(Under the hood it's a soulbound NFT. You don't need to think about that to use Chain Daddy.)* Each registration represents a specific token's ticker on a specific chain (e.g., the DOGE token at address 0x123... on Ethereum). The registered owner controls the token's metadata, listing data, and token page.
How is this different from a bio-link page? A bio-link page is a URL with some links. Anyone can claim anything. Nothing is verified. A Chain Daddy registration is a verified on-chain record proving you own a project, with a customizable token page built on top of it and a health score monitoring whether you're still active. The page is what people see. The on-chain proof is why they should trust it.
Can I transfer my registration to another wallet? No. Registrations are permanently bound to your wallet. They cannot be transferred, sold, or traded. This is enforced at the smart contract level. If you need to change ownership, you can: - **Release** your registration (retires the on-chain credential and frees the ticker for anyone to register) - Use the [deals system](/creator-tools/deals) to facilitate a structured ownership transition with built-in holder protections ::: tip Recommendation Register from a multisig wallet (like a Safe) for built-in key rotation and recovery without losing your registration. :::
What if I lose access to my wallet? Nobody can recover it for you. There are no admin functions to move or reassign registrations. Your options: 1. **Wait for activity decay**: If your token's health score stays below 60 for 30+ consecutive days, the registration expires and the ticker becomes available again 2. **Register from a new wallet**: Once expired, anyone (including you from a new wallet) can register the ticker through the standard flow ([see pricing](/pricing/registration)) ::: warning Prevention To avoid this scenario, register from a multisig wallet. Multisig wallets allow key rotation without changing the wallet address, so you can recover access even if individual keys are compromised. :::
What happens when a registration expires? When a token's health score drops below the threshold for an extended period, the registration expires and the ticker becomes **eligible for re-registration** again β€” by the original owner or by anyone else who passes [verification](/token/verification-methods). Expiry isn't a loss; it simply reopens the slot, so an active project can re-register while an abandoned ticker doesn't stay locked forever. There is no separate "reclaim" process. Re-registering an expired ticker works exactly like a fresh registration β€” verify ownership, pay the fee, done β€” whether you're the original owner coming back or a new registrant.
Can Chain Daddy take my registration or reassign it? No. The smart contract has no admin functions for restoring or forcibly transferring registrations. Chain Daddy cannot: - Revoke or release your registration - Transfer it to another wallet - Override your metadata - Bypass the health score system The only way a registration changes hands is through natural activity decay (inactivity) or an explicit owner-initiated release or deal.
What happens if two people register the same name? Each registration is tied to a specific token contract on a specific chain. If multiple tokens share the same ticker on the same chain, each can have its own registration. The first valid registration for a given (symbol, chain, token) slot wins and is not displaced β€” there is no mechanism for a "stronger" verification to take over an existing registration. [Verification method strength](/token/verification-methods) matters only when a slot is open (unclaimed or expired). If someone else holds the slot for your token, your path is to wait for their registration to expire through activity decay β€” a squatter can't keep it without genuine on-chain activity β€” and claim it then.
## Costs & Pricing
How much does it cost? For the current rate card, see [Registration & Creation Pricing](/pricing/registration) (one-time fees) and [Token Plans](/pricing/plans) (recurring tools and API access). [OG projects](/pricing/registration#og-free-registration) pay no platform fee β€” only gas.
What are gas costs? Gas is paid to the chain, not to Chain Daddy, and varies by network β€” L2s and Solana are consistently under a dollar, Ethereum mainnet swings the most. See the [gas estimates table](/pricing/registration#gas-estimates) for typical per-chain costs.
Do I qualify as an OG project? You may qualify for free registration (no platform fee, gas only) if your token is 60+ days old with sufficient market cap and liquidity β€” checked automatically at registration time. See [OG Free Registration](/pricing/registration#og-free-registration) for the exact thresholds.
## Chains & Tokens
What chains are supported? Live today: Ethereum, Arbitrum, Base, Polygon, BNB Chain, Avalanche, Gnosis, and Solana. More chains (starting with Optimism) are coming β€” see the full [supported chains table](/getting-started/what-is-chain-daddy#supported-chains) for tiers and details. Token verification and creation work on all live chains. Upcoming chains have token data pre-populated via our data pipeline.
Can I register a token I didn't create? Yes, if you can prove ownership through one of the supported [verification methods](/token/verification-methods): - **Deployer**: Your wallet deployed the token contract - **Owner**: The contract's `owner()` function returns your address - **Mint/Update Authority** (Solana): You control minting or metadata - **Majority Holder**: You hold >50% of the token supply You don't need to be the original deployer. Any valid verification method works.
Can I have the same name on multiple chains? Yes. Each chain has its own registration for a given ticker. You can register DOGE on Arbitrum, DOGE on Solana, and DOGE on Base β€” each is a separate registration. Register them from the same wallet and they [link automatically](/token/cross-chain) under one unified token page β€” no linking fee, no extra step. Buying 2+ chains in one order gets the multi-chain bundle discount ([see pricing](/pricing/registration)).
## Airdrops & Distribution
How do airdrops work β€” does Chain Daddy hold my tokens? No. Airdrops are non-custodial: your tokens stay in your own wallet, and you approve a spending allowance (capped at your campaign budget) to a distributor address. Each confirmed claim transfers directly from your wallet to the claimant, and revoking the allowance stops distribution instantly. See the [Airdrops guide](/creator-tools/airdrops) for modes (allowlist vs first-come-first-serve), eligibility gates, and funding.
Is claiming an airdrop safe? What am I signing? Claiming is free and risk-free for the recipient: you sign a short message that proves you control your wallet β€” it moves nothing and grants no permissions β€” and the tokens are then sent to you, with gas paid by the distributor. You never submit a transaction or approve anything. More detail in [Claim Statuses and Troubleshooting](/creator-tools/airdrops#claim-statuses-and-troubleshooting).
## Apps & Extensibility
Can I extend my token page with apps? Yes. Apps are services that extend your token page β€” headless (API-only) or visual (embeddable widgets). Examples include tip widgets, buy buttons, and holder snapshots. See [Creator Tools](/creator-tools/integrations) for available integrations, or browse the App Directory from your token page's Apps tab.
## Activity & Risk
How does the health score work? Your health score is a 0-100 number, computed daily from three on-chain signals: - **Activity timestamp** (50%): How long since the listing was registered (a stepped decay) - **Trading volume** (30%): DEX volume, smoothed and capped against pool liquidity to filter wash trading - **Holder health** (20%): The shape of your holder distribution β€” concentration, suspicious wallets, breadth If your score stays below 60 for 30 consecutive days (after the 30-day new-registration grace period), the registration expires and the ticker becomes available for anyone to register through the standard flow ([see pricing](/pricing/registration)). See [Token Health & Activity](/platform/heartbeat) for full details.
How do I prevent my registration from going inactive? Keep your token active: - Maintain regular trading volume - Grow your holder count - Keep your token listed on on-chain exchanges New registrations have a 30-day grace period during which the listing cannot be reclaimed regardless of score. After grace, if your score drops below 60 you'll receive alerts (Pro subscribers get email/push notifications) and have 30 days to recover before the slot becomes reclaimable.
What stops people from hoarding tickers? Ticker squatting is prevented through: 1. **Activity decay**: Tokens whose health score stays below 60 for 30 consecutive days lose their registration β€” a squatter can't hold a name without keeping the token genuinely active 2. **First-claim-wins**: Expired tickers become available to anyone, so real projects can take over abandoned names 3. **Expired-slot reclaim**: Re-registering an expired ticker goes through the standard registration flow ([see pricing](/pricing/registration)) See [Token Health & Activity](/platform/heartbeat) for the full mechanism.
## Technical
Is the underlying contract upgradeable? Yes, the registration contract uses the UUPS (Universal Upgradeable Proxy Standard) pattern. Upgrades can only be initiated by the admin multisig. However, upgrades cannot: - Revoke existing registrations - Make registrations transferable - Add transfer functionality - Modify ownership records The upgrade mechanism exists only for bug fixes and new feature additions.
What happens if Chain Daddy shuts down? Your registration exists on-chain regardless of whether Chain Daddy is online. Even if the website goes offline: - Your on-chain credential remains in your wallet - The smart contract continues to function - Health score updates stop (no new expirations) - On-chain metadata is preserved Your registration is an on-chain credential that any operator or app can read and respect without going through us β€” Chain Daddy never really owns your data. The Token List standard endpoints can be run by anyone with the contract address.
Can I interact with the contract directly? Yes. The registration contract is verified on-chain. You can: - Call `release()` to retire your registration - Call `setManager()` to assign a manager - Read `heartbeatScore()` for current status - Use any block explorer or direct RPC calls See the [API Reference](/api-reference/authentication) for programmatic access, or the [CLI](/api-reference/cli) for command-line interaction.
--- # Claim an Existing Token URL: https://docs.chaindaddy.io/getting-started/claim-an-existing-token Category: getting-started # Claim an Existing Token If your token already exists on-chain, claim it to lock in your verified ownership and unlock your public token page. The fastest path: connect your wallet and Chain Daddy detects every token you can claim across all supported chains in one pass. ## Prerequisites - A crypto wallet (MetaMask, Phantom, or any compatible wallet) connected from the address that deployed your token, holds mint/update authority, or holds the majority of supply - Gas on the token's chain to pay for the claim transaction ::: tip OG Projects If your token was deployed 60+ days ago with a market cap β‰₯ $50,000 and liquidity β‰₯ $10,000, the platform fee is waived β€” you only pay gas. Look for the OG badge in search results. See [OG Free Registration](/pricing/registration#og-free-registration) for details. ::: ## Option 1: Auto-Detect (Recommended) Connect your wallet from anywhere on the site and Chain Daddy scans every supported chain in parallel for tokens you're eligible to claim. When it finds any, a **"You can register N tokens"** banner appears at the top of the page. 1. Connect your wallet. If you hold claimable tokens, the **"You can register N tokens"** banner appears automatically. 2. Open the banner to review your [detected tokens](https://chaindaddy.io/_claim), sorted by verification strength. Each shows the chain, the qualification method (see [verification methods](#verification-methods)), and the registration status. 3. Click a token to open its page. Chain Daddy checks your ownership automatically, then **Claim** switches networks if needed, prompts you to sign the ownership message, and submits the transaction. ![Detected claimable tokens across every supported chain](/screenshots/quickclaim-detected.png) ::: tip Solana Solana claims take two transactions β€” one to prove your qualification, one to file the registration. Both are guided with clear status indicators. ::: If your token isn't detected β€” usually because you're connecting from a wallet that doesn't qualify, or the token isn't indexed yet β€” use **Option 2** below. ## Option 2: Search or Add by Address Use this when the auto-detect banner doesn't surface your token. ### Your token is already indexed 1. Search by symbol or contract address (e.g., `DOGE`, `PEPE`). Confirm the status is **Unclaimed** β€” or check whether a prior registration has lapsed via the [heartbeat](/platform/heartbeat). ![Search results showing PEPE tokens across every supported chain](/screenshots/auto/search-results--desktop--light.png) 2. Connect the wallet that deployed your token, holds mint/update authority, or holds the majority of supply. 3. Click the result to open your token's page. Ownership is checked there automatically β€” there's no separate "verify" button β€” using the strongest available method. 4. Click **Claim** to file your on-chain registration. ### Your token isn't in search yet If your token doesn't show up in search, look it up by its **contract address**. When no result comes back, a **"Can't find a token? Listing is FREE"** card appears β€” or go straight to the [**Add a token**](https://chaindaddy.io/_submit) page. Paste the address, pick the chain(s), and add it: Chain Daddy indexes your token for free and takes you straight to [your claimable tokens](https://chaindaddy.io/_claim) to finish claiming it. ![Add a token by contract address β€” paste the address, pick the chains, and Chain Daddy indexes it for free, then routes you to claim it](/screenshots/auto/submit-token--desktop--light.png) | Status | Meaning | |--------|---------| | Available | No token exists on this chain | | Unclaimed | Token exists, no one has claimed it yet | | Claimed | Someone else is the verified owner | | Inactive | Registration exists but health score is low | ## Verification Methods The strongest available method is used automatically. **EVM** (strongest first): Owner (`owner()` returns your address) β†’ Deployer (matching contract deployer) β†’ Majority Holder (>50% of supply). **Solana** (strongest first): Mint Authority β†’ Update Authority β†’ Deployer β†’ Majority Holder (>50% of supply). ## Pricing Standard claims charge the platform fee plus gas; OG-eligible tokens skip the platform fee. See [Registration & Creation Pricing](/pricing/registration) for current rates and [OG Free Registration](/pricing/registration#og-free-registration) for qualification details. ::: info Your registration is permanently yours Claims are non-transferable and permanently bound to your wallet. No one β€” including Chain Daddy β€” can move or revoke them. Ownership changes go through an announced [deal](/creator-tools/deals). ::: ## After You Claim You're taken to your **[token manager](/token/token-management)**, where you can: - Edit metadata (name, description, logo, links) - Monitor your [health score](/platform/heartbeat) and stay active - Delegate page editing to another wallet - Export listing data for major platforms ::: tip Keep It Active Your registration stays yours as long as activity holds up. Health below 60% for 30 days marks the registration at-risk; see [Heartbeat & Activity](/platform/heartbeat) for the full rules. ::: ## Next Steps - [Token Management](/token/token-management) to customize your page - [Heartbeat & Activity](/platform/heartbeat) to keep your registration healthy - [Listing Export](/creator-tools/listing-export) to get listed on aggregator platforms --- # Create a Token URL: https://docs.chaindaddy.io/getting-started/create-a-token Category: getting-started # Create a Token Create a new token and register it in a single flow. Chain Daddy deploys a standard ERC-20 (or SPL on Solana) contract with the full supply sent directly to your wallet, then files your verified ownership on-chain automatically. *Getting started takes two quick steps: from the homepage, hit **Launch New Token**, **name** your ticker, **pick your chains**, and **Add to Cart**. You configure the token itself β€” supply, settings, liquidity β€” in the wizard after checkout.* **Step 1 β€” Name it.** Enter your ticker symbol (for example `CHAPY`). You'll set the longer display name, supply, and everything else after checkout. **Step 2 β€” Pick your chains.** Choose one or more chains. Multi-chain selections get an automatic bundle discount, shown live in the footer β€” then **Add to Cart** and check out. ::: tip Name already taken? We'll tell you. If a ticker is already in use, the chain picker shows how many tokens we found going by that name **on each chain** β€” so you can see at a glance where `$YOURS` is contested before you commit. (First-claim-wins is per symbol *and* chain, so a name taken on one chain may still be open on another.) ![The Launch dialog's chain step flags how many existing tokens already use this name on each chain](/screenshots/launch/name-taken.png) ::: ## Why Make a Token? A token turns your idea, community, or inside joke into something people can actually hold, trade, and rally around β€” and it's unmistakably *yours*. You claim the ticker, the full supply lands in your wallet, and your verified ownership is filed on-chain automatically, so when someone searches `$YOURS` they find the real one, not a copycat. No Solidity, no deploy scripts, no gatekeepers. It takes about two minutes and works on every major chain. ## What Gets Deployed Each token creation deploys: - **Standard ERC-20 contract** on your chosen chain(s) - **Full supply to your wallet**: you control 100% of tokens - **On-chain registration**: your verified ownership record is filed automatically; no separate step - **Cross-chain linking configured**: if deploying to multiple chains The deployed token is a standard, audited contract with no admin keys or special permissions beyond what you configure at creation time. ## Pricing Token creation combines a flat per-chain token-deployment fee with the standard registration fee. Ethereum costs more than other chains due to gas. Multi-chain bundles (Duo / Tri / Quad / All-Chain / All-Chain + ETH) bundle both into a single discounted price. ::: tip OG Discount [OG-eligible projects](/pricing/registration#og-free-registration) pay no platform fee for the registration portion. The token-deployment fee still applies. ::: For the current per-chain rates and bundle prices, see [Registration & Creation Pricing](/pricing/registration). ## What's Included Every token creation includes: - Token contract deployment on selected chain(s) - On-chain registration listed under your wallet as the verified owner - Cross-chain linking (multi-chain bundles) - Public token page with editable metadata - Listing export data for major platforms ## Which Chain Should I Choose? {#which-chain-should-i-choose} Each blockchain has different strengths. Here's a quick summary to help you pick, with links to learn more about each chain. ### Solana, Most Popular **Best for: High-speed trading and meme coins** Near-instant transactions with fees under a penny. Solana has the largest retail trader community and the most active on-chain trading volume. If your community is already on Solana or you want the fastest trading experience, start here. [Learn more about Solana](https://solana.com) ### Ethereum, Most Established **Best for: Maximum credibility and institutional presence** The original smart contract platform. Ethereum mainnet carries the most prestige but has significantly higher gas costs (the Ethereum token-creation fee reflects this β€” [see pricing](/pricing/registration)). Best for established projects that want the strongest on-chain credibility. [Learn more about Ethereum](https://ethereum.org) ### Arbitrum, Low Cost, Big Ecosystem **Best for: Most projects getting started** Low fees (usually under $0.10 per transaction), fast confirmations, and the strongest on-chain finance ecosystem of any Layer 2. Arbitrum inherits Ethereum's security while keeping costs low. A great default for new projects. [Learn more about Arbitrum](https://arbitrum.io) ### Base, Built by Coinbase **Best for: Consumer apps and social tokens** Built by the team at Coinbase, Base has low fees and a growing user base focused on consumer-friendly apps. Great choice if your audience is newer to crypto or already uses Coinbase. [Learn more about Base](https://base.org) ### Polygon, Widely Supported **Best for: High-volume and gaming projects** Very low fees and supported by virtually every wallet and platform. Polygon has strong adoption in gaming and NFT communities. Good choice if you expect high transaction volume. [Learn more about Polygon](https://polygon.technology) ### BNB Chain, Powered by Binance **Best for: Global reach and exchange-backed ecosystem** One of the largest blockchain ecosystems by user count, especially popular in Asia. Low fees and broad exchange support. Choose BNB Chain if your community is already active there. [Learn more about BNB Chain](https://www.bnbchain.org) ### Avalanche, Fast & Scalable **Best for: High-throughput and subnet-ready projects** Sub-second finality and a scalable subnet architecture. Avalanche offers fast transaction speeds with low costs and a growing ecosystem of trading and gaming projects. [Learn more about Avalanche](https://www.avax.network) ### Gnosis, Community Powered **Best for: DAO-focused and community-governed projects** Home of Safe (formerly Gnosis Safe), the most popular multi-sig wallet. Gnosis Chain is community-governed with ultra-low fees paid in xDAI. A natural fit for DAO-native projects and community-first tokens. [Learn more about Gnosis Chain](https://www.gnosis.io) ### Go Multi-Chain ::: tip Launch on Multiple Chains You don't have to pick just one. Multi-chain tokens reach more traders, more exchanges, and more communities. Chain Daddy handles the cross-chain linking automatically, so your token page shows a unified view across all your deployments. Multi-chain bundles are discounted compared to deploying chains individually. See [Registration & Creation Pricing](/pricing/registration) for current rates. ::: ## Creation Wizard After checkout, a guided wizard walks you through configuring your token before it mints β€” identity, supply, token settings, trust features, liquidity, and a final review β€” with your progress saved at every step. Reasonable defaults are pre-filled, so you can accept them and mint immediately, or fine-tune any step. *Configuring a token across the wizard's steps β€” the symbol is locked to your paid order, and everything else has a sensible default you can change.* ### Step 1: Identity Name your token and give it a one-line description. The **symbol is locked** to your paid order; the **name** defaults to the symbol β€” change it if your token's display name differs (e.g. "Dogecoin" for DOGE). The **description** is optional: a one-liner marketplaces and search can show next to your token. ![Wizard step 1 β€” Identity: token name and description; the symbol is locked to your paid order](/screenshots/auto/wizard-identity--desktop--light.png) ### Step 2: Supply & Precision Set how many tokens mint at launch and how finely they divide. **Both are permanent** β€” they can't change once the token deploys. - **Total supply**: total tokens minted to your wallet at launch. Quick presets: 1M / 100M / 1B / 10B. - **Decimals**: how divisible each token is. The convention is **18 on EVM** and **9 on Solana** β€” pick what holders expect. On a multi-chain order, an **Apply to all** toggle mints the same supply and decimals on every chain; uncheck it to set per-chain values. ![Wizard step 2 β€” Supply & precision: total supply and decimals, both permanent once minted](/screenshots/auto/wizard-supply--desktop--light.png) ### Step 3: Token Settings Choose your token's capabilities. These are **one-way doors at launch** β€” you can disable them later, but never turn them back on. The defaults match a safe-meme template: not mintable, holders can burn, owner retained. - **Mintable**: lets the owner mint more after launch (until you burn the mint authority). Off by default for a fixed supply. - **Burnable**: lets holders burn their own tokens. Doesn't touch the supply already in your wallet. - **Cap supply** (only when mintable): caps how much can ever be minted β€” set a **Max supply**. Without a cap, "mintable" means uncapped. - **Renounce ownership at launch**: permanently gives up all owner-only controls (future mint and trust changes). Irreversible. ![Wizard step 3 β€” Token settings: mintable, burnable, supply cap, renounce ownership](/screenshots/auto/wizard-settings--desktop--light.png) ### Step 4: Trust Features Anti-bot protections for the first trades. Unlike the token settings above, these **aren't one-way** β€” you can loosen them later from your token manager. Pick a preset β€” **None**, **Light**, **Recommended**, or **Strict** β€” or open **Customize**: - **Deadblocks (0–10)**: blocks after launch before trading opens, to shake off first-block snipers. - **Max wallet**: the largest balance any one wallet may hold, in basis points (100 = 1%). `0` disables it. - **Max tx**: the largest single trade, in basis points. `0` disables it. ![Wizard step 4 β€” Trust features: anti-bot presets plus per-parameter customization](/screenshots/auto/wizard-trust--desktop--light.png) ### Step 5: Liquidity & Trading Pair Optionally seed a DEX pool from your own wallet at mint time, so your token is tradable the moment it launches. **Skip it** to launch as a non-tradable token β€” you can [add liquidity later](/token/liquidity) from your token manager. - **Supply % paired**: the portion of your total supply paired into the pool (the rest stays in your wallet). 50% is a common starting point β€” higher means deeper liquidity, lower keeps more tokens for you. - **Native amount to fund**: how much of the chain's native token (ETH, SOL, …) you'll add at mint to pair with your tokens. This sets the **opening price** and is charged **on top of gas**. On a multi-chain order, **Apply to all** uses the same split on every chain, or configure each chain individually. ![Wizard step 5 β€” Liquidity & trading pair: seed a DEX pool at mint, or skip and add liquidity later](/screenshots/auto/wizard-liquidity--desktop--light.png) ::: tip Expanding a token you already own? If you're launching a symbol you already hold on other chains, an extra **Import** step appears just before the summary β€” copy the branding and settings from a chain you've already configured so your new deployment matches. ::: ### Step 6: Review & Mint A final summary of everything β€” symbol, name, supply, capabilities, trust, and liquidity β€” with a clear note of what's **permanent** (symbol, total supply, decimals, and any "renounce ownership" choice) versus adjustable later from your token manager. Your order is already paid; from here you sign **one transaction per chain** and pay gas (plus any liquidity you chose to seed) from your connected wallet. ![Wizard final step β€” Review & mint: confirm every setting, then sign one transaction per chain](/screenshots/auto/wizard-summary--desktop--light.png) ## Notes ::: tip What can it do? Once your token is live, it's yours to build on. Reward your community with [token-gated perks and links](/creator-tools/token-gated-links), [keep holders in the loop](/creator-tools/holder-notifications) when you ship or drop, [export your holder list](/creator-tools/holder-export) for airdrops, and [get it listed](/creator-tools/listing-export) on the major platforms β€” whether it's a memecoin, a creator coin, or a community token. ::: ::: tip Already Have a Token? If your token already exists on-chain, [claim it](/getting-started/claim-an-existing-token) instead. ::: ::: warning Supply Ownership The full token supply is sent to the wallet that initiates creation. Distribute tokens as you see fit after deployment. ::: ::: info Under the hood Each registration is a soulbound on-chain credential, internally called a "crown", that proves your ownership and can never be transferred without an announced deal. Most users never need to think about it; it just makes your token page yours. ::: --- # Getting Started URL: https://docs.chaindaddy.io/getting-started/ Category: getting-started # Getting Started Welcome to Chain Daddy. Create a new token or register an existing one to lock in verified ownership, get a public token page, send notifications, and gate content for your holders. *Search your symbol, scan every chain at once, and land on the token page β€” the whole flow takes seconds.* ## Choose Your Path ### Creating a New Token? Most users want to launch a new token. Chain Daddy deploys your token and registers it in one transaction. **[Create a Token β†’](/getting-started/create-a-token)** - Deploy a standard ERC-20 or SPL token - Full supply sent directly to your wallet - On-chain registration filed automatically, no separate step - Multi-chain bundles available ([see pricing](/pricing/registration)) ### Already Have a Token? If your token already exists on-chain, claim it to prove you're the verified owner. **[Claim an Existing Token β†’](/getting-started/claim-an-existing-token)** - Auto-detect with QuickClaim, or search and verify manually - Verify via deployer, mint/update authority, or majority holdings - Flat [registration fee](/pricing/registration), waived for [OG projects](/pricing/registration#og-free-registration) - Works with any ERC-20 or SPL token on supported chains ## Get Started With Your AI Assistant Want to launch and manage your token through an AI agent? Copy the prompt below into ChatGPT, Claude, Cursor, or any other LLM that supports web fetch: ```text I want to launch (or register an existing) token on Chain Daddy and run it from there: verified registration, a public token page, push notifications to my holders, and token-gated content across web, Discord, and Telegram. Pull the current docs from https://docs.chaindaddy.io/llms-full.txt and walk me through: 1. Which chain is best for my project, and whether to create a new token or register an existing one. 2. The exact registration flow (which verification method to use, what I'll be signing, what the fee covers). 3. How the health score works and what I need to do to keep my registration healthy long-term. 4. How to plug in apps (notifications, polls, token-gated content, buy button, tip jar) once I'm registered. Ask me questions one at a time. Don't make assumptions about my project. ``` ::: tip Prefer a real CLI for agentic workflows? Install the Chain Daddy CLI to mint, register, and manage tokens directly from your terminal or from any tool that can shell out: ```bash npm install -g @chaindaddy/cli chaindaddy --help ``` The CLI exposes the full registration, listing-export, and Crown App submission surface, so coding agents (Claude Code, Cursor, Aider, etc.) can drive Chain Daddy end-to-end. See the [CLI reference](/api-reference/cli). ::: ## Quick Links - [What is Chain Daddy?](./what-is-chain-daddy): Platform overview, supported chains, and how it works - [Create a Token](./create-a-token): Deploy a new token and register it - [Claim an Existing Token](./claim-an-existing-token): Verify ownership of a token you already deployed ## Documentation for AI Agents {#llm-access} Every page has a **Copy for LLM** button (top-right) that copies the raw markdown for pasting into any AI assistant. ::: details For developers: machine-readable doc endpoints Multiple discovery endpoints help agents find content without HTML parsing: | Endpoint | Description | |----------|-------------| | [`/llms.txt`](https://docs.chaindaddy.io/llms.txt) | Structured index of all pages with descriptions (follows [llmstxt.org](https://llmstxt.org) spec) | | [`/llms-full.txt`](https://docs.chaindaddy.io/llms-full.txt) | Complete documentation concatenated into a single file for large-context agents | | [`/docs-index.json`](https://docs.chaindaddy.io/docs-index.json) | Machine-readable JSON catalog with titles, descriptions, categories, and markdown URLs | | `/md/{path}.md` | Raw markdown for any page (e.g., [`/md/getting-started/index.md`](https://docs.chaindaddy.io/md/getting-started/index.md)) | | [`/openapi.yaml`](https://docs.chaindaddy.io/openapi.yaml) | OpenAPI 3.0 spec for the Chain Daddy API | Point your agent at `/llms-full.txt` for complete context in one request, or use `/docs-index.json` to selectively fetch pages by category. More in the [developer docs](/developer/). ::: --- # What is Chain Daddy? URL: https://docs.chaindaddy.io/getting-started/what-is-chain-daddy Category: getting-started # What is Chain Daddy? You launched a token. Now what? Claim a public token page and customize it with your own branded themes, media, and widgets. Run polls, share announcements, and create exclusive content for your holders β€” all from one place. ## What You Get ### Token Page - Customizable public page for your project (chaindaddy.io/TICKER) - Custom banner, logo, colors, themes, playable media - Verified social links (Twitter, Discord, Telegram, etc.) - SEO-optimized and shareable β€” the page exchange-listing services should have given you - Vanity domain unique to your token (`TICKER.crown.info`) ![A public token page β€” branding, verified links, live market stats, a live price chart, and the claim prompt for unregistered tokens](/screenshots/auto/token-page--desktop--light.png) ::: info How vanity domains work Every token gets a short, memorable link at `TICKER.crown.info`. When several tokens share a ticker, the most active one (highest health score) automatically holds the domain β€” so it always points to the liveliest project. Need a specific chain? Chain-scoped links like `TICKER.CHAIN.crown.info` or `TICKER.crown.info/chain` (e.g. `DOGE.solana.crown.info`) always resolve to the most active token for that ticker on that chain. ::: ### Listing Exports - One-click export for major listing platforms - Token List standard so wallets and exchanges can auto-import your token ### Apps & Extensibility - Extend your token page with apps β€” headless services or visual widgets - Embeddable tip widget β€” accept donations anywhere - Embeddable buy button β€” direct token purchases - Send notification announcements to your community - Run polls for your holders, weighted by holdings - Token-gate exclusive content across web, Discord, and Telegram - Holder snapshots for airdrops (Pro subscription) ### Cross-Chain - One unified token page across Ethereum, Arbitrum, Base, Polygon, BNB Chain, Avalanche, Gnosis, and Solana - Shared metadata β€” update once, verified everywhere - Multi-chain bundles available ## Quick Start ``` Search Ticker β†’ Create or Verify β†’ Register β†’ Build Your Page ``` ![The Chain Daddy homepage β€” search your ticker to get started](/screenshots/auto/homepage--desktop--light.png) 1. **Search**: Look up your ticker to see availability across all chains 2. **Create or Verify**: Deploy a new token or prove ownership of an existing one 3. **Register**: File your verified ownership on-chain ([flat registration fee](/pricing/registration), waived for [OG projects](/pricing/registration#og-free-registration)) 4. **Build**: Customize your token page, add socials, export to listings ## For Developers For technical details on verification methods, heartbeat scoring, and API integration, see the [API Reference](/api-reference/authentication). ## How Verification Works Each registration links a ticker to a specific token contract on a specific chain. Think of it like a domain name for your token β€” your registration is the verified record that you own your project's ticker. You verify ownership via: - **Deployer address**: You deployed the contract - **Mint authority**: You control minting (Solana) - **Majority holder**: You hold >50% of supply Once verified, your registration is yours β€” permanently bound to your wallet and non-transferable except through an announced ownership deal. (e.g. soulbound NFT) No admin can revoke it, and squatters can't flip it on secondary markets. Ownership changes require 30-day notice to protect holders. ## Active Management Activity-based scoring surfaces who's actively maintaining their token: - Active projects keep their registration automatically - Inactive projects (low volume, no updates) become "at-risk" - If a registration expires from inactivity, the ticker becomes **eligible for re-registration** again β€” the original owner can simply re-register it, and so can anyone else who passes [verification](/token/verification-methods) (first-claim-wins) Expiry isn't a loss β€” it just reopens the slot. So the registry always reflects who's actively managing a ticker rather than who registered it once and walked away, and squatters can't sit on a ticker without genuine on-chain activity. ## Supported Chains | Chain | Type | Tier | |-------|------|------| | Ethereum | EVM | Live | | Arbitrum | EVM | Live | | Base | EVM | Live | | Polygon | EVM | Live | | BNB Chain | EVM | Live | | Avalanche | EVM | Live | | Gnosis | EVM | Live | | Solana | SPL | Live | | Optimism | EVM | Next | | Fantom | EVM | Next | | zkSync Era | EVM | Next | | Linea | EVM | Next | | Blast | EVM | Next | | Scroll | EVM | Next | | Mantle | EVM | Planned | | Mode | EVM | Planned | | Cronos | EVM | Planned | | Celo | EVM | Planned | | Moonbeam | EVM | Planned | | Sonic | EVM | Planned | | Sui | Move | Planned | All Live chains are equal peers. Tokens can be registered on any of them. Next and Planned chains have token data indexed already and will support registration as they go live. ## Next Steps Ready to get started? [Create a Token](/getting-started/create-a-token) or [Claim an Existing Token](/getting-started/claim-an-existing-token). --- # Chain Daddy Docs URL: https://docs.chaindaddy.io/ Category: general --- # Fund Verification: Service Terms URL: https://docs.chaindaddy.io/platform/fund-verification-terms Category: platform # Fund Verification: Service Terms *Effective date: 2026-03-23 Β· Last updated: 2026-07-02* ## 1. Service description Chain Daddy provides an optional fund verification service ("Fund Verification") for deal offers. Fund Verification checks the on-chain balance of a buyer's wallet at a specific block and creates a signed attestation of the result. ## 2. Nature of verification 2.1. Fund Verification is a **point-in-time balance check**, not a guarantee, escrow, or hold on funds. 2.2. A passing verification confirms that, at a specific block number, the wallet held a balance meeting or exceeding the required threshold. It does not guarantee that funds will remain available at deal completion. 2.3. Verification results are **informational**. They do not constitute financial advice, credit checks, or underwriting. ## 3. Attestation 3.1. When verification passes, Chain Daddy signs a cryptographic attestation containing the verification details. This attestation is: - Stored off-chain in Chain Daddy's database - Referenced on-chain via a hash in the deal contract - Independently verifiable by calling `verifyFundAttestation()` on the smart contract 3.2. The attestation signer key is dedicated to fund verification and is separate from Chain Daddy's administrative keys. ## 4. Limitations 4.1. **Not an escrow or guarantee.** Fund Verification does not lock, reserve, or custody any funds. The buyer retains full control of their wallet at all times. 4.2. **Point-in-time only.** Balances can change between verification and deal completion. Re-verification at claim time provides updated information but is also point-in-time. 4.3. **RPC dependency.** Verification relies on third-party blockchain RPC providers. Temporary RPC outages may prevent verification. This is not a service failure. 4.4. **Soft enforcement.** Fund verification is a soft check. It does not block deal progression at the smart contract level. The smart contract remains the authority on deal execution. 4.5. **Currency volatility.** The required verification percentage adjusts based on 60-day currency volatility. This is a risk-adjusted threshold, not a guarantee against price movements. ## 5. Liability 5.1. Chain Daddy is not liable for deals where a verified buyer subsequently lacks sufficient funds. Fund Verification is a tool for informed decision-making, not a financial guarantee. 5.2. Chain Daddy is not liable for temporary unavailability of Fund Verification due to RPC provider outages, price API outages, or infrastructure maintenance. 5.3. The maximum liability for Fund Verification service errors shall not exceed the facilitation fees paid for the relevant deal. ## 6. Data handling 6.1. Verification records (wallet address, balance, attestation hash) are stored in Chain Daddy's database and retained for the lifetime of the associated deal. 6.2. Wallet addresses are masked in system logs (first 6 + last 4 characters visible). 6.3. On-chain attestation hashes are publicly visible on the blockchain. ## 7. Availability 7.1. Fund Verification targets 99.5% availability as measured over rolling 30-day windows. 7.2. Scheduled maintenance windows will be communicated via the platform status page. 7.3. Deal offers can be submitted without fund verification. Unverified offers are clearly marked in the deal management interface. --- # Token Health & Activity URL: https://docs.chaindaddy.io/platform/heartbeat Category: platform # Token Health & Activity Your token's health score measures how active your token is on-chain. It determines whether your registration stays in good standing or expires and becomes available for someone else to register. ## How the Score Works Your health score is a single number from 0-100, computed daily from three on-chain signals: | Signal | Weight | What It Measures | |--------|--------|-----------------| | Activity timestamp | 50% | How long since the listing was registered (a stepped decay) | | Trading volume | 30% | DEX volume, smoothed across 24h + 7d, capped against pool liquidity, then log-scaled (see below) | | Holder Health Score | 20% | Holder distribution shape β€” concentration, suspicious wallets, distribution breadth, scale (see below) | Verified social channels appear as a badge on your token page but **do not affect the score**. The score is a token-health signal; social verification is a separate identity signal. Each daily commit is also annotated with a 0-100 **confidence** value derived from how recent the underlying market data was when the score was computed. Confidence is shown alongside the score in the API response so you can see at a glance how fresh the inputs were. The operator's indexer recomputes scores once per day and publishes them as a single Merkle root commitment on-chain. Anyone can verify the score for any listing against that root β€” see [the heartbeat oracle reference](/api-reference/explorer) for the public RPC endpoints. ## How the Volume Signal Works Raw 24-hour volume is easy to inflate with wash trading. Two filters run before the score is computed: - **Smoothing**: your effective volume is a blend of the last 24 hours and a trailing 7-day daily average (default 70/30). A single-day burst contributes only 70% of its value; the rest is anchored to the week. This damps wash-trading spikes without erasing real recent activity. - **Liquidity-anchored cap**: your effective volume is capped at 100Γ— the token's DEX pool liquidity. A token reporting $1M volume on $50 of pool liquidity is wash-trading by definition; the cap clamps that down without affecting honest tokens (real volume rarely exceeds 10-20Γ— daily turnover). Newly-listed tokens with no pool data yet skip the cap entirely so they're not zeroed out before they have a market. Both filters run on data from the same provider call as the holder distribution β€” no additional cost. ## How the Holder Health Score Works Raw holder counts are easy to game by splitting tokens across many wallets. The Holder Health Score evaluates the **shape** of token ownership instead, with four sub-components: | Sub-component | Share | What it captures | |---------------|-------|-----------------| | Concentration | 40 of 100 | How much of supply the top 10 / top 50 wallets control | | Suspicious wallets | 33 of 100 | Snipers, bundlers, insiders, and sandwich attackers (labeled by the data provider) | | Distribution | 17 of 100 | How many wallets together hold 50% of supply | | Holder scale | 10 of 100 | Raw holder count, capped at 5,000 (EVM) or 50,000 (Solana) | Splitting balance across new wallets *worsens* concentration and distribution scores even as it inflates the raw count, so wallet-splitting attacks lower your score instead of raising it. ## Status Thresholds | Score Range | Status | What It Means | |-------------|--------|---------------| | 60-100 | Healthy | Registration in good standing | | Below 60 | At-Risk | The 30-day expiration countdown is running; alerts fire | | Below 60 for 30 consecutive days | Expired | Ticker available for re-registration | ## Grace Period for New Registrations Newly registered tokens receive a **30-day grace period** during which the listing cannot be reclaimed regardless of score. This gives new tokens time to build organic activity. During grace period: - Your health score is tracked but does not trigger at-risk status - The slot cannot be reclaimed, regardless of score - Token page displays a "New" badge The grace period is measured from the original first claim of the (symbol, chain, token contract) triple β€” releasing and re-registering does not reset it. ## Reclaiming an Expired Slot When a listing's score has been below 60 for 30 consecutive days and it is past its grace period, the registration expires and the slot becomes reclaimable. Expiry is enforced on-chain: **anyone** can submit a Merkle proof of the failing score to mark the listing inactive β€” no admin involvement. Re-registering an expired ticker goes through the standard [registration flow](/getting-started/claim-an-existing-token) ([see pricing](/pricing/registration)), plus gas. There are no penalty fees and no per-wallet limits β€” activity decay plus first-claim-wins is the entire anti-squatting mechanism. ## What Happens When a Registration Expires Once a registration expires: 1. Status changes to "Expired" in search results 2. The slot reopens for re-registration β€” the original owner or anyone else who passes [verification](/token/verification-methods) can register it through the standard flow, first-claim-wins 3. The original owner keeps no special claim on the slot; to get the ticker back they simply re-register (before someone else does) 4. Metadata and manager assignments are cleared when a new owner registers ::: warning Re-registration is first-come β€” no admin recovery Expiry doesn't erase your ability to come back: until someone re-registers the open slot, you can re-register it yourself. But there are no admin functions to restore a registration β€” once another wallet re-registers an expired ticker, first-claim-wins makes it theirs, and support can't reverse it. ::: ## Tips for Maintaining a Healthy Score - **Keep trading active**: Even small volume counts toward the 30% volume signal - **Grow your holder base genuinely**: Concentration is the biggest piece of the holder health score; spreading supply across real wallets matters more than raw count - **Verify your socials**: Verified social channels appear as a trust badge on your token page (they don't affect the health score, but they help users distinguish legitimate projects) - **Monitor your score**: Watch your health score as a live metric in your token manager's [Analytics](/analytics/#health-score) tab - **Set up alerts**: PRO subscribers receive health warning notifications before at-risk status triggers - **Use a multisig**: Register from a Safe multisig wallet so team members can maintain activity even if one person is unavailable --- # Token Plans URL: https://docs.chaindaddy.io/pricing/plans Category: pricing # Token Plans Five plan tiers are available, from free access for verified token owners to partner-grade API integration β€” plus a custom Enterprise tier for teams that need more. ## Plan Comparison | | Free | PRO | PRO+ | Developer | Partner | |---|---|---|---|---|---| | **Price** | $0 | ${{price.subscriptionTiers.pro.monthly}}/mo | ${{price.subscriptionTiers.pro_plus.monthly}}/mo | ${{price.subscriptionTiers.developer.monthly}}/mo | ${{price.subscriptionTiers.business.monthly}}/mo | | **Annual** | β€” | ${{price.subscriptionTiers.pro.yearly}}/yr | ${{price.subscriptionTiers.pro_plus.yearly}}/yr | ${{price.subscriptionTiers.developer.yearly}}/yr | ${{price.subscriptionTiers.business.yearly}}/yr | | **API Calls/Day** | 100 | 5,000 | 15,000 | 50,000 | 250,000 | | **Rate Limit** | 1 req/s | 5 req/s | 10 req/s | 15 req/s | 50 req/s | | **Notifications/Week** | 1 | Unlimited | Unlimited | Unlimited | Unlimited | | **Member Cap** | 10,000 | 50,000 | 50,000 | Unlimited | Unlimited | | Search & token lookup | Yes | Yes | Yes | Yes | Yes | | Token management | Yes | Yes | Yes | Yes | Yes | | Apps (market data) | Yes | Yes | Yes | Yes | Yes | | Embeddable widgets (buy, tip) *(coming soon)* | β€” | β€” | β€” | β€” | β€” | | Token page color presets | Yes | Yes | Yes | Yes | Yes | | Background patterns | Yes | Yes | Yes | Yes | Yes | | Social verification (X, website) | Yes | Yes | Yes | Yes | Yes | | Social links | Yes | Yes | Yes | Yes | Yes | | Featured links | Yes | Yes | Yes | Yes | Yes | | Custom hex colors | β€” | Yes | Yes | Yes | Yes | | Animated backgrounds | β€” | Yes | Yes | Yes | Yes | | Video backgrounds | β€” | Yes | Yes | Yes | Yes | | Custom CSS | β€” | Yes | Yes | Yes | Yes | | Layout & template picker | β€” | Yes | Yes | Yes | Yes | | Export (CSV/JSON) | β€” | Yes | Yes | Yes | Yes | | Custom widget branding *(coming soon)* | β€” | β€” | β€” | Yes | Yes | | Tip alert overlays (OBS) *(coming soon)* | β€” | Yes | Yes | Yes | Yes | | Discord tip alerts *(coming soon)* | β€” | Yes | Yes | Yes | Yes | | Verified badge | β€” | Yes | Yes | Yes | Yes | | Analytics dashboard | β€” | Yes | Yes | Yes | Yes | | Health score alerts | β€” | Yes | Yes | Yes | Yes | | Squatter shield | β€” | Yes | Yes | Yes | Yes | | Holder snapshot export | β€” | Yes | Yes | Yes | Yes | | Airdrops (non-custodial) | β€” | β€” | Yes | Yes | Yes | | Copycat detection | β€” | β€” | Yes | Yes | Yes | | No watermark | β€” | β€” | Yes | Yes | Yes | | 3rd party apps | β€” | β€” | Yes | Yes | Yes | | Scheduled holder notifications | β€” | β€” | Yes | Yes | Yes | | Access tiers | β€” | 5 | 10 | 20 | 40 | | Token-gated links | β€” | 5/token | 10/token | 20/token | 40/token | | Holder exports/day | β€” | 50 | 200 | 500 | 1,000 | | App publishing | β€” | β€” | Yes | Yes | Yes | | Paid apps (rev share) *(coming soon)* | β€” | β€” | β€” | Yes | Yes | | Custom domain mapping *(coming soon)* | β€” | β€” | Yes | Yes | Yes | | App marketplace *(coming soon)* | Yes | Yes | Yes | Yes | Yes | | Zapier integration *(coming soon)* | β€” | β€” | Yes | Yes | Yes | | Webhook notifications | β€” | β€” | β€” | Yes | Yes | | Bulk API endpoints | β€” | β€” | β€” | Yes | Yes | | Embed usage analytics *(coming soon)* | β€” | β€” | β€” | Yes | Yes | | White-label (no branding) | β€” | β€” | β€” | β€” | Yes | | Content subscriptions *(coming soon)* | β€” | β€” | β€” | β€” | Yes | | 99.9% SLA guarantee | β€” | β€” | β€” | β€” | Yes | Need more than Partner? An **Enterprise** tier with custom limits is available β€” see [Enterprise](#enterprise) below. ## Free Every verified token owner and community member gets access at no cost: - **Search & token lookup**: Query tickers and retrieve token data across all chains - **Token management**: Register, update metadata, and manage your tokens - **Token page color presets**: 16 background and 16 accent color options - **Background patterns**: Subtle pattern overlays for your token page - **Social verification**: Verify X (Twitter) via OAuth and website via DNS/meta tag - **Social & featured links**: Add X, Discord, Telegram, GitHub, and custom links to your token page - **Apps**: Market Data app on your token page (browse the App Directory from your token page's Apps tab). Embeddable buy and tip widgets coming soon. - **Holder notifications**: 1 notification/week to up to 10,000 verified holders - **API access**: 100 calls/day at 1 request/second **Eligibility:** Verified token owners and community members ($100+ token holdings) qualify automatically. ## PRO Full suite of tools for verified token owners. **${{price.subscriptionTiers.pro.monthly}}/month** or **${{price.subscriptionTiers.pro.yearly}}/year** (save 2 months with annual billing). Everything in Free, plus: - **Custom hex colors**: Any color value for background and accent (beyond presets) - **Animated backgrounds**: Particles, gradient, sparkle, rain, snow, bubbles, confetti, wave, aurora, stars - **Video backgrounds**: Looping video with poster image support - **Custom CSS**: Full CSS control over your public token page styling - **Layout & template picker**: Choose from multiple layouts and pre-configured theme templates - **Export to CSV/JSON**: Download holder lists, transaction data, and analytics - **Tip alert overlays** *(coming soon)* β€” OBS-compatible alerts for live streaming - **Discord tip alerts** *(coming soon)* β€” Notifications in your server when tips are received - **Verified badge**: Displayed on your token page and in search results - **Analytics dashboard**: Holder growth, volume trends, and token page views - **Health score alerts**: Notifications when your score drops near the at-risk threshold - **Squatter shield**: Priority dispute resolution and enhanced monitoring - **Holder snapshot export**: Download wallet addresses and balances (50 exports/day) - **Access tiers**: Up to 5 hold-to-access tiers - **Token-gated links**: Up to 5 links accessible only to verified holders - **Holder notifications**: Unlimited notifications/week, doubled type limits (4 announcements, 8 updates), up to 50,000 members - **API access**: 5,000 calls/day at 5 requests/second ## PRO+ The founding member tier for token founders. **${{price.subscriptionTiers.pro_plus.monthly}}/month** or **${{price.subscriptionTiers.pro_plus.yearly}}/year**. Everything in PRO, plus: - **Copycat detection**: Alerts when tokens with similar names or tickers appear on other chains - **No watermark**: Remove the Chain Daddy watermark from your token page and embeds - **3rd party apps**: Install community-built apps on your token page - **Scheduled holder notifications**: Queue holder notifications for future delivery at a specific date and time - **App publishing**: Submit widgets and runners to the App Directory - **Custom domain mapping** *(coming soon)* β€” Map your own domain to your token page - **Zapier integration** *(coming soon)* β€” Connect on-chain registration events to 5,000+ apps via Zapier - **Animated/video backgrounds**: Full access to animated and video background options - **Custom CSS**: Full CSS control over your public token page styling - **Access tiers**: Up to 10 hold-to-access tiers - **Token-gated links**: Up to 10 links accessible only to verified holders - **Holder snapshot export**: 200 exports/day - **[Airdrops](/creator-tools/airdrops)**: Distribute your token to an allowlist or an open claim link β€” non-custodially, straight from your own wallet - **API access**: 15,000 calls/day at 10 requests/second ## Developer For builders shipping apps on Chain Daddy and integrating registration data into their own products. **${{price.subscriptionTiers.developer.monthly}}/month** or **${{price.subscriptionTiers.developer.yearly}}/year**. Everything in PRO+, plus: - **Widget branding** *(coming soon)* β€” Ship widgets with your own colors, logo, and CTA - **Paid apps** *(coming soon)* β€” Sell paid app subscriptions to verified token owners with revenue share. See [paid apps](/developer/paid-apps) for current rates. - **Webhook notifications**: Real-time events for registrations, transfers, and health score changes - **Bulk API endpoints**: Batch queries for multiple tickers, registrations, or holders in a single request - **Embed usage analytics** *(coming soon)* β€” Track impressions, clicks, and conversions on your widgets - **Access tiers**: Up to 20 hold-to-access tiers - **Token-gated links**: Up to 20 links accessible only to verified holders - **Holder notifications**: Unlimited notifications, types, and members - **API access**: 50,000 calls/day at 15 requests/second > **Coming Soon.** Developer is in closed beta while we finalize the monetization rails. Beta participants get founding-developer pricing when the plan opens. [Apply for the beta](https://chaindaddy.io/_developer) or read the [Developer Beta Program overview](/developer/getting-started). ## Partner For developers scaling a portfolio of published apps and monetizing on the platform. **${{price.subscriptionTiers.business.monthly}}/month** or **${{price.subscriptionTiers.business.yearly}}/year**. Everything in Developer, plus: - **Premium app revenue share**: Higher split on paid apps than Developer tier - **Content subscriptions** *(coming soon)* β€” Charge holders a recurring fee for premium content on your token page, billed through Chain Daddy - **Access tiers**: Up to 40 hold-to-access tiers - **Token-gated links**: Up to 40 links accessible only to verified holders - **99.9% SLA guarantee**: Uptime commitment with credits for any violations - **White-label embeds**: Remove all platform branding from widgets and overlays - **API access**: 250,000 calls/day at 50 requests/second > **Coming Soon.** Partner is part of the Developer Beta Program and opens to approved developers in rolling waves. [Apply for the beta](https://chaindaddy.io/_developer) or see [App Development](/developer/getting-started) for the full program details. ## Enterprise For organizations that outgrow Partner β€” exchanges, wallets, data platforms, and large token portfolios. Enterprise is a custom agreement: unlimited API calls, custom rate limits and webhook allocations, no caps on gated links, access tiers, exports, or widgets, and every platform feature included. **Pricing is custom β€” [contact us](mailto:sales@chaindaddy.io) to discuss your needs.** ## Widgets {#widget-space} Your token page is a grid. The **Token Header** widget anchors the top; the remaining area is the space you fill with apps, Market Data, Activity Feed, HTML blocks, Polls, Highlights, TradingView charts, 3D viewers, and anything else from the App Directory (browse it from your token page's Apps tab). Higher tiers give you more widget space, so more widgets fit on the page. Roughly: | Tier | Widgets that fit | Example layouts | |------|--------:|-----------------| | **Free** | 2-3 | Token header + Market Data + Activity Feed (optionally a Swap) | | **PRO** | 5+ | + Poll, Highlights, TradingView, an HTML block | | **PRO+** | 10+ | + Token-gated video widget, 3D viewer, extra charts, multi-chain market tiles | | **Developer** | 20+ | Full dashboard: custom analytics panels, community apps, embedded runners | | **Partner** | 30+ | Multi-section storefront: paid subscription widgets, commerce blocks, gated drops | ### How the math works Each widget declares a `defaultSize` in its manifest that maps to a grid footprint: | Size | Cols Γ— Rows | Roughly… | |------|:-----------:|----------| | `small` (1Γ—1) | 6 Γ— 2 | a compact stat tile or buy button | | `wide` (2Γ—1) | 12 Γ— 2 | market data strip | | `tall` (1Γ—2) | 6 Γ— 4 | a list (activity, holders) | | `large` (2Γ—2) | 12 Γ— 4 | chart, media player, 3D viewer | Rule of thumb: most widgets eat 2-4 rows. `rich`/`heavy` tier widgets (3D viewers, embedded TradingView) fill 6-8 rows each, a Token Header plus a 3D viewer comfortably uses a Free token's entire budget. ### What hits the ceiling first Three limits apply together: 1. **Widget space**: the grid area from the table above β€” each widget's footprint consumes rows until the space is full. 2. **Widget count**: the Apps tab enforces a hard per-tier cap on how many apps can be active at once (Free: 3, Pro: 6, Pro+: 12, Developer: 24, Partner: 40). 3. **Page performance budget**: a 500 KB gzipped cap on the total bundle size of enabled widgets, so the page stays fast on mobile. Hit any of them and the Apps tab shows a clear indicator; disable less-critical widgets to make room. ## Holder Notifications Holder notifications are included with every tier, send verified messages directly to your token holders: | Tier | Notifications/Week | Announcements | Updates | Alerts | Member Cap | |------|----------------|---------------|---------|--------|------------| | **Free** | 1 | 2/week | 4/week | Unlimited | 10,000 | | **PRO** | Unlimited | 4/week | 8/week | Unlimited | 50,000 | | **PRO+** | Unlimited | 4/week | 8/week | Unlimited | 50,000 | | **Developer+** | Unlimited | Unlimited | Unlimited | Unlimited | Unlimited | See [Holder Notifications](/creator-tools/holder-notifications) for details. ## License - **Free, PRO, and PRO+**: Personal use only. You may use token pages and tools for your own token project. - **Developer**: Commercial use permitted. Integrate registration data and widgets into products you distribute or sell, and charge for premium apps on the platform. - **Partner**: Full commercial use with white-label rights. Redistribution and resale of embedded widgets permitted. ## Support | Tier | Support Channels | |------|-----------------| | **Free** | Community Discord, knowledge base | | **PRO** | Community Discord, email support (48h response) | | **PRO+** | Community Discord, email support (48h response) | | **Developer** | Email support (24h response), priority Discord channel | | **Partner** | Email support (4h response), priority Discord, scheduled calls, dedicated account manager | ## SLA | Tier | Uptime Guarantee | Credit Policy | |------|-----------------|---------------| | **Free** | Best effort | β€” | | **PRO** | Best effort | β€” | | **PRO+** | Best effort | β€” | | **Developer** | 99.5% monthly | β€” | | **Partner** | 99.9% monthly | 10% credit per 0.1% below target | ## Getting Started 1. [Create a token](/getting-started/create-a-token) or [claim an existing one](/getting-started/claim-an-existing-token) 2. Navigate to your token page and select **Upgrade** 3. Choose your tier and billing period 4. Access your new tools immediately after payment For detailed API documentation, including the full rate-limit and endpoint matrix, see [API Authentication](/api-reference/authentication#rate-limiting). ## Deal Fees Token plans cover token management tools. **Ownership deal facilitation** (buyouts, migrations, project acquisitions) has separate, usage-based pricing with a sliding scale that drops as deal size increases. See [Ownership Deals](/creator-tools/deals#fees) for the full fee schedule, including caps and tier examples. --- # Registration & Creation Pricing URL: https://docs.chaindaddy.io/pricing/registration Category: pricing # Registration & Creation Pricing One-time fees for getting your token onto Chain Daddy. Recurring plans are documented separately on [Token Plans](/pricing/plans). ## Create a Token Deploy a brand-new ERC-20 (or SPL on Solana) and file the on-chain registration in one flow. Token creation combines a flat per-chain creation fee with the registration fee. | Item | Cost | |------|------| | Token creation, per chain | **${{price.createFee}}** | | Registration, per chain | **${{price.crownFee}}** | | **Single-chain create + register** | **${{price.crownFee}} + ${{price.createFee}}** (creation + registration combined) | | Gas | Paid to the chain, varies (see [gas estimates](#gas-estimates)) | Standard create flow: [Create a Token](/getting-started/create-a-token). ## Multi-Chain Bundles Bundles combine creation + registration across multiple chains into one discounted price: a flat **10% off every chain** in any order of 2+ chains. Your registrations link automatically into one unified token page across all your deployments β€” see [Cross-Chain Linking](/token/cross-chain). | Bundle | Chains | Price | Savings vs. Γ  la carte | |--------|--------|-------|------------------------| | **Duo** | 2 | **${{price.bundles.duo.price}}** | ${{price.bundles.duo.savings}} | | **Tri** | 3 | **${{price.bundles.tri.price}}** | ${{price.bundles.tri.savings}} | | **Quad** | 4 | **${{price.bundles.quad.price}}** | ${{price.bundles.quad.savings}} | | **All-Chain** | 5 | **${{price.bundles.allChain.price}}** | ${{price.bundles.allChain.savings}} | Bundle prices already include both the creation fee and the registration fee for every chain in the bundle. You only pay gas on top. The same flat 10% applies to any mix of chains β€” including Ethereum, which has a higher per-chain price. ## Cross-Chain Linking Linking is **automatic and free**. When the same wallet registers the same ticker on additional chains β€” whether in one bundled order or one chain at a time β€” the registrations link into one unified token page on their own. There is no separate linking fee and no manual linking step; you only ever pay the normal per-chain registration or creation fees above. The one requirement: register from the **same wallet** on every chain. The token on each chain can have been created by a different wallet, as long as the wallet you register with passes that chain's [ownership verification](/token/verification-methods). See [Cross-Chain Linking](/token/cross-chain) for how the peer model works. ## Claim an Existing Token A flat platform fee covers your on-chain registration. You still pay gas on the destination chain. | Item | Cost | |------|------| | Standard platform fee | **${{price.crownFee}}** | | OG-eligible projects | **$0** ([see eligibility](#og-free-registration)) | | Gas | Paid to the chain, varies (see [gas estimates](#gas-estimates)) | Standard claim flow: [Claim an Existing Token](/getting-started/claim-an-existing-token). ## OG Free Registration {#og-free-registration} Established token projects that meet specific activity thresholds qualify for **OG status**, which waives the platform fee when registering a token β€” you only pay gas. ### Eligibility Criteria All three conditions must be met simultaneously: | Criterion | Requirement | |-----------|-------------| | **Deployment Age** | Token contract deployed 60+ days ago | | **Market Cap** | Market cap β‰₯ $50,000 | | **Liquidity** | Liquidity β‰₯ $10,000 | ::: tip Automatic Detection OG eligibility is calculated automatically from on-chain data. No application or manual review is required. ::: ### How to Check Eligibility 1. **Search your token name** on Chain Daddy 2. Look for the **OG badge** next to your token in search results 3. If the badge appears, your registration will be fee-free (gas only) The OG badge indicates the token has met all three criteria at the time of the search. Eligibility is recalculated on each search query using live on-chain data. ::: warning Eligibility Can Change If your token's market cap or liquidity drops below the thresholds before you register, the OG badge may disappear. Register while eligible to lock in the free rate. ::: ::: tip OG covers registration only The fee waiver applies only to the initial registration. Per-chain creation fees and bundle discounts still apply at standard rates. ::: ### OG FAQ **Does OG status expire after registering?** No. Once you register your token, the registration remains yours regardless of future activity levels. The OG check only applies at registration time. **Can I get a refund if I paid the platform fee but was eligible?** OG eligibility is checked at registration time. If the badge was not showing when you registered, you did not meet all three criteria at that moment. **My token is old but has low liquidity. Am I eligible?** All three criteria must be met simultaneously. A 60-day-old token below the market cap or liquidity threshold does not qualify. ## Gas Estimates {#gas-estimates} Gas costs are paid directly to the chain, not to Chain Daddy. Estimates vary with network conditions; L2s and Solana are consistently low, Ethereum mainnet swings the most. | Chain | Typical Gas Cost | |-------|------------------| | Arbitrum | $0.05-$0.50 | | Solana | $0.01-$0.05 | | Base | $0.01-$0.10 | | Polygon | $0.01-$0.05 | | BNB Chain | $0.05-$0.30 | | Ethereum | $5-$50+ | ## Deal Fees Ownership deal facilitation (buyouts, migrations, project acquisitions) is priced separately on a sliding scale with hard caps. See [Ownership Deals](/creator-tools/deals#fees) for the full schedule. ## Token Plans Recurring tools for token management (analytics, alerts, gated links, holder notifications, API access) are covered by plan tiers. See [Token Plans](/pricing/plans). --- # Cross-Chain Linking URL: https://docs.chaindaddy.io/token/cross-chain Category: token # Cross-Chain Manage your token's presence across multiple blockchains with unified ownership and metadata. ## Overview Cross-chain linking gives your token one name recognized on every chain. Instead of managing separate registrations independently, your per-chain registrations are linked as peers β€” they share metadata and present a unified token page. **What you get:** - One name aggregating all your chain deployments - Unified metadata synced across all linked registrations - Token List standard output for wallet and exchange auto-ingestion - Shared token page data across all chains ## Adding a Chain 1. **Start from your token page or Token Manager**: open the chain switcher and select **Add Chain** ![The chain switcher for CHAP β€” the current chains (Gnosis, Arbitrum, Polygon, Base, BNB Chain) with an "Add Chain" entry](/screenshots/select-chain-switcher.png) 2. **Pick the chain**: Chains you already have a registration on are marked "Already peered" and can't be double-added. Bundle two or more chains in one order for a 10% discount ![The Add Chain picker β€” bundle options, per-chain pricing, chains already registered marked "Already peered", and a "Select chains" cart button](/screenshots/add-chain-modal.png) 3. **Register or create on that chain**: Priced as a normal per-chain registration (or creation + registration) β€” [see pricing](/pricing/registration). Registering 2+ chains in one order gets the multi-chain bundle discount 4. **Done**: The new registration links to your existing ones automatically β€” no extra step, no linking fee After the new registration confirms, all your chains appear together on the ticker's public token page. ### Same wallet, not same creator Linking is keyed on the wallet that **owns the registrations** β€” not the wallet that created each token: - **To link, register from the same wallet.** Registrations only group into one token page when the same wallet owns them on every chain. Registrations made from different wallets stay separate. - **The token itself can come from anywhere.** Each chain's token may have been deployed or created by a different wallet. What matters is that the wallet you're registering with passes that chain's [ownership verification](/token/verification-methods) β€” deployer, contract owner, mint/update authority (Solana), or majority holder all qualify. ## Supported Chains | Chain | Type | Token Standard | Notes | |-------|------|---------------|-------| | Ethereum | EVM | ERC-20 | Higher gas costs | | Arbitrum | EVM | ERC-20 | Low gas costs | | Base | EVM | ERC-20 | Shared address across EVM chains | | Polygon | EVM | ERC-20 | Shared address across EVM chains | | BNB Chain | EVM | ERC-20 | Shared address across EVM chains | | Avalanche | EVM | ERC-20 | Shared address across EVM chains | | Gnosis | EVM | ERC-20 | Shared address across EVM chains | | Solana | SVM | SPL | Native program, lowest fees | ::: tip EVM Same-Address Deployment Tokens created through Chain Daddy on EVM chains share the same contract address across all EVM deployments, simplifying integration. ::: ::: tip Solana Native Registrations Solana registrations use native program accounts with Metaplex NFT compatibility. They appear in standard Solana wallets and can be linked to EVM registrations for cross-chain presence. ::: ## Linking Is Automatic There is no separate linking step and no linking fee. When the same wallet registers the same ticker on another chain, the registrations link automatically as peers β€” you get: - One name linking all your chain registrations - Cross-chain metadata synchronization - Token List standard inclusion ::: info One signature per chain "Automatic" means there's no separate linking step, transaction, or fee β€” the peering that groups your registrations happens on its own. But each chain's registration is its own on-chain action, so you sign once per chain as you add it. Registering on three chains is three signatures (one per registration); the grouping into a single token page then happens automatically, with no extra signature. ::: ::: info [Multi-chain bundles](/getting-started/create-a-token) are simply the discounted way to buy several chains at once β€” every multi-chain registration links automatically, bundled or not. ::: ## How Linking Works One name recognized on every chain β€” that's the whole model. Each ticker (e.g., DOGE) groups all per-chain registrations owned by the same wallet as equal peers, so your Arbitrum, Solana, and Base registrations present as one token, not three. ![My Tokens dashboard β€” one ticker (CHAP) held by the same wallet across Arbitrum, Base, BNB Chain, Gnosis, and Polygon](/screenshots/auto/my-tokens--desktop--light.png) *Owners see the same peer group grouped by chain in their dashboard: one ticker claimed on five chains by the same wallet, presented as one token.* ### Ticker Structure ``` Ticker: DOGE └── Linked Registrations (same wallet): β”œβ”€β”€ Arbitrum β†’ doge-arb β”œβ”€β”€ Solana β†’ doge-sol └── Base β†’ doge-base ``` **Key concepts:** | Concept | Description | |---------|-------------| | Ticker | Top-level grouping for a token name across all chains | | Linked Registrations | Per-chain registrations owned by the same wallet, sharing metadata | | Representation | A per-chain registration under the ticker | ### Peer Model All linked registrations are equal. There is no "primary" or "master" designation. When the same wallet owns registrations for the same ticker on multiple chains: - All registrations share a single set of metadata - Editing any registration's metadata updates all linked registrations - Each registration resolves independently via its chain-specific URL ### One registration per chain per wallet A wallet's peer group for a ticker admits **at most one registration per chain**. You can own DOGE on Arbitrum and DOGE on Base and DOGE on Solana β€” three distinct entries in the same peer group β€” but you cannot hold two Solana DOGE registrations under the same wallet. Attempting to add a second registration on a chain you already peer (for example, a second Solana DOGE registration with a different token address) is rejected at every layer: the Add Chain picker crosses the chain out with "Already peered", the API rejects the request before any transaction is built, and the on-chain registry reverts `DuplicateChainInPeerGroup` if a transaction still reaches it. If you need to re-point a chain slot at a different token (for example, migrating DOGE on Solana from an old mint to a new one), remove the existing peer first, then add the new one. To keep multiple registrations of the same ticker on the same chain, use a different wallet β€” peer groups are per `(ticker, wallet)`, so a second wallet can carry its own independent registration on that chain. ## Unified Metadata When registrations are linked, metadata changes sync across all representations: | Field | Behavior | |-------|----------| | Name | Shared across all linked registrations | | Description | Shared across all linked registrations | | Logo | Shared across all linked registrations | | Social links | Shared across all linked registrations | | Token address | Per-chain (unique to each representation) | | Contract details | Per-chain (unique to each representation) | ::: warning Chain-specific fields (token address, contract details) remain unique per representation. Only registration-level metadata syncs across chains. ::: ## Token List Standard Output Linked registrations automatically generate a Token List compatible JSON file. This follows the widely-adopted token list standard used by wallets and exchange aggregators. **What it includes:** - Token name, symbol, decimals - Per-chain contract addresses with chain IDs - Logo URI from your token metadata - Version tracking for updates **Endpoints:** ``` GET /tokenlist.json # All verified tokens GET /tokenlist/arbitrum.json # Chain-specific list GET /tokenlist/solana.json ``` Wallets and exchanges can subscribe to your token list for automatic metadata updates without manual listing applications. ::: tip Combined with [Listing Export](/creator-tools/listing-export), cross-chain linking gives you one-click distribution of your token data to all major platforms. ::: ## Verification by Chain Ownership verification methods differ between EVM and Solana due to different program and contract models. See [Verification Methods](/token/verification-methods) for the full chain-vs-method matrix β€” deployer, contract owner, mint/update authority (Solana), and majority holder β€” and how strength rankings apply. ## Costs | Action | Fee | |--------|-----| | Linking | Free β€” automatic when the same wallet registers the same ticker on 2+ chains | | Adding a chain | Normal per-chain registration/creation fee ([see pricing](/pricing/registration)) | | Metadata sync | Free | | Token List inclusion | Free | ::: tip Registering multiple chains in one order qualifies for multi-chain bundle discounts. See [Create a Token](/getting-started/create-a-token) for bundle options, and [Registration & Creation Pricing](/pricing/registration) for the current rate card. ::: --- # Token Ownership URL: https://docs.chaindaddy.io/token/ Category: token # Token Ownership Your on-chain registration is your token's verified identity. This section covers everything from registering and configuring your token to customizing how it appears to the world. ![A public token page β€” branding, verified socials, live market stats, and a live price chart](/screenshots/auto/token-page--desktop--light.png) *A public token page: branding, verified socials, live market stats, and a live price chart.* ## Guides - **[Token Management](/token/token-management)**: Edit metadata, delegate a manager role, view your health score, and release your registration. - **[Verification Methods](/token/verification-methods)**: Prove token ownership via deployer, mint authority, contract owner, or majority holder verification. - **[Token Page Themes](/token/themes)**: Customize colors, backgrounds, layouts, and CSS on your public token page. - **[Social Verification](/token/social-verification)**: Verify X/Twitter, Discord, GitHub, and other social accounts to display badges on your token page. - **[Cross-Chain](/token/cross-chain)**: Link your token's registrations across multiple chains under a unified name and token page. --- ## Vanity URL {#vanity-url} Every registration gets a vanity URL at `{symbol}.crown.info` β€” a short, shareable link to your public token page. The URL is assigned automatically when you register and works on all tiers, including Free. If your token is registered on multiple chains with linked records, the vanity URL resolves to your unified cross-chain page. ## Watermark {#watermark} Token pages on Free and Pro tiers display a small Chain Daddy logo watermark in the corner of the page. The watermark is removed on Pro+ and above. If you upgrade and later downgrade, the watermark reappears on your next page load. ![The Chain Daddy logo watermark in the top corner of a Free/Pro token page](/screenshots/watermark-example.png) ::: tip Pro+ and above Watermark removal is included with [Pro+](/pricing/plans) and all higher tiers. ::: ## Trust Badges {#trust-badges} Verification status badges are displayed on your token page to signal trust to visitors. Badges reflect your verification method (deployer, mint authority, majority holder) and any completed social verifications. Stronger verification methods show a more prominent badge. Trust badges are available on all tiers and update automatically as you complete additional verifications. ![A verified social link on a token page β€” the handle carries a check badge once verified](/screenshots/social-verified-badge.png) Verified social links show a **check** badge; links you've added but not yet verified show a shield-question until you complete the flow. See [Social Verification](/token/social-verification) for the full process and [Verification Methods](/token/verification-methods) for how each ownership method contributes. ## Social Links {#social-links} Add links to your social profiles and community channels directly on your token page. Visitors see clickable icons for each platform you configure. The number of social links available depends on your tier: | Tier | Social Links | |------|-------------| | Free | 6 | | Pro | 12 | | Pro+ | 20 | | Developer | 30 | | Partner | 50 | Supported platforms include X/Twitter, Discord, Telegram, GitHub, YouTube, TikTok, Instagram, Reddit, and custom URLs. Configure your social links from the **Edit** modal (click Edit on your token's Token tab in the manager). --- # Liquidity URL: https://docs.chaindaddy.io/token/liquidity Category: token # Liquidity **Liquidity** is what makes your token *tradable*. For anyone to buy or sell `$YOURS`, there has to be a pool on a decentralized exchange (DEX) that holds some of your tokens paired with a base asset like ETH or SOL. That pool is your token's "market" β€” its size sets how much can trade before the price moves, and the ratio you seed it with sets the **opening price**. You don't need to be a DeFi expert. This page explains your options in plain language and helps you pick the one that fits. ::: tip The one-sentence version If you want people to be able to buy your token, you need a liquidity pool. You can set one up **at launch** (plan it in the creation wizard, then add it in one click right after mint) or **any time later** (from your token manager). You can also **lock** the pool tokens to prove you won't pull the rug. ::: ## Do you even need it? Not every token needs liquidity right away: - **Community or reward token, no trading yet?** Launch it **non-tradable** and add liquidity later when you're ready. Nothing breaks β€” your token page, holder tools, and metadata all work without a pool. - **Want it tradable from minute one?** Seed a pool **at launch** so buyers can trade the moment it mints. - **Already launched and want a market now?** Add liquidity **from your token manager** (see below). ## How much can you add? (supply & decimals) When you add liquidity you enter an amount of **your token** to pair with ETH/SOL. That amount is in **whole tokens**, and it has to be **no more than your wallet holds**. Two ideas trip up first-timers: - **Total supply is a count of whole tokens.** If you launched with a supply of `1,000,000`, then one million whole tokens exist β€” and at launch, you hold them. You can pair up to that many as liquidity. - **"Decimals" are precision, not quantity.** Decimals (18 on EVM, 9 on Solana by convention) let each token divide into tiny fractions β€” like cents in a dollar. They don't change *how many* tokens you have. You always work in **whole tokens** β€” for transfers, for liquidity, everywhere β€” and never have to think about the "base units" underneath. ::: warning Adding more than you hold The most common "Create Pair" failure is entering a bigger number than your wallet actually holds β€” for example, trying to seed `10` tokens when you only hold a fraction of one. The app **checks your balance before anything is signed**, so you never waste gas on a pool that can't be funded. If you see *"you're adding X but this wallet holds Y,"* lower the amount β€” or you set the supply smaller than you meant at launch. ::: ## Your three options ### 1. Plan liquidity at launch (in the wizard) The [creation wizard](/getting-started/create-a-token#step-5-liquidity-trading-pair)'s **Liquidity** step is where you set the plan: - **Supply % paired** β€” how much of your total supply goes into the pool; the rest stays in your wallet. 50% is a common starting point: higher means a deeper, more stable market, lower keeps more tokens for you (airdrops, treasury, team). - **Native amount** β€” how much ETH / SOL / etc. you pair alongside those tokens. Together with the supply %, this sets your **opening price**. Your token **launches first**, then you add the liquidity from your own wallet as a quick next step. The moment the mint finishes, an **"Add liquidity now β†’"** button takes you straight to Create Pair with these amounts already filled in β€” one click and your pool is live. Prefer to wait? Skip the step to launch non-tradable and add liquidity anytime later. ### 2. Add liquidity later (from your token manager) Open your token manager and find the owner-only **[Liquidity](/token/token-management#liquidity)** section. There you can: - **Pick the chain** β€” add liquidity on any chain you own the token on, right from the Liquidity section; no need to open each chain's page separately. - **Create a trading pair** β€” open a new DEX pool and fund it from your wallet. Where a chain has more than one DEX (for example Uniswap, Camelot, or SushiSwap on Arbitrum), pick the one your community trades on. - **Add to an existing pair** β€” deepen a pool you already created, or **link** a pair you made on the DEX directly so it shows on your token page. ![The Liquidity section β€” pick a chain, then link or create a trading pair and lock your LP](/screenshots/liquidity-section.png) **Create Pair** opens a short form: choose the DEX, enter how much of your token and native asset to seed, then **Add Liquidity**. Because a pool is public and one-way, you confirm before signing. | | | |---|---| | ![Create Pair β€” choose the DEX and the token + native amounts to seed the pool](/screenshots/liquidity-create-pair.png) | ![Add Liquidity confirmation β€” creating a public trading pair is permanent](/screenshots/liquidity-add-confirm.png) | Before you sign, the app checks your token and native balances, so an amount you can't cover is caught up front β€” no wasted gas. It's the same market a launch-time pool creates β€” just on your schedule. ### 3. Lock your LP tokens When you add liquidity, the DEX gives you **LP tokens** β€” a receipt for your share of the pool. Whoever holds those LP tokens can withdraw the pooled liquidity, so **locking** them (for a fixed period) is the single strongest signal to traders that you won't "pull the rug." Lock your LP from the **Liquidity** section of your token manager on EVM chains β€” paste the LP token address and the lock URL from a locker like **UNCX**, **Team.Finance**, or **PinkSale**, and Chain Daddy verifies it on-chain. ![Add LP Lock β€” paste the LP token address and the lock URL; the locker platform is auto-detected](/screenshots/liquidity-lp-lock.png) Traders can verify the lock on-chain, and a locked pool reads as a real trust signal on your token page. ::: tip Chains differ LP locking is available on the EVM chains. On Solana, liquidity lives in programs like Raydium β€” your manager lists your Solana trading pairs, and you manage or lock liquidity through the Solana DEX's own tooling. ::: ## What sets the price? Your opening price is just the **ratio** of the two sides of the pool: > price per token β‰ˆ native amount Γ· tokens paired Pair more native for the same number of tokens β†’ higher opening price. Pair more tokens for the same native β†’ lower opening price. After launch the market moves the price as people trade; the amount you seeded determines how much buying or selling it takes to move it. ## A word on risk - **Your paired native is real money.** Seeding a pool moves ETH/SOL from your wallet into the pool. If people sell into the pool it ends up with more of your token and less native β€” that's normal market behavior, not a bug. - **Locking is a commitment.** A locked LP position can't be withdrawn until the lock ends. Lock an amount and duration you're comfortable committing to. - **Start reasonable.** You can always add more liquidity later β€” you don't need a huge pool on day one. ## Next steps - [Create a Token](/getting-started/create-a-token#step-5-liquidity-trading-pair) β€” seed a pool during launch - [Token Management](/token/token-management#liquidity) β€” the Liquidity section in your manager - [Token Health & Anti-Squatting](/platform/heartbeat) β€” trading activity feeds your health score --- # Social Verification URL: https://docs.chaindaddy.io/token/social-verification Category: token # Social Verification Verify ownership of your social accounts and website domain, and display verified badges on your token page. Verified social channels also contribute to your [health score](/platform/heartbeat). ## How verification works **1. Add a link.** Add a social or website link on your token page β€” Chain Daddy auto-detects the platform. ![Adding a social link β€” paste your X profile URL; it's detected as X (Twitter)](/screenshots/social-add-link.png) **2. It starts unverified.** New links carry a **shield-question** badge, and a shield in the top bar flags how many are waiting. | | | |---|---| | ![An unverified X link β€” a shield-question badge until you verify it](/screenshots/social-unverified.png) | ![The verification shield in the top nav, badged with the unverified count](/screenshots/social-verify-bell.png) | **3. Open the Verify panel.** The **Verify External Links** panel lists every link with a **Verify** button (or **Verify All**). ![The Verify External Links panel β€” one row per link with a Verify button and a "Verify All" action](/screenshots/social-verify-modal.png) **4. Prove ownership.** OAuth platforms (X, Discord, …) send you to authorize read-only access; bio-code and website methods use a code (both covered below). ![Authorizing on X β€” "Chain Daddy wants to access your X account"](/screenshots/social-oauth-authorize.png) **5. Verified.** The account is now linked to your token, and it shows a **check** badge on your page. | | | |---|---| | ![X verified β€” the account is now linked to your token](/screenshots/social-verified-success.png) | ![The verified X handle with a check badge on the token page](/screenshots/social-verified-badge.png) | The rest of this page covers the specifics for each verification method. ## Supported Platforms | Platform | Method | Badge Display | |----------|--------|---------------| | **X (Twitter)** | OAuth | Verified handle with link | | **Discord** | OAuth | Verified username with link | | **Twitch** | OAuth | Verified channel with link | | **YouTube** | OAuth | Verified channel with link | | **GitHub** | OAuth | Verified username with link | | **TikTok** | Bio code | Verified handle with link | | **Telegram** | Bio code | Verified channel with link | | **Instagram** | Bio code | Verified handle with link | | **Reddit** | Bio code | Verified username with link | | **PumpFun** | Wallet match | Verified creator badge | | **Website** | DNS TXT / HTML meta | Verified domain with link | ## OAuth Verification (X, Discord, Twitch, YouTube, GitHub) Prove you control an account by authenticating via OAuth. ### Flow 1. Click **Verify [Platform]** on your token manager dashboard 2. You'll be redirected to the social platform for authorization 3. Grant read-only access to your account 4. Sign the verification attestation with your wallet (EVM or Solana) 5. Badge appears on your token page immediately ### What Gets Verified - Your platform username or channel name - The connection between your wallet address and platform identity - Timestamp of verification ### Platform-Specific Scopes | Platform | Access Granted | |----------|---------------| | X | Read profile info | | Discord | Identify (username, avatar) | | Twitch | Read user info | | YouTube | Read channel info | | GitHub | Read user profile | ## Bio Code Verification (TikTok, Telegram, Instagram, Reddit) Prove you control an account by placing a unique verification code in your profile bio or channel description. ### Flow 1. Click **Verify [Platform]** on your token manager dashboard 2. You'll receive a unique verification code (valid for 10 minutes) 3. Add the code to your profile bio or channel description 4. Enter your handle/username and click **Check** 5. The system fetches your public profile and confirms the code 6. Sign the verification attestation with your wallet 7. Badge appears on your token page. You can remove the code from your bio ![The bio-code verification step for Telegram β€” a one-time verification code to place in your channel description, plus a handle input](/screenshots/social-verify-biocode.png) ### Platform-Specific Details | Platform | Where to Place Code | |----------|-------------------| | TikTok | Profile bio | | Telegram | Channel description (public channels or groups only) | | Instagram | Profile bio | | Reddit | User bio/about | ::: tip The verification code only needs to be in your bio at the moment of checking. You can remove it immediately after verification. ::: #### Telegram: public channel (bio code): one option The bio-code path reads the `description` field of a **public Telegram channel or group** via the Bot API. Requirements: 1. **A public Telegram channel or group with a `@username`.** Private channels (`t.me/+invite-link`) cannot be verified via this path. If you only have a private group, switch it to public, or create a dedicated channel. Telegram's official guide: [How to create a channel](https://telegram.org/faq_channels) and [How to make a public channel/group](https://telegram.org/blog/usernames-and-secret-chats-v2). 2. **You must be an admin** on the channel/group so you can edit the description. 3. **Set the verification code in the `Description` field** of the channel (not a posted message). Open channel info β†’ **Edit** (pencil icon) β†’ **Description** β†’ paste the code β†’ save. ::: warning Description propagation lag Telegram caches channel descriptions for the Bot API. When you save a fresh description edit, it can take up to **~30 seconds** before our verifier sees the new content. If verification fails immediately after saving, wait 30 seconds and try **Check** again. ::: #### Telegram: personal account (Login Widget): the other option If you don't have or want a public channel, the [Telegram Login Widget](https://core.telegram.org/widgets/login) path lets you verify your personal Telegram account directly. The widget asks you to authorize Chain Daddy's verification bot (read-only: your Telegram ID + username); on confirmation the widget returns a signed payload to the page, which the backend HMAC-verifies against the bot's secret key. The signed attestation is stored under the same `telegram` platform key as the channel path, verified handles render identically regardless of which path produced them. API endpoint: `POST /api/v2/verify/social/telegram-personal/check` (no `/init` step, the widget is purely client-side). ## PumpFun Verification Prove you created a token on PumpFun by matching your connected wallet to the token's deployer address on Solana. ### Flow 1. Click **Verify PumpFun** on your listing manager dashboard 2. Enter your PumpFun token's mint address 3. The system checks on-chain that your connected wallet deployed the token 4. Optionally, if deployer doesn't match, you can use the bio-code method on PumpFun's profile page 5. Sign the verification attestation 6. Badge appears on your token page ## Website Verification Prove you control a domain by adding a verification record. ### Method 1: DNS TXT Record Add a TXT record to your domain's DNS: ``` _chaindaddy-verify.yourdomain.com TXT "chaindaddy-verify=YOUR_VERIFICATION_CODE" ``` ### Method 2: HTML Meta Tag Add a meta tag to your website's ``: ```html ``` ### Flow 1. Click **Verify Website** on your listing manager dashboard 2. Enter your domain name 3. Copy the verification code provided 4. Add the DNS TXT record or HTML meta tag 5. Click **Check Verification**: the system checks for the record 6. Sign the attestation with your wallet 7. Badge appears on your token page ::: tip DNS Propagation DNS TXT records can take up to 48 hours to propagate. The HTML meta tag method is instant. ::: ## Verification Badges Verified accounts display checkmark badges on your public token page. Each badge shows: - Platform icon and verified handle/channel - Link to your profile on that platform - Verification date Badges appear in your token page header and are visible to all visitors. Verified links show a check badge; links you've added but not yet verified show a shield-question badge until you complete the flow. ![Links in the token page header β€” a verified X handle with a check badge, alongside website, Telegram, and GitHub links with unverified shield-question badges and an "Add link" affordance](/screenshots/social-links-badges.png) ## Multi-Chain Support Works with both EVM and Solana wallets. Your verification is tied to the specific wallet you sign with. ## Social Links In addition to verified accounts. You can add unverified social links to your token page: | Link Type | Format | |-----------|--------| | X (Twitter) | Handle or profile URL | | Discord | Invite link | | Telegram | Channel or username | | GitHub | Repository or org URL | | Website | Any HTTPS URL | | Whitepaper | Documentation URL | | Email | Contact address | | Custom | Any URL | Unverified links display without the verification badge but still link to your social presence. ## Managing Verifications - View all verifications from your token manager dashboard - Each registration can have independent verifications - Verifications persist unless explicitly removed - Re-verification is available if you change your handle or domain - You can verify up to 11 platforms per registration (all supported platforms) --- # Token Page Themes URL: https://docs.chaindaddy.io/token/themes Category: token # Token Page Themes & Customization Customize your token page's appearance with colors, backgrounds, layouts, and more. ## Token Pages in the Wild Every token page carries the token's own branding out of the box β€” hero banner, logo, links, and live market data are auto-populated from public metadata before anyone even claims the page. The theming controls on this page let verified owners layer their own look on top: custom colors, backgrounds, animated overlays, layouts, and CSS. | | | |---|---| | ![PENGU token page with Pudgy Penguins hero banner](/screenshots/auto/token-page-pengu--desktop--light.png) | ![POPCAT token page with wall-of-cats hero banner](/screenshots/auto/token-page-popcat--desktop--light.png) | ![BRETT token page with blue comic-style hero banner](/screenshots/auto/token-page-brett--desktop--light.png) ## Opening the Style Editor {#opening-the-style-editor} All theming lives in the **Style editor**. Open it from the **chain switcher** in the top bar of your token manager and click the **sliders / Style button** (circled below) β€” it sits right next to the gear icon that opens admin settings. ![The chain switcher β€” the Style button (circled) opens the Style editor; the gear icon beside it opens admin settings](/screenshots/admin-chain-selector-style.png) You can also open it straight from your token page: click **Edit** while viewing your page as the owner. ## Color Customization ### Background Colors Choose from 16 preset background colors:
Midnight
#1a1a2e
Ocean
#0a1628
Forest
#1a2e1a
Sunset
#2e1a1a
Lavender
#1e1a2e
Charcoal
#2a2a2a
Wine
#2e1a28
Slate
#1e2a3a
Navy
#0d1b3e
Emerald
#0d2e2e
Rose
#2e0d1b
Amber
#2e2a0d
Indigo
#1a0d3e
Teal
#0d2e28
Copper
#2e1e0d
Obsidian
#0a0a0a
### Accent Colors Choose from 16 preset accent colors for highlights, buttons, and interactive elements: Amber, Blue, Green, Pink, Purple, Red, Orange, Cyan, Lime, Fuchsia, Yellow, Violet, Emerald, Rose, Sky, Gold ### Custom Colors (PRO) PRO subscribers can enter any hex color value for both background and accent, beyond the preset options. ## Backgrounds Backgrounds and animated overlays live in the **Background Media** section of the Style editor. Pick a solid color, gradient, or uploaded image, then layer an animated overlay on top. ![The Background Media and Animated Overlay controls in the Style editor β€” background tiles (None, Solid, Gradient, Upload) and the overlay gallery (Particles, Gradient Shift, Sparkle, Snow, Bubbles, Confetti, Aurora, Stars)](/screenshots/theme-background-media.png) ### Patterns Apply subtle pattern overlays to your token page background. Patterns layer on top of your background color. ### Background Images Upload a custom image for your token page background. Images are stored on IPFS for permanence. - Supported formats: PNG, JPG, WebP - Recommended size: 1920x1080 or larger - Images are automatically optimized for different screen sizes ### Animated Overlays Add motion to your token page with animated effects: | Effect | Description | |--------|-------------| | Particles | Floating particle field | | Gradient | Slowly shifting color gradient | | Sparkle | Glittering sparkle effect | | Rain | Falling rain drops | | Snow | Gentle snowfall | | Bubbles | Rising bubble animation | | Confetti | Celebratory confetti burst | | Wave | Undulating wave motion | | Aurora | Northern lights effect | | Stars | Twinkling starfield | ### Video Backgrounds (PRO) Upload a looping video as your token page background. Includes poster image support for loading states. - Supported formats: MP4, WebM - Auto-loops with no audio - Poster image displayed during load ## Layouts Choose how your token page content is arranged: - **Standard**: Default card-based layout - **Compact**: Dense layout optimized for information density - **Wide**: Full-width sections for maximum visual impact - **Minimal**: Clean layout with minimal chrome ## Templates Pre-configured theme combinations for quick setup. Templates set your colors, background, and layout in one click. You can further customize after applying a template. ## Theme Mode Control your token page's light/dark appearance: - **Light**: Light backgrounds with dark text - **Dark**: Dark backgrounds with light text (default) - **Auto**: Matches the visitor's system preference ## Custom CSS (PRO) Write custom CSS rules to style any element on your token page. This gives full control over typography, spacing, animations, and any visual property. ::: warning Custom CSS applies only to your public token page. Malformed CSS is sanitized before rendering. ::: ## Featured Links Add prominent links to your token page that appear above the fold: - Website URL - X (Twitter) handle - Telegram channel - Discord invite - GitHub repository - Whitepaper/docs URL - Email contact - Custom links with any URL Links include validation and platform-specific formatting. ## Managing Themes All theming lives in the **Edit** panel for your token page: 1. Open your token page as the owner (or from your token manager). 2. Click the **chain switcher** in the top bar and choose **Style preferences** (the sliders icon) β€” or click **Edit** on your token page. 3. Set colors, theme mode, layout, and templates in the appearance controls. 4. Add patterns, background images, animated overlays, and video under **Background Media**. 5. Add featured links, and β€” on PRO β€” custom CSS. ![The Style editor β€” Page Layout & Theme controls: layout (Default, Link in Bio, Landing), theme presets, and a live preview of the token page](/screenshots/theme-style-panel.png) Changes show a live preview before saving. Use **Reset to Defaults** to restore the original theme. --- # Token Management URL: https://docs.chaindaddy.io/token/token-management Category: token # Token Management Once you've registered your token, use the Token Manager to maintain your token's on-chain presence. ![The Token Manager for a token registered on five chains β€” edit metadata, socials, and theme; switch chains or add a new one](/screenshots/manager-overview.png) ## Editing Metadata From your Token Manager. You can update: | Field | Description | |-------|-------------| | **Name** | Display name for your token | | **Description** | Short description (max 280 characters) | | **Logo** | Token logo image (PNG/SVG, max 512x512) | | **Website** | Project website URL | | **Social Links** | X/Twitter, Discord, Telegram links | | **Tags** | Category tags (meme, gaming, governance, etc.) | Changes are written on-chain and reflected across all listing exports and token pages. ::: tip Keep your metadata complete β€” tokens with complete metadata rank higher in search results. ::: ## Chain Admin Settings Roles, liquidity, and destructive actions are managed **per chain**, from that chain's admin panel. Open it from the **chain switcher** in the top bar of your Token Manager and click the **gear icon** (circled below): ![The chain switcher β€” the gear icon (circled) opens that chain's admin settings; the sliders icon opens Style preferences](/screenshots/admin-chain-selector-gear.png) The admin panel is scoped to the chain you're viewing and covers **[Roles](#roles)**, **[Listing Export](#listing-export)**, **[Liquidity](#liquidity)**, and the **[Danger Zone](#danger-zone)** β€” everything applies to the currently-selected chain only. ### Roles {#roles} Grant page-management access to other wallets β€” a **Manager** (day-to-day edits) or a **Maintainer**. The owner is shown at the top and can't be changed (it's bound to your registration). Add a role by entering a wallet address; you can also import or export the role list as CSV. ![The Roles section β€” owner, managers, and maintainers, with add / import / export controls](/screenshots/admin-roles.png) ### Listing Export {#listing-export} Export this chain's registration as pre-filled listing data for exchanges and aggregators, or point them at the automatic Token List feed. New here? The [**Listing Export guide**](/creator-tools/listing-export) walks through the full export flow and the supported platforms. ### Liquidity {#liquidity} Manage this chain's on-chain market in its own section β€” **create a trading pair**, **add liquidity**, and **lock your LP tokens**. It sits above the Danger Zone so routine liquidity work stays separate from irreversible actions. New to this? The [**Liquidity guide**](/token/liquidity) walks through each option and helps you decide what fits your token. ### Danger Zone {#danger-zone} Irreversible, chain-scoped actions live here, outlined in red. For **factory tokens** (created through Chain Daddy), the Danger Zone also surfaces this deployment's on-chain **Token Settings**. **Contract Ownership** sits at the top: **Renounce** makes every owner-only setting (limits, exemptions, mint authority) permanent; **Transfer** hands control to another wallet β€” use it before selling the project or handing off to a DAO / multisig. ![Token Settings in the Danger Zone β€” Contract Ownership (Renounce / Transfer) surfaced first](/screenshots/admin-token-settings.png) Below it, Token Settings covers the rest of the on-chain configuration: - **Trading Status** β€” enable trading if the token launched paused. - **Supply** β€” mint (if mintable), set a max supply, or lock the supply permanently. - **Anti-whale limits** β€” max transaction and max wallet, plus deadblocks (the same [Trust Features](/getting-started/create-a-token#step-4-trust-features) you set at launch). Removing a limit is protected by a 24-hour timelock. - **Exemptions** β€” addresses that bypass the limits, and LP pairs exempt from the wallet limit. - **Immutable features** β€” the mintable / burnable capabilities the token launched with (these can't change), plus a **Burn** control for your own tokens. ![Immutable features β€” the mintable / burnable capabilities set at launch, and a Burn control](/screenshots/admin-token-features.png) Finally, **Release Token** permanently frees this chain's registration so the ticker can be claimed by someone else (your other chains are unaffected): ![Release Token β€” transfer or renounce the contract first, then permanently free the symbol on this chain](/screenshots/admin-release-token.png) ::: info Imported tokens Tokens you registered but didn't create through Chain Daddy have no Chain Daddy trust config, so the Token Settings block doesn't appear β€” only **Release Token** does. ::: ::: warning Everything in the admin panel applies to the **currently-selected chain** only. To manage another chain, switch to it with the chain switcher first. ::: ## Manager Role Token owners can delegate a **manager** address to handle day-to-day page edits. ### What a Manager Can Do - Edit metadata (name, description, logo, links) - Update token contract address - View health analytics ### What a Manager Cannot Do - Set other managers - Release the registration - Transfer ownership - Register additional tokens on behalf of the owner To set a manager, open your chain's admin settings (chain switcher β†’ gear icon) and add the wallet address in the [Roles](#roles) section. ::: warning Only the token owner can add or remove managers. Choose a trusted address. ::: ## Releasing a Registration If you no longer want to hold a registration, you can **release** it. This permanently retires the on-chain credential bound to your wallet. **Consequences of releasing:** - The ticker becomes available for others to register - All metadata associated with your registration is cleared - This action is irreversible. You cannot undo a release - If you want the ticker back, you'll need to go through the full registration process again To release, open your chain's admin settings (chain switcher β†’ gear icon) and use **Release Token** in the [Danger Zone](#danger-zone). ::: danger Releasing a registration is permanent. There is no undo. There are no admin recovery functions. ::: --- # Verification Methods URL: https://docs.chaindaddy.io/token/verification-methods Category: token # Verification Methods Before registering a token, you must prove you own it. Chain Daddy supports multiple verification methods depending on the chain type. ## Chain vs Method Matrix | Method | EVM Chains | Solana | |--------|:----------:|:------:| | Mint Authority | β€” | βœ“ | | Update Authority | β€” | βœ“ | | Owner (contract) | βœ“ | β€” | | Deployer | βœ“ | βœ“ | | Majority Holder | βœ“ | βœ“ | ## Strength Rankings Each method has a strength ranking that determines priority when multiple wallets could verify the same **open** slot. | Rank | Method | Description | |------|--------|-------------| | 1 (Strongest) | Mint Authority | Wallet controls token minting (Solana only) | | 2 | Update Authority | Wallet controls metadata updates (Solana only) | | 3 | Owner | Contract `owner()` returns your address (EVM only) | | 4 | Deployer | Wallet that originally deployed the contract | | 5 (Weakest) | Majority Holder | Wallet holds >50% of total supply | Strength matters only while a slot is unclaimed or expired. Registrations are **first-claim-wins** per (symbol, chain, token): once a valid registration exists, it is not displaced by a later claimant β€” even one with a stronger method. The stronger badge does show on your token page as a stronger trust signal. ## EVM Methods ### Owner Chain Daddy calls the `owner()` function on your token contract. If it returns your connected wallet address, verification passes. **Requirements:** - Contract implements `owner()` (standard Ownable pattern) - Connected wallet matches the returned address ### Deployer Chain Daddy checks on-chain deployment history to confirm your wallet created the token contract via `CREATE` or `CREATE2`. **Requirements:** - Connected wallet is the original deployer - Deployment transaction is indexable on the target chain ::: tip Deployer verification works even if ownership was later transferred or renounced. ::: ### Majority Holder Chain Daddy checks your wallet's token balance against total supply. You must hold more than 50% of the circulating supply. **Requirements:** - Connected wallet holds >50% of total supply - Balance is checked at verification time (not historical) ::: warning If you sell tokens and drop below 50%, your verification remains valid β€” registrations are first-claim-wins and are not displaced by other claimants. But if your registration later expires through [activity decay](/platform/heartbeat), the slot opens again and any qualifying wallet (including one with a stronger method) can claim it. ::: ## Solana Methods ### Mint Authority Chain Daddy checks if your connected wallet is the current mint authority for the SPL token β€” this is the strongest Solana verification because mint authority has the most control over token supply. **Requirements:** - Connected wallet is the current mint authority - Mint authority has not been revoked ### Update Authority Chain Daddy checks if your wallet is the metadata update authority. This proves control over the token's on-chain metadata. **Requirements:** - Connected wallet is the update authority on the token's metadata account ### Deployer Similar to EVM, Chain Daddy checks if your wallet initiated the token creation transaction. **Requirements:** - Connected wallet signed the original token creation instruction ### Majority Holder Same as EVM, your wallet must hold more than 50% of the token's total supply. **Requirements:** - Connected wallet holds >50% of total supply - Balance checked at verification time ## Frequently Asked Questions ### I lost access to my deployer wallet. What can I do? If you still have access to a wallet with a stronger verification method (e.g., Mint Authority on Solana, Owner on EVM), use that instead. If you have no other qualifying wallet: 1. Wait for the registration to expire via activity decay (30+ consecutive days below 60) 2. Register again from a new wallet through the standard flow ([see pricing](/pricing/registration)) 3. For future registrations, consider using a multisig wallet for built-in recovery ::: tip Prevent this scenario Register from a multisig (like Safe) so no single key loss locks you out. ::: ### Can I verify with a different wallet than I registered with? No. The wallet that verifies is the wallet that registers. Registrations are permanently bound to the verifying wallet. ### What if ownership was transferred after I deployed? Deployer verification still works β€” it checks historical deployment, not current ownership. And because registrations are first-claim-wins, the new owner cannot take over your existing registration with a stronger method; strength only matters if the slot is unclaimed or your registration expires. ### My token has no owner function. Which method should I use? Use Deployer if you created the contract, or Majority Holder if you hold >50% of supply β€” these are your available alternatives on EVM chains. --- # Wallet Security & Recovery URL: https://docs.chaindaddy.io/token/wallet-security Category: token # Wallet Security & Recovery Your registration is bound to the wallet that registered it. Chain Daddy **cannot move a registration between wallets** β€” the contract has no admin function for it. This is intentional: - We cannot help you = we cannot be compelled to help anyone else - No subjective dispute resolution = no wrong decisions - Fully trustless = your keys, your registration > **Under the hood**: your registration is a soulbound (non-transferable) NFT. The only way ownership moves is through an announced [deal](/creator-tools/deals). ## Recommended: register from a Safe multisig For important tokens, register from a [Safe](https://app.safe.global) multisig wallet: 1. Create a 2-of-3 or 3-of-5 Safe 2. Use the Safe address when registering 3. If one key is compromised or lost, the remaining signers keep access You get built-in key recovery via signer rotation, no single point of failure, and industry-standard security. ## If you're locked out If you lose access to the wallet that holds your registration: 1. **Let the health score decay.** A registration with no owner activity loses [health](/platform/heartbeat) over time. 2. **Reclaim the expired slot.** Once the registration expires, anyone β€” including you, from a new wallet β€” can reclaim it through the standard flow (see [pricing](/pricing/registration)). 3. **You own it again**, from the new wallet. This is the intended recovery mechanism: activity decay reopens the slot for re-registration, so a lapsed registration can be recovered β€” while a squatter still can't hold a ticker without genuine on-chain activity. ## Best practices - **Hardware wallets** β€” use Ledger or Trezor for registrations you care about. - **Back up recovery phrases** offline: safe deposit box, fireproof safe, or an encrypted backup with someone you trust. - **Separate hot/cold wallets** β€” day-to-day transactions from a hot wallet; valuable registrations and large holdings in cold storage. ## Emergency controls The platform retains a `pause()` control for genuine emergencies (active exploits). Pausing stops all registrations and transfers and preserves state for investigation; unpausing requires multisig approval. Pause cannot transfer ownership or recover an individual registration. ## Summary | Scenario | What to do | |----------|------------| | Lost wallet access | Let health decay, then reclaim the expired slot from a new wallet | | Compromised key | Move assets immediately; if the registration is taken over, reclaim after expiry | | Want recovery built in | Register from a Safe multisig from the start | | Ownership dispute | The chain decides β€” ownership is whoever holds the registered wallet | The absence of admin recovery is a feature, not a limitation.