openapi: 3.0.3
info:
  title: Chain Daddy API
  description: |
    Token name service API for managing crowns across multiple chains.
    One crown (non-transferable NFT) per name per chain.
  version: 2.0.0
  contact:
    url: https://chaindaddy.io

servers:
  - url: https://api.chaindaddy.io
    description: Production

security:
  - ApiKeyHeader: []

tags:
  - name: Search
    description: Token and symbol search endpoints
  - name: Crowns
    description: Crown status, claims, and management
  - name: Social Verification
    description: Social account verification (OAuth and bio-code flows)
  - name: Tokens
    description: Token creation and listing export
  - name: Webhooks
    description: Webhook subscription management (Developer+ tier)
  - name: Health
    description: Service health and status

paths:
  /api/v2/search:
    get:
      tags: [Search]
      summary: Search tokens across all chains
      description: |
        Search for tokens by symbol across all supported chains with real-time lookups
        from multiple data providers.
      operationId: searchTokens
      parameters:
        - name: symbol
          in: query
          required: true
          description: Token symbol to search (1-20 alphanumeric characters)
          schema:
            type: string
            minLength: 1
            maxLength: 20
            example: PEPE
        - name: refresh
          in: query
          required: false
          description: Force cache refresh for real-time data
          schema:
            type: boolean
            default: false
        - name: includeDeployer
          in: query
          required: false
          description: Include deployer wallet information in results
          schema:
            type: boolean
            default: false
        - name: includeOwnership
          in: query
          required: false
          description: Include ownership verification details
          schema:
            type: boolean
            default: false
      responses:
        '200':
          description: Search results
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SearchResponse'
              example:
                success: true
                symbol: PEPE
                filters:
                  chain: all
                  status: all
                sort:
                  field: score
                  order: desc
                results:
                  - chainId: 42161
                    chainName: Arbitrum
                    token:
                      address: "0x6982508145454ce325ddbe47a25d4ec3d2311933"
                      symbol: PEPE
                      name: Pepe
                      decimals: 18
                      marketCap: 1000000
                      volume24h: 50000
                      priceUsd: 0.001
                      liquidity: 200000
                      holders: 5000
                    crown:
                      status: claimed
                      tokenId: 123
                      owner: "0x1234567890abcdef1234567890abcdef12345678"
                      verificationMethod: deployer
                    chainKey: arbitrum
                pagination:
                  total: 5
                  returned: 5
                  hasMore: false
                meta:
                  chainCounts:
                    arbitrum: 2
                    eth: 1
                    solana: 2
                  statusCounts:
                    claimed: 3
                    unclaimed: 2
        '400':
          $ref: '#/components/responses/BadRequest'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v2/token/{symbol}/{chain}:
    get:
      tags: [Search]
      summary: Get token info for a specific symbol and chain
      description: Retrieve detailed token information for a specific symbol on a specific chain.
      operationId: getToken
      parameters:
        - name: symbol
          in: path
          required: true
          description: Token symbol
          schema:
            type: string
            example: PEPE
        - name: chain
          in: path
          required: true
          description: Chain key identifier
          schema:
            type: string
            enum: [eth, arbitrum, arbitrum-sepolia, base, polygon, bnb, avax, gnosis, solana, solana-devnet]
            example: arbitrum
      responses:
        '200':
          description: Token information
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TokenResult'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'

  /registration/unified/{symbol}:
    get:
      tags: [Crowns]
      summary: Get unified crown data for a symbol
      description: |
        Get crown data for a symbol, abstracting whether the crown is confirmed
        on-chain or still pending from token creation.
      operationId: getUnifiedCrown
      parameters:
        - name: symbol
          in: path
          required: true
          description: Token symbol
          schema:
            type: string
            example: DOGE
      responses:
        '200':
          description: Unified crown data
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnifiedCrown'
              example:
                symbol: DOGE
                owner: "0x1234567890abcdef1234567890abcdef12345678"
                tokenId: 123
                chainId: 42161
                status: confirmed
                primaryType: evm
                primaryClaimedAt: null
                isPending: false
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'

  /registration/v2/symbol/{symbol}/all-chains:
    get:
      tags: [Crowns]
      summary: Get all crowns for a symbol across chains
      description: Retrieve all crowns for a symbol across all supported chains, including pending crowns.
      operationId: getCrownAllChains
      parameters:
        - name: symbol
          in: path
          required: true
          description: Token symbol
          schema:
            type: string
            example: DOGE
        - name: excludeEvm
          in: query
          required: false
          description: Exclude crowns owned by this EVM address
          schema:
            type: string
            example: "0x1234567890abcdef1234567890abcdef12345678"
      responses:
        '200':
          description: All crowns for the symbol
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AllChainsCrowns'
              example:
                symbol: DOGE
                crowns:
                  - tokenId: 123
                    owner: "0x1234567890abcdef1234567890abcdef12345678"
                    ownerType: evm
                    chainType: evm
                    isLinked: true
                    isActive: true
                    deploymentCount: 1
                    primaryChainId: 42161
                    isPending: false
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'

  /registration/{id}/roles:
    get:
      tags: [Crowns]
      summary: Get crown roles
      description: Get owner, managers, and maintainers for a crown. The id can be a numeric token ID or a symbol string.
      operationId: getCrownRoles
      parameters:
        - name: id
          in: path
          required: true
          description: Crown token ID (numeric) or symbol (string)
          schema:
            type: string
            example: "123"
      responses:
        '200':
          description: Crown roles
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CrownRoles'
              example:
                tokenId: 123
                owner: "0x1234567890abcdef1234567890abcdef12345678"
                manager: "0xabcdef1234567890abcdef1234567890abcdef12"
                managers:
                  - "0xabcdef1234567890abcdef1234567890abcdef12"
                maintainers: []
                isPending: false
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v2/registry/info:
    get:
      tags: [Crowns]
      summary: Get registry info
      description: Get registry protocol information and the list of supported chains.
      operationId: getRegistryInfo
      responses:
        '200':
          description: Registry information
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  protocol:
                    type: string
                    description: Registry protocol identifier
                  protocolVersion:
                    type: string
                    description: Registry protocol version
                  isOpenCrown:
                    type: boolean
                  supportedChains:
                    type: array
                    items:
                      type: string
                    description: Chains supported by the registry
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v2/claim/verify:
    post:
      tags: [Crowns]
      summary: Verify token ownership for a claim
      description: |
        Verify that a wallet qualifies to claim a crown for an existing token
        (deployer, owner, or other supported verification methods). On success,
        returns a proof hash to pass to the claim endpoint.
      operationId: claimVerify
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [symbol, tokenAddress, walletAddress]
              properties:
                symbol:
                  type: string
                  description: Token symbol to claim
                chainId:
                  type: integer
                  format: int64
                  description: Chain ID for the crown
                tokenAddress:
                  type: string
                  description: Token contract address
                walletAddress:
                  type: string
                  description: Wallet address claiming ownership
                signature:
                  type: string
                  description: Wallet signature proving control
                timestamp:
                  type: integer
                  format: int64
                  description: Signing timestamp (unix seconds, max 5 minutes old)
      responses:
        '200':
          description: Verification result
          content:
            application/json:
              schema:
                type: object
                properties:
                  verified:
                    type: boolean
                  verificationMethod:
                    type: string
                    description: Method that succeeded (e.g. deployer, owner)
                  methodsAttempted:
                    type: array
                    items:
                      type: string
                  proofHash:
                    type: string
                    description: Proof to pass to POST /api/v2/claim
                  expiresAt:
                    type: integer
                    format: int64
                  error:
                    type: string
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v2/claim:
    post:
      tags: [Crowns]
      summary: Claim a crown for an existing token
      description: |
        Build the unsigned crown mint transaction for a verified claim.
        Requires a proof hash from POST /api/v2/claim/verify.
      operationId: claimCrown
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [symbol, tokenAddress, walletAddress]
              properties:
                symbol:
                  type: string
                chainId:
                  type: integer
                  format: int64
                tokenAddress:
                  type: string
                walletAddress:
                  type: string
                proofHash:
                  type: string
                  description: Proof hash from the verify step
      responses:
        '200':
          description: Unsigned crown mint transaction data to sign and submit
        '400':
          $ref: '#/components/responses/BadRequest'
        '409':
          description: Crown already claimed for this symbol on this chain
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v2/registration/claimable:
    get:
      tags: [Crowns]
      summary: List tokens a wallet can claim crowns for
      description: |
        Discover tokens the authenticated wallet qualifies to claim crowns for
        (deployer, mint authority, or update authority). The wallet is taken
        from the JWT session; legacy clients may send an X-Wallet-Address header.
      operationId: getClaimable
      responses:
        '200':
          description: Claimable tokens for the wallet
          content:
            application/json:
              schema:
                type: object
                properties:
                  tokens:
                    type: array
                    items:
                      type: object
                      properties:
                        address:
                          type: string
                        chainId:
                          type: string
                        symbol:
                          type: string
                        name:
                          type: string
                        qualification:
                          type: object
                  total:
                    type: integer
        '400':
          $ref: '#/components/responses/BadRequest'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v2/registration/check-qualify:
    post:
      tags: [Crowns]
      summary: Check claim qualification for a specific token
      description: Check whether a specific wallet qualifies to claim a crown for a specific token.
      operationId: checkQualify
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [wallet, tokenAddress]
              properties:
                wallet:
                  type: string
                tokenAddress:
                  type: string
                chainId:
                  description: Chain ID (number or string)
                symbol:
                  type: string
      responses:
        '200':
          description: Qualification result
          content:
            application/json:
              schema:
                type: object
                properties:
                  eligible:
                    type: boolean
                  reason:
                    type: string
                    description: Why the wallet is not eligible (e.g. already_claimed, not_eligible)
                  qualification:
                    type: object
                  price:
                    type: number
                  currency:
                    type: string
        '400':
          $ref: '#/components/responses/BadRequest'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v2/heartbeat/{symbol}/{chain}:
    get:
      tags: [Crowns]
      summary: Get heartbeat score for a crown
      description: Get the heartbeat score and activity status for a crown by symbol and chain.
      operationId: getHeartbeat
      parameters:
        - name: symbol
          in: path
          required: true
          description: Token symbol
          schema:
            type: string
            example: PEPE
        - name: chain
          in: path
          required: true
          description: Chain key (e.g. `arbitrum`, `base`)
          schema:
            type: string
            example: arbitrum
      responses:
        '200':
          description: Heartbeat score
          content:
            application/json:
              schema:
                type: object
                properties:
                  symbol:
                    type: string
                  chainId:
                    type: integer
                  score:
                    type: number
                    description: Composite heartbeat score (0-100). Weighted sum of timestamp + volume + holder-health.
                  status:
                    type: string
                    description: Heartbeat status derived from the score
                  lastUpdated:
                    type: string
                    format: date-time
                  components:
                    type: object
                    properties:
                      timestamp:
                        type: number
                        description: Timestamp score (0-100, weight 50%)
                      volume:
                        type: number
                        description: Volume score (0-100, weight 30%) — DEX volume blended across 24h + 7d (default 70/30) and capped at 100× pool liquidity, then log-scaled into [$20, $100k]
                      holders:
                        type: number
                        description: Holder Health Score (0-100, weight 20%) — composite of concentration, suspicious-wallet ratio, distribution, and scale
                      confidence:
                        type: number
                        description: Staleness annotation (0-100). 100 when underlying market data is < 1h old, 0 when ≥ 12h, linear in between. NOT part of the on-chain leaf hash.
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v2/registration/{id}/profile:
    put:
      tags: [Crowns]
      summary: Update crown profile
      description: |
        Update the public profile of a crown (name, description, links, media).
        Requires an authenticated session with owner or manager role on the crown.
        Omitted fields keep their existing values; empty strings clear a field.
      operationId: updateCrownProfile
      parameters:
        - name: id
          in: path
          required: true
          description: Crown token ID (numeric) or symbol (string)
          schema:
            type: string
            example: "123"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                description:
                  type: string
                logoUrl:
                  type: string
                bannerUrl:
                  type: string
                website:
                  type: string
                xdotcom:
                  type: string
                telegram:
                  type: string
                discord:
                  type: string
                tags:
                  type: array
                  items:
                    type: string
      responses:
        '200':
          description: Profile updated
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v2/verify/social/{platform}/init:
    post:
      tags: [Social Verification]
      summary: Start social verification
      description: |
        Start a social verification flow for a platform. For OAuth platforms (xdotcom, discord,
        twitch, youtube, github), returns an authorization URL. For bio-code platforms (tiktok,
        telegram, instagram, reddit, pumpfun), returns a verification code to place in your
        profile bio. Requires an authenticated wallet session (JWT).
      operationId: socialVerifyInit
      parameters:
        - name: platform
          in: path
          required: true
          schema:
            type: string
            enum: [xdotcom, discord, twitch, youtube, github, tiktok, telegram, instagram, reddit, pumpfun]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [crownId, walletAddress]
              properties:
                crownId:
                  type: integer
                  description: Crown token ID to verify for
                walletAddress:
                  type: string
                  description: Wallet address (EVM or Solana)
                primaryChain:
                  type: string
                  description: CAIP-2 chain ID (e.g., eip155:42161, solana:mainnet)
                mintAddress:
                  type: string
                  description: Token mint address (PumpFun only)
      responses:
        '200':
          description: |
            OAuth platforms return authUrl and state. Bio-code platforms return code and instructions.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/OAuthInitResponse'
                  - $ref: '#/components/schemas/BioCodeInitResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v2/verify/social/{platform}/callback:
    get:
      tags: [Social Verification]
      summary: OAuth callback
      description: |
        OAuth callback endpoint (xdotcom, discord, twitch, youtube, github only).
        Called by the platform after user authorizes. Returns attestation on success.
      operationId: socialVerifyCallback
      parameters:
        - name: platform
          in: path
          required: true
          schema:
            type: string
            enum: [xdotcom, discord, twitch, youtube, github]
        - name: code
          in: query
          required: true
          schema:
            type: string
        - name: state
          in: query
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Verification successful
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VerificationResult'
        '400':
          $ref: '#/components/responses/BadRequest'

  /api/v2/verify/social/{platform}/check:
    post:
      tags: [Social Verification]
      summary: Check bio-code verification
      description: |
        Check if the verification code is present in the user's profile bio.
        For bio-code platforms (tiktok, telegram, instagram, reddit, pumpfun) only.
        Requires an authenticated wallet session (JWT).
      operationId: socialVerifyCheck
      parameters:
        - name: platform
          in: path
          required: true
          schema:
            type: string
            enum: [tiktok, telegram, instagram, reddit, pumpfun]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [crownId, walletAddress, handle]
              properties:
                crownId:
                  type: integer
                walletAddress:
                  type: string
                handle:
                  type: string
                  description: Username or profile URL to check
                primaryChain:
                  type: string
      responses:
        '200':
          description: Verification result
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VerificationResult'
        '400':
          $ref: '#/components/responses/BadRequest'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v2/factory/create:
    post:
      tags: [Tokens]
      summary: Create a new token
      description: |
        Build unsigned token deployment transaction(s) via the factory contract,
        one per requested chain. The creator signs and submits the returned
        transaction data; the full supply is sent to the creator.
      operationId: factoryCreateToken
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [symbol, chains, creatorAddress]
              properties:
                symbol:
                  type: string
                  description: Token symbol (1-20 alphanumeric)
                chains:
                  type: array
                  description: Target chains (one entry per chain, no duplicates)
                  items:
                    type: object
                    properties:
                      chainId:
                        type: integer
                        format: int64
                creatorAddress:
                  type: string
                  description: Creator wallet address (receives full supply)
                supply:
                  type: string
                  description: Total supply
                decimals:
                  type: integer
                mintable:
                  type: boolean
                burnable:
                  type: boolean
                metadata:
                  type: object
                  description: Optional token metadata (name, description, links)
      responses:
        '200':
          description: Unsigned token deployment transaction data per chain
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v2/tokenlist:
    get:
      tags: [Tokens]
      summary: Get Token List (Uniswap standard)
      description: |
        Returns verified crowns in Uniswap Token List standard format
        for wallet and DEX auto-ingestion.
      operationId: getTokenList
      parameters:
        - name: chainId
          in: query
          required: false
          description: Filter to a single chain ID
          schema:
            type: integer
        - name: symbol
          in: query
          required: false
          description: Filter to specific symbols (repeatable)
          schema:
            type: string
      responses:
        '200':
          description: Token list in Uniswap standard format
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TokenList'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v2/tokenlist/export/{symbol}/{chain}:
    get:
      tags: [Tokens]
      summary: Export token listing data
      description: |
        Export crown/token metadata in platform-specific format for listing applications.
        Requires PRO subscription.
      operationId: exportListing
      parameters:
        - name: symbol
          in: path
          required: true
          description: Token symbol
          schema:
            type: string
            example: PEPE
        - name: chain
          in: path
          required: true
          description: Chain key (e.g. `arbitrum`, `base`, `solana`)
          schema:
            type: string
            example: arbitrum
        - name: format
          in: query
          required: false
          description: Export format
          schema:
            type: string
            enum: [json, cmc, coingecko, dexscreener]
            default: json
        - name: download
          in: query
          required: false
          description: Return as downloadable file
          schema:
            type: boolean
            default: false
      responses:
        '200':
          description: Exported listing data
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListingExport'
              example:
                project_name: PEPE
                symbol: PEPE
                description: "The original meme coin"
                contract_addresses:
                  - chain: Arbitrum
                    address: "0x6982508145454ce325ddbe47a25d4ec3d2311933"
                website: "https://example.com"
                logo: "https://example.com/logo.png"
                total_supply: "420690000000000"
                ownership_proof: "https://chaindaddy.io/$PEPE"
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v2/config/fees:
    get:
      tags: [Tokens]
      summary: Get all current fees
      description: Get all platform fees including claim, creation, link, bundle, and subscription pricing.
      operationId: getFees
      responses:
        '200':
          description: Fee schedule
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Fees'
              example:
                crownFee: 15
                createFee: 5
                whaleMultiplier: 3
                linkPrice: 5
                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: 5
                    price: 90
                    savings: 10
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v2/webhooks:
    get:
      tags: [Webhooks]
      summary: List webhooks
      description: List all webhook subscriptions for the authenticated wallet. Requires the webhooks feature (Developer+ tier).
      operationId: listWebhooks
      responses:
        '200':
          description: Webhook subscriptions
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
    post:
      tags: [Webhooks]
      summary: Create a webhook
      description: |
        Create a webhook subscription. The signing secret is returned once on creation.
        Requires the webhooks feature (Developer+ tier).
      operationId: createWebhook
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [url, events]
              properties:
                url:
                  type: string
                  description: HTTPS endpoint to deliver events to
                events:
                  type: array
                  items:
                    type: string
                  description: Event types to subscribe to (see GET /api/v2/webhooks/events)
                filter:
                  type: object
                  properties:
                    crown_ids:
                      type: array
                      items:
                        type: integer
                    chains:
                      type: array
                      items:
                        type: string
      responses:
        '200':
          description: Created webhook (includes the signing secret, shown only once)
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v2/webhooks/{id}:
    get:
      tags: [Webhooks]
      summary: Get a webhook
      operationId: getWebhook
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Webhook subscription
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
    patch:
      tags: [Webhooks]
      summary: Update a webhook
      description: Update the URL, events, or filter of a webhook subscription.
      operationId: updateWebhook
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                url:
                  type: string
                events:
                  type: array
                  items:
                    type: string
                filter:
                  type: object
      responses:
        '200':
          description: Updated webhook
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
    delete:
      tags: [Webhooks]
      summary: Delete a webhook
      operationId: deleteWebhook
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Webhook deleted
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v2/webhooks/events:
    get:
      tags: [Webhooks]
      summary: List available webhook event types
      description: List the event types that webhooks can subscribe to.
      operationId: getWebhookEvents
      responses:
        '200':
          description: Available event types
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'

  /health:
    get:
      tags: [Health]
      summary: Health check
      description: Returns service health status and configuration.
      operationId: healthCheck
      security: []
      responses:
        '200':
          description: Service is healthy
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HealthResponse'
              example:
                status: ok
                timestamp: "2025-01-15T00:00:00.000Z"
                contractAddress: "0x1234567890abcdef1234567890abcdef12345678"
                network: arbitrum-sepolia
        '503':
          description: Service unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

components:
  securitySchemes:
    ApiKeyHeader:
      type: apiKey
      in: header
      name: X-API-Key
      description: |
        API key for authentication. Get one at https://chaindaddy.io/_api.
        Format: `cd_live_` followed by 64 hex characters.

  responses:
    BadRequest:
      description: Invalid request parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: Bad Request
            message: "Symbol is required and must be 1-20 alphanumeric characters"
            code: INVALID_PARAMS
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: Not Found
            message: "Crown not found"
            code: NOT_FOUND
    Forbidden:
      description: Authentication failed or insufficient permissions
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: Forbidden
            message: "Invalid API key or insufficient tier"
            code: FORBIDDEN
    RateLimited:
      description: Rate limit exceeded
      headers:
        X-RateLimit-Limit:
          schema:
            type: integer
          description: Daily request limit
        X-RateLimit-Remaining:
          schema:
            type: integer
          description: Remaining requests today
        X-RateLimit-Reset:
          schema:
            type: integer
          description: Unix timestamp when limit resets
        Retry-After:
          schema:
            type: integer
          description: Seconds to wait before retrying
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: rate_limit_exceeded
            message: "Too many requests per second"
            retry_after: 1

  schemas:
    Error:
      type: object
      properties:
        error:
          type: string
          description: Error type
        message:
          type: string
          description: Human-readable description
        code:
          type: string
          description: Machine-readable error code
      required: [error, message]

    SearchResponse:
      type: object
      properties:
        success:
          type: boolean
        symbol:
          type: string
        filters:
          type: object
          properties:
            chain:
              type: string
            status:
              type: string
        sort:
          type: object
          properties:
            field:
              type: string
            order:
              type: string
        results:
          type: array
          items:
            $ref: '#/components/schemas/SearchResult'
        pagination:
          $ref: '#/components/schemas/Pagination'
        meta:
          type: object
          properties:
            chainCounts:
              type: object
              additionalProperties:
                type: integer
            statusCounts:
              type: object
              additionalProperties:
                type: integer

    SearchResult:
      type: object
      properties:
        chainId:
          type: integer
          description: Chain ID (e.g., 42161 for Arbitrum)
        chainName:
          type: string
          description: Human-readable chain name
        token:
          $ref: '#/components/schemas/TokenData'
        crown:
          $ref: '#/components/schemas/CrownStatus'
        source:
          type: string
          description: Primary data source
        sources:
          type: array
          items:
            type: string
          description: All contributing data sources
        chainKey:
          type: string
          description: Short chain identifier
        chainIcon:
          type: string
          description: Chain icon URL

    TokenData:
      type: object
      properties:
        address:
          type: string
          description: Token contract address
        symbol:
          type: string
        name:
          type: string
        nameSource:
          type: string
          description: Source of the token name
        decimals:
          type: integer
        logoUrl:
          type: string
        header:
          type: string
          description: Header/banner image URL
        website:
          type: string
        twitter:
          type: string
        telegram:
          type: string
        discord:
          type: string
        marketCap:
          type: number
        fdv:
          type: number
          description: Fully diluted valuation
        volume24h:
          type: number
        priceUsd:
          type: number
        liquidity:
          type: number
        holders:
          type: integer
        priceChange24h:
          type: number
          description: 24-hour price change percentage

    CrownStatus:
      type: object
      properties:
        status:
          type: string
          enum: [available, unclaimed, grace_period, claimed, owned, inactive]
          description: |
            Crown status:
            - `available`: No token exists on this chain
            - `unclaimed`: Token exists but no crown minted
            - `grace_period`: New crown in 30-day grace period
            - `claimed`: Crown exists (owned by someone else)
            - `owned`: Factory-created token (you own it)
            - `inactive`: Crown exists but heartbeat below 60%
        tokenId:
          type: integer
          nullable: true
          description: Crown token ID (null if unclaimed)
        owner:
          type: string
          nullable: true
          description: Crown owner address
        verificationMethod:
          type: string
          nullable: true
          description: Method used to verify ownership

    TokenResult:
      type: object
      properties:
        success:
          type: boolean
        token:
          $ref: '#/components/schemas/TokenData'
        crown:
          $ref: '#/components/schemas/CrownStatus'
        chainId:
          type: integer
        chainName:
          type: string

    UnifiedCrown:
      type: object
      properties:
        symbol:
          type: string
        owner:
          type: string
          nullable: true
        tokenId:
          type: integer
          nullable: true
        chainId:
          type: integer
          nullable: true
        status:
          type: string
          enum: [confirmed, pending, available]
        primaryType:
          type: string
          nullable: true
          enum: [evm, solana]
        primaryClaimedAt:
          type: string
          nullable: true
          format: date-time
        isPending:
          type: boolean
        txHash:
          type: string
          nullable: true
          description: Pending transaction hash (only when isPending is true)

    AllChainsCrowns:
      type: object
      properties:
        symbol:
          type: string
        crowns:
          type: array
          items:
            type: object
            properties:
              tokenId:
                type: integer
                nullable: true
              owner:
                type: string
              ownerType:
                type: string
                enum: [evm, solana]
              chainType:
                type: string
                enum: [evm, solana]
              isLinked:
                type: boolean
              isActive:
                type: boolean
              deploymentCount:
                type: integer
              primaryChainId:
                type: integer
              isPending:
                type: boolean
              txHash:
                type: string
                nullable: true
              status:
                type: string
                nullable: true

    CrownRoles:
      type: object
      properties:
        tokenId:
          type: integer
          nullable: true
        owner:
          type: string
        manager:
          type: string
          nullable: true
        managers:
          type: array
          items:
            type: string
        maintainers:
          type: array
          items:
            type: string
        isPending:
          type: boolean
        txHash:
          type: string
          nullable: true

    ListingExport:
      type: object
      properties:
        project_name:
          type: string
        symbol:
          type: string
        description:
          type: string
        contract_addresses:
          type: array
          items:
            type: object
            properties:
              chain:
                type: string
              address:
                type: string
        website:
          type: string
        twitter:
          type: string
        telegram:
          type: string
        logo:
          type: string
        total_supply:
          type: string
        circulating_supply:
          type: string
        liquidity_locked:
          type: boolean
        liquidity_lock_until:
          type: string
          format: date-time
          nullable: true
        ownership_proof:
          type: string
          description: URL to crown verification page

    TokenList:
      type: object
      description: Uniswap Token List standard format
      properties:
        name:
          type: string
        timestamp:
          type: string
          format: date-time
        version:
          type: object
          properties:
            major:
              type: integer
            minor:
              type: integer
            patch:
              type: integer
        logoURI:
          type: string
        keywords:
          type: array
          items:
            type: string
        tokens:
          type: array
          items:
            type: object
            properties:
              chainId:
                type: integer
              address:
                type: string
              name:
                type: string
              symbol:
                type: string
              decimals:
                type: integer
              logoURI:
                type: string

    Fees:
      type: object
      properties:
        crownFee:
          type: number
          description: Claim fee in USD
        createFee:
          type: number
          description: Token creation fee in USD
        whaleMultiplier:
          type: number
          description: Ethereum mainnet fee multiplier
        linkPrice:
          type: number
          description: Cross-chain link fee in USD
        expiredClaimPrice:
          type: number
          description: Expired ticker reclaim price in USD
        bundles:
          type: object
          properties:
            duo:
              $ref: '#/components/schemas/BundleFee'
            tri:
              $ref: '#/components/schemas/BundleFee'
            quad:
              $ref: '#/components/schemas/BundleFee'
            allChain:
              $ref: '#/components/schemas/BundleFee'
            allChainEth:
              $ref: '#/components/schemas/BundleFee'
        subscriptionTiers:
          type: object
          description: Per-tier monthly and yearly prices in USD
          additionalProperties:
            type: object
            properties:
              monthly:
                type: number
              yearly:
                type: number

    BundleFee:
      type: object
      properties:
        chains:
          type: integer
        price:
          type: number
          description: Bundle price in USD
        savings:
          type: number
          description: Savings vs per-chain pricing in USD

    Pagination:
      type: object
      properties:
        total:
          type: integer
          description: Total number of results
        returned:
          type: integer
          description: Number of results in this response
        hasMore:
          type: boolean
          description: Whether more results are available

    HealthResponse:
      type: object
      properties:
        status:
          type: string
          enum: [ok, degraded, error]
        timestamp:
          type: string
          format: date-time
        contractAddress:
          type: string
          description: Crown contract address
        network:
          type: string
          description: Connected network name

    OAuthInitResponse:
      type: object
      properties:
        success:
          type: boolean
        authUrl:
          type: string
          description: URL to redirect user for OAuth authorization
        state:
          type: string
          description: State parameter for CSRF protection
        expiresAt:
          type: integer
          description: Unix timestamp when the state expires

    BioCodeInitResponse:
      type: object
      properties:
        code:
          type: string
          description: Verification code to place in profile bio
        instructions:
          type: string
          description: Human-readable instructions for the user
        expiresAt:
          type: integer
          description: Unix timestamp when the code expires (10 minutes)

    VerificationResult:
      type: object
      properties:
        success:
          type: boolean
        verified:
          type: boolean
        handle:
          type: string
          description: Verified username or handle
        attestation:
          $ref: '#/components/schemas/SocialAttestation'
        error:
          type: string
          description: Error message if verification failed

    SocialAttestation:
      type: object
      properties:
        platform:
          type: string
          enum: [xdotcom, discord, twitch, youtube, github, tiktok, telegram, instagram, reddit, pumpfun, website]
        handle:
          type: string
          description: Verified handle or username
        walletAddress:
          type: string
        crownId:
          type: integer
        timestamp:
          type: integer
          description: Unix timestamp of verification
        signature:
          type: string
          description: EIP-712 or Ed25519 attestation signature
