openapi: "3.1.0"
info:
  title: NACHO API — Cardano Blockchain Data
  version: "1.0.0"
  description: |
    Cardano blockchain data API covering stake pools, addresses, transactions, blocks,
    governance (DReps), and network statistics. Two networks are supported: mainnet and preprod (testnet).

    **Authentication:** All endpoints require an API key in the `apikey` request header (`napi_xxxx` format).
    Sign up for a free account at https://app.nacho.builders — a free API key is created automatically.
    The free tier includes all REST, explorer, GraphQL, and Ogmios endpoints within rate limits.
    Transaction submission is limited to 10 tx/hour on the free tier; the paid tier removes this limit.

    **Networks:** Pass `mainnet` for production or `preprod` for the Cardano pre-production testnet.

    **Lovelace:** All ADA amounts are returned as lovelace strings (1 ADA = 1,000,000 lovelace).
    Amounts are serialized as strings to avoid JavaScript integer precision loss.
  contact:
    url: https://app.nacho.builders
  license:
    name: Proprietary
    url: https://app.nacho.builders/privacy

servers:
  - url: https://api.nacho.builders
    description: Production

security: []

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: apikey
      description: "API key in the form napi_xxxx. Required for all endpoints. Free accounts get a key automatically at https://app.nacho.builders."

  parameters:
    NetworkParam:
      name: network
      in: path
      required: true
      schema:
        type: string
        enum: [mainnet, preprod]
      description: "Cardano network. Use 'mainnet' for production, 'preprod' for testing with tADA."

    PageParam:
      name: page
      in: query
      schema:
        type: integer
        minimum: 1
        default: 1
      description: "Page number (1-indexed)"

    LimitParam:
      name: limit
      in: query
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 25
      description: "Results per page (max 100)"

    PageSizeParam:
      name: pageSize
      in: query
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 25
      description: "Results per page (max 100)"

  schemas:
    Lovelace:
      type: string
      description: "ADA amount in lovelace (1 ADA = 1,000,000 lovelace), returned as decimal string to avoid integer overflow."
      example: "5000000"

    Error:
      type: object
      properties:
        error:
          type: string
        message:
          type: string
      example:
        error: "Not Found"
        message: "Pool not found"

    PaginationMeta:
      type: object
      properties:
        total:
          type: integer
          description: "Total number of results"
        page:
          type: integer
          description: "Current page (1-indexed)"
        pageSize:
          type: integer
          description: "Results per page"
        hasMore:
          type: boolean
          description: "Whether there are more pages"

    PoolRelay:
      type: object
      properties:
        dns:
          type: string
          nullable: true
        ipv4:
          type: string
          nullable: true
        ipv6:
          type: string
          nullable: true
        port:
          type: integer

    PoolInfo:
      type: object
      required: [poolId, poolIdBech32, liveStake, activeStake, saturation, delegatorCount, pledge, pledgeMet, margin, fixedCost, lifetimeBlocks, epochBlocks, rewardAddress, owners, relays, vrfKeyHash, registeredEpoch]
      properties:
        poolId:
          type: string
          description: "Pool ID in hex format"
          example: "6df91d7497754eb633c1fbeb55e41bf6f531e40db79c79c8a3540e49"
        poolIdBech32:
          type: string
          description: "Pool ID in bech32 format"
          example: "pool1dhugawja82wkmrq0lhd24uyrhm02v7grdhnren9r2qgujsh5kml"
        ticker:
          type: string
          nullable: true
          example: "NACHO"
        name:
          type: string
          nullable: true
        description:
          type: string
          nullable: true
        homepage:
          type: string
          nullable: true
        logo:
          type: string
          nullable: true
        liveStake:
          $ref: "#/components/schemas/Lovelace"
        activeStake:
          $ref: "#/components/schemas/Lovelace"
        saturation:
          type: number
          description: "Pool saturation as a decimal (0.0 to 1.0)"
          example: 0.15
        delegatorCount:
          type: integer
        pledge:
          $ref: "#/components/schemas/Lovelace"
        pledgeMet:
          type: boolean
        margin:
          type: number
          description: "Pool fee as a decimal (0.0 to 1.0). E.g. 0.01 = 1%."
          example: 0.01
        fixedCost:
          $ref: "#/components/schemas/Lovelace"
        lifetimeBlocks:
          type: integer
        epochBlocks:
          type: integer
        lifetimeRewards:
          $ref: "#/components/schemas/Lovelace"
        ros30d:
          type: number
          description: "30-day return on stake (annualized)"
        rewardAddress:
          type: string
        owners:
          type: array
          items:
            type: string
        relays:
          type: array
          items:
            $ref: "#/components/schemas/PoolRelay"
        retiring:
          type: integer
          nullable: true
          description: "Epoch number at which this pool is retiring, if applicable"
        vrfKeyHash:
          type: string
        registeredEpoch:
          type: integer

    Token:
      type: object
      required: [policyId, assetName, assetNameHex, quantity]
      properties:
        policyId:
          type: string
        assetName:
          type: string
        assetNameHex:
          type: string
        quantity:
          $ref: "#/components/schemas/Lovelace"
        fingerprint:
          type: string
          nullable: true

    TransactionInput:
      type: object
      required: [txHash, outputIndex, address, value]
      properties:
        txHash:
          type: string
        outputIndex:
          type: integer
        address:
          type: string
        value:
          $ref: "#/components/schemas/Lovelace"
        tokens:
          type: array
          items:
            $ref: "#/components/schemas/Token"
        datumHash:
          type: string
          nullable: true

    TransactionOutput:
      type: object
      required: [index, address, value, isSpent]
      properties:
        index:
          type: integer
        address:
          type: string
        value:
          $ref: "#/components/schemas/Lovelace"
        tokens:
          type: array
          items:
            $ref: "#/components/schemas/Token"
        datumHash:
          type: string
          nullable: true
        inlineDatum:
          type: string
          nullable: true
        referenceScript:
          type: string
          nullable: true
        isSpent:
          type: boolean
        spentByTxHash:
          type: string
          nullable: true

    Certificate:
      type: object
      required: [type]
      properties:
        type:
          type: string
          enum: [stake_registration, stake_deregistration, delegation, pool_registration, pool_retirement, drep_registration, drep_deregistration, vote_delegation, stake_vote_delegation]
        stakeAddress:
          type: string
          nullable: true
        poolId:
          type: string
          nullable: true
        poolTicker:
          type: string
          nullable: true
        epoch:
          type: integer
          nullable: true

    Withdrawal:
      type: object
      required: [stakeAddress, amount]
      properties:
        stakeAddress:
          type: string
        amount:
          $ref: "#/components/schemas/Lovelace"

    Transaction:
      type: object
      required: [hash, blockNo, blockTime, slotNo, fee, totalOutput, deposit, size, validContract, scriptSize, inputs, outputs]
      properties:
        hash:
          type: string
        blockNo:
          type: integer
        blockHash:
          type: string
          nullable: true
        epochNo:
          type: integer
          nullable: true
        blockTime:
          type: string
          format: date-time
        slotNo:
          type: integer
        fee:
          $ref: "#/components/schemas/Lovelace"
        totalOutput:
          $ref: "#/components/schemas/Lovelace"
        deposit:
          $ref: "#/components/schemas/Lovelace"
        size:
          type: integer
        validContract:
          type: boolean
        scriptSize:
          type: integer
        invalidBefore:
          type: integer
          nullable: true
        invalidHereafter:
          type: integer
          nullable: true
        inputs:
          type: array
          items:
            $ref: "#/components/schemas/TransactionInput"
        outputs:
          type: array
          items:
            $ref: "#/components/schemas/TransactionOutput"
        certificates:
          type: array
          items:
            $ref: "#/components/schemas/Certificate"
        withdrawals:
          type: array
          items:
            $ref: "#/components/schemas/Withdrawal"
        mints:
          type: array
          items:
            type: object
            properties:
              policyId:
                type: string
              assetName:
                type: string
              assetNameHex:
                type: string
              quantity:
                $ref: "#/components/schemas/Lovelace"
        collateral:
          type: array
          items:
            $ref: "#/components/schemas/TransactionInput"
        metadata:
          type: array
          items:
            type: object
            properties:
              key:
                type: string
              json:
                description: "Arbitrary metadata value"

    Block:
      type: object
      required: [blockNo, hash, slotNo, epochNo, epochSlotNo, time, txCount, size, totalOutput, totalFees]
      properties:
        blockNo:
          type: integer
        hash:
          type: string
        slotNo:
          type: integer
        epochNo:
          type: integer
        epochSlotNo:
          type: integer
        time:
          type: string
          format: date-time
        txCount:
          type: integer
        size:
          type: integer
        poolId:
          type: string
          nullable: true
        poolTicker:
          type: string
          nullable: true
        poolName:
          type: string
          nullable: true
        totalOutput:
          $ref: "#/components/schemas/Lovelace"
        totalFees:
          $ref: "#/components/schemas/Lovelace"

    BlockSummary:
      type: object
      required: [blockNo, hash, slotNo, time, txCount]
      properties:
        blockNo:
          type: integer
        hash:
          type: string
        slotNo:
          type: integer
        time:
          type: string
          format: date-time
        txCount:
          type: integer
        size:
          type: integer
          nullable: true
        poolTicker:
          type: string
          nullable: true
        totalFees:
          $ref: "#/components/schemas/Lovelace"
        totalOutput:
          $ref: "#/components/schemas/Lovelace"

    AddressInfo:
      type: object
      required: [address, type, balance, tokenCount, utxoCount]
      properties:
        address:
          type: string
        type:
          type: string
          enum: [base, enterprise, pointer, reward, byron, script]
        stakeAddress:
          type: string
          nullable: true
        balance:
          $ref: "#/components/schemas/Lovelace"
        tokenCount:
          type: integer
        utxoCount:
          type: integer
        firstSeen:
          type: string
          format: date-time
          nullable: true
        lastSeen:
          type: string
          format: date-time
          nullable: true

    AddressUtxo:
      type: object
      required: [txHash, outputIndex, value, tokens, blockNo, blockTime]
      properties:
        txHash:
          type: string
        outputIndex:
          type: integer
        value:
          $ref: "#/components/schemas/Lovelace"
        tokens:
          type: array
          items:
            $ref: "#/components/schemas/Token"
        blockNo:
          type: integer
        blockTime:
          type: string
          format: date-time
        datumHash:
          type: string
          nullable: true

    NetworkStats:
      type: object
      required: [blockHeight, slotNo, epochNo, epochProgress, totalTransactions, circulatingSupply, treasury, reserves, activeStake, activePools, activeDelegators]
      properties:
        blockHeight:
          type: integer
        slotNo:
          type: integer
        epochNo:
          type: integer
        epochProgress:
          type: number
          description: "Epoch completion percentage (0-100)"
        totalTransactions:
          type: integer
        circulatingSupply:
          $ref: "#/components/schemas/Lovelace"
        treasury:
          $ref: "#/components/schemas/Lovelace"
        reserves:
          $ref: "#/components/schemas/Lovelace"
        activeStake:
          $ref: "#/components/schemas/Lovelace"
        activePools:
          type: integer
        activeDelegators:
          type: integer

    DRep:
      type: object
      required: [drepIdBech32, type, isActive]
      properties:
        drepIdBech32:
          type: string
        type:
          type: string
          enum: [registered, abstain, noConfidence]
        name:
          type: string
          nullable: true
        givenName:
          type: string
          nullable: true
        isActive:
          type: boolean
        votingPower:
          $ref: "#/components/schemas/Lovelace"
        delegatorCount:
          type: integer
        votesCount:
          type: integer

paths:
  /api/public/pool-info:
    get:
      operationId: getPoolInfo
      summary: Get stake pool information
      description: Returns metadata and statistics for any Cardano stake pool by pool ID.
      tags: [pool]
      parameters:
        - name: poolId
          in: query
          required: true
          schema:
            type: string
          description: "Pool ID in bech32 format: pool1... (mainnet) or pool_test1... (preprod)"
          example: "pool1dhugawja82wkmrq0lhd24uyrhm02v7grdhnren9r2qgujsh5kml"
      responses:
        "200":
          description: Pool information
          content:
            application/json:
              schema:
                type: object
                properties:
                  poolId:
                    type: string
                  poolIdBech32:
                    type: string
                  ticker:
                    type: string
                    nullable: true
                  name:
                    type: string
                    nullable: true
                  description:
                    type: string
                    nullable: true
                  margin:
                    type: number
                    description: "Fee as decimal 0-1 (e.g. 0.01 = 1%)"
                  fixedCost:
                    $ref: "#/components/schemas/Lovelace"
                  pledge:
                    $ref: "#/components/schemas/Lovelace"
                  activeStake:
                    $ref: "#/components/schemas/Lovelace"
                  delegatorCount:
                    type: integer
                  blocksLifetime:
                    type: integer
                  blocksEpoch:
                    type: integer
                  relays:
                    type: array
                    items:
                      $ref: "#/components/schemas/PoolRelay"
        "404":
          description: Pool not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /api/public/pool-status:
    get:
      operationId: getPoolStatus
      summary: Get NACHO pool live status
      description: Returns live statistics for the NACHO stake pool including active stake, block count, and relay health.
      tags: [pool]
      responses:
        "200":
          description: NACHO pool status
          content:
            application/json:
              schema:
                type: object
                properties:
                  activeStake:
                    type: integer
                    description: "Active stake in ADA (integer)"
                  delegators:
                    type: integer
                  blocksMinted:
                    type: integer
                  lifetimeBlocks:
                    type: integer
                  margin:
                    type: number
                  pledge:
                    type: integer
                    description: "Pledge in ADA (integer)"
                  relays:
                    type: array
                    items:
                      type: object
                      properties:
                        name:
                          type: string
                        healthy:
                          type: boolean
                  network:
                    type: object
                    properties:
                      tip:
                        type: object
                        properties:
                          slot:
                            type: integer
                          epoch:
                            type: integer
                          block:
                            type: integer

  /v2/explorer/{network}/pool/{poolId}:
    get:
      operationId: getPoolDetail
      summary: Get full pool details from explorer
      description: Returns complete pool information including relays, owners, and historical statistics.
      tags: [pool]
      parameters:
        - $ref: "#/components/parameters/NetworkParam"
        - name: poolId
          in: path
          required: true
          schema:
            type: string
          description: "Pool ID in bech32 format (pool1...)"
      responses:
        "200":
          description: Full pool detail
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PoolInfo"
        "404":
          description: Pool not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /api/public/stake-account:
    get:
      operationId: getStakeAccount
      summary: Get stake account information
      description: Returns delegation status, rewards balance, and total stake for a Cardano stake address.
      tags: [address]
      parameters:
        - name: address
          in: query
          required: true
          schema:
            type: string
          description: "Stake address in bech32 format: stake1... (mainnet) or stake_test1... (preprod)"
          example: "stake1ux3g2c9dx2nhhehyrezyxpkstartcqmu9hk63qj4zz7z4hgas4enh"
      responses:
        "200":
          description: Stake account information
          content:
            application/json:
              schema:
                type: object
                properties:
                  registered:
                    type: boolean
                  delegatedPoolId:
                    type: string
                    nullable: true
                  rewardsBalance:
                    $ref: "#/components/schemas/Lovelace"
                  totalStake:
                    $ref: "#/components/schemas/Lovelace"
        "400":
          description: Invalid address format
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /v2/explorer/{network}/address/{addr}:
    get:
      operationId: getAddress
      summary: Get address information
      description: Returns balance, token count, UTxO count, and activity timestamps for a Cardano address.
      tags: [address]
      parameters:
        - $ref: "#/components/parameters/NetworkParam"
        - name: addr
          in: path
          required: true
          schema:
            type: string
          description: "Cardano address (addr1..., stake1..., etc.)"
      responses:
        "200":
          description: Address information
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AddressInfo"
        "404":
          description: Address not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /v2/explorer/{network}/address/{addr}/utxos:
    get:
      operationId: getAddressUtxos
      summary: Get address UTxOs
      description: Returns paginated list of unspent transaction outputs (UTxOs) for a Cardano address.
      tags: [address]
      parameters:
        - $ref: "#/components/parameters/NetworkParam"
        - name: addr
          in: path
          required: true
          schema:
            type: string
        - $ref: "#/components/parameters/PageParam"
        - $ref: "#/components/parameters/LimitParam"
      responses:
        "200":
          description: Paginated UTxO list
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/PaginationMeta"
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: "#/components/schemas/AddressUtxo"

  /api/public/tx-status:
    get:
      operationId: getTxStatus
      summary: Get transaction confirmation status
      description: Check whether a transaction has been confirmed on-chain. Poll this after submitting a transaction.
      tags: [transaction]
      parameters:
        - name: txHash
          in: query
          required: true
          schema:
            type: string
            pattern: "^[a-f0-9]{64}$"
          description: "Transaction hash (64 hex characters)"
          example: "3a9f6d3babc13a2c8f4d7e1b9c0a5e2f6d8b4c1a7e3f9d2b5c8a0e4f7b1d3c6"
      responses:
        "200":
          description: Transaction status
          content:
            application/json:
              schema:
                type: object
                required: [found]
                properties:
                  found:
                    type: boolean
                  blockNo:
                    type: integer
                    nullable: true
                  blockTime:
                    type: string
                    format: date-time
                    nullable: true
                  confirmations:
                    type: integer
                    nullable: true
                  fee:
                    $ref: "#/components/schemas/Lovelace"

  /v2/explorer/{network}/tx/{hash}:
    get:
      operationId: getTransaction
      summary: Get full transaction details
      description: Returns complete transaction data including all inputs, outputs, tokens, certificates, withdrawals, and metadata.
      tags: [transaction]
      parameters:
        - $ref: "#/components/parameters/NetworkParam"
        - name: hash
          in: path
          required: true
          schema:
            type: string
          description: "Transaction hash (64 hex characters)"
      responses:
        "200":
          description: Full transaction
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Transaction"
        "404":
          description: Transaction not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /v2/explorer/{network}/blocks:
    get:
      operationId: getBlocks
      summary: Get recent blocks
      description: Returns a paginated list of recent blocks with summary statistics.
      tags: [block]
      parameters:
        - $ref: "#/components/parameters/NetworkParam"
        - $ref: "#/components/parameters/PageParam"
        - $ref: "#/components/parameters/LimitParam"
      responses:
        "200":
          description: Paginated blocks
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/PaginationMeta"
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: "#/components/schemas/BlockSummary"

  /v2/explorer/{network}/block/{id}:
    get:
      operationId: getBlock
      summary: Get block by number or hash
      description: Returns full block details. The id parameter accepts either a block number (integer) or a 64-character block hash.
      tags: [block]
      parameters:
        - $ref: "#/components/parameters/NetworkParam"
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: "Block number (integer) or block hash (64 hex characters)"
      responses:
        "200":
          description: Block details
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Block"
        "404":
          description: Block not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /v2/explorer/{network}/stats:
    get:
      operationId: getNetworkStats
      summary: Get network statistics
      description: Returns current Cardano network statistics including epoch progress, supply metrics, and active stake.
      tags: [network]
      parameters:
        - $ref: "#/components/parameters/NetworkParam"
      responses:
        "200":
          description: Network statistics
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NetworkStats"

  /api/public/price:
    get:
      operationId: getPrice
      summary: Get ADA/USD price
      description: Returns the current ADA/USD exchange rate. Cached for 60 seconds.
      tags: [network]
      responses:
        "200":
          description: Current ADA price
          content:
            application/json:
              schema:
                type: object
                required: [ada_usd, updated_at]
                properties:
                  ada_usd:
                    type: number
                    description: "ADA price in USD"
                    example: 0.38
                  updated_at:
                    type: string
                    format: date-time

  /api/public/protocol-parameters:
    get:
      operationId: getProtocolParameters
      summary: Get Cardano protocol parameters
      description: Returns the current Cardano network protocol parameters in Ogmios format. Useful for transaction building. Cached for 1 hour.
      tags: [network]
      responses:
        "200":
          description: Protocol parameters (Ogmios format)
          content:
            application/json:
              schema:
                type: object
                description: "Raw Ogmios protocol parameters object. Contains minFeeCoefficient, minFeeConstant, maxBlockBodySize, maxTransactionSize, stakeKeyDeposit, poolDeposit, and all other Cardano network parameters."
                additionalProperties: true

  /v2/explorer/{network}/dreps:
    get:
      operationId: getDReps
      summary: Get governance DReps
      description: Returns a paginated list of Cardano governance Delegated Representatives (DReps).
      tags: [governance]
      parameters:
        - $ref: "#/components/parameters/NetworkParam"
        - $ref: "#/components/parameters/PageParam"
        - $ref: "#/components/parameters/PageSizeParam"
        - name: activeOnly
          in: query
          schema:
            type: boolean
            default: false
          description: "If true, return only active DReps"
      responses:
        "200":
          description: Paginated DRep list
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/PaginationMeta"
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: "#/components/schemas/DRep"

  /v1/graphql:
    post:
      operationId: graphqlQuery
      summary: Run a GraphQL query
      description: |
        Execute a GraphQL query over the full Cardano DB-Sync schema via Hasura.
        Supports all indexed blockchain data including blocks, transactions, addresses, pools, and governance.
        Available on all tiers. Rate-limited per tier (100 req/s free, 500 req/s paid).
      tags: [authenticated]
      security:
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [query]
              properties:
                query:
                  type: string
                  description: "GraphQL query string"
                  example: "{ cardano { tip { slotNo epochNo } } }"
                variables:
                  type: object
                  description: "GraphQL variables"
                  additionalProperties: true
      responses:
        "200":
          description: GraphQL response
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    description: "Query result data"
                  errors:
                    type: array
                    items:
                      type: object
                      properties:
                        message:
                          type: string
        "401":
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
