---
title: "Crypto address validator: detect the blockchain and verify the checksum (EVM, Bitcoin, Solana and more)"
method: GET
path: "/v1/chain/address"
tags: ["deterministic", "no-api-key", "chain", "blockchain", "addresses", "validation"]
---

# Crypto address validator: detect the blockchain and verify the checksum (EVM, Bitcoin, Solana and more)

`GET /v1/chain/address`

## Request

- Base URL: `https://api.duoleads.com`
- URL: `https://api.duoleads.com/v1/chain/address`
- Auth: none declared

Crypto address validator: identify which blockchain an address belongs to and validate its encoding: EVM EIP-55 checksum, Bitcoin base58check and bech32/bech32m with witness version, Solana base58 and on-curve check, Cosmos bech32 with its HRP, Tron, XRP, Litecoin, Dogecoin, Cardano, Polkadot SS58 and Algorand. Returns every chain the address is valid for (ambiguous when several match), the checksummed form for EVM addresses, and the reason a check failed, including unrecognised_format.

**Output (`data`):** valid, matches [{chain, format (string|null), valid, reason (string|null), detail (members depend on the format: hrp, witness_version, encoding for bech32 (cosmos adds bytes); version_byte, purpose for base58check; on_curve for Solana; address_type, header_type, network for Cardano; network_prefix for SS58)}], checksum ({input_form, checksummed, checksum_valid, eip1191_applied} for EVM, else null), ambiguous, reason (present only when the whole input failed: expect_mismatch when expect= was given and no match has that chain, unrecognised_format when no detector recognises the input and no match is listed).

Deterministic: identical input returns identical output, so the response is served with `Cache-Control: private, max-age=31536000, immutable` (the paying client may cache it indefinitely; shared caches must not, because the response is paid).

Price: $0.05 USDC per call (x402, Base). Route contract version 1.0.0. Docs: https://api.duoleads.com/docs#chain-address

## Query parameters

- `address` string, required
- `expect` 'evm' | 'bitcoin' | 'solana' | 'cosmos' | 'tron' | 'xrp' | 'cardano' | 'polkadot' | 'algorand' | 'litecoin' | 'dogecoin'
- `chain_id` integer

## Response `200`

Paid and settled. `data` is route-specific; a route that judges its input returns 200 with `data.valid: false` for a bad value.

- object
  - `ok` unknown, required
  - `route` '/v1/chain/address', required
  - `version` '1.0.0', required
  - `data` object, required: valid, matches [{chain, format (string|null), valid, reason (string|null), detail (members depend on the format: hrp, witness_version, encoding for bech32 (cosmos adds bytes); version_byte, purpose for base58check; on_curve for Solana; address_type, header_type, network for Cardano; network_prefix for SS58)}], checksum ({input_form, checksummed, checksum_valid, eip1191_applied} for EVM, else null), ambiguous, reason (present only when the whole input failed: expect_mismatch when expect= was given and no match has that chain, unrecognised_format when no detector recognises the input and no match is listed).
    - `valid` boolean, required
    - `matches` object[], required
      - `chain` string, required
      - `format` string, nullable, required
      - `valid` boolean, required
      - `reason` string, nullable, required
      - `detail` object, required
        - `hrp` string
        - `witness_version` integer
        - `encoding` string
        - `version_byte` integer
        - `purpose` string
        - `on_curve` boolean
        - `bytes` integer
        - `address_type` string
        - `header_type` integer
        - `network` string
        - `network_prefix` integer
    - `checksum` object, nullable, required
      - `input_form` string, required
      - `checksummed` string, required
      - `checksum_valid` boolean, required
      - `eip1191_applied` boolean, required
    - `ambiguous` boolean, required
    - `reason` string
  - `meta` Meta, required
    - `disclaimer` string, required: Legal short disclaimer, identical on every response.
    - `request_id` string, required: ULID.
    - `computed_at` string, date-time, required: RFC 3339 UTC with milliseconds.
    - `price_usd` string, required: Decimal string, "0.05".
    - `deterministic` boolean, required
    - `sources` object[]: Present only on routes that read a vendored dataset: the exact edition that answered.
      - `id` string, required
      - `version` string, required
      - `published` string, required
      - `attribution` string
      - `licence` string

## Other responses

- `400`: MISSING_PARAM, INVALID_PARAM or UNSUPPORTED_VALUE. Not charged: validation runs before the paywall.
- `402`: Payment required. No valid PAYMENT-SIGNATURE was supplied: read the base64 PAYMENT-REQUIRED header (or this body) for the price ($0.05 = 50000 atomic USDC on eip155:8453), sign an EIP-3009 authorization and retry. Also returned when settlement is declined (PAYMENT_FAILED). Nothing is charged on a 402.
- `404`: NOT_FOUND: unknown path. Not charged.
- `405`: METHOD_NOT_ALLOWED: only GET and HEAD are served. Not charged.
- `413`: INPUT_TOO_LARGE: a parameter exceeded its documented maximum length. Not charged.
- `500`: INTERNAL: a server bug. Not charged.

---

[API](https://skmtc.dev/duoleads/apis/duo-data-utilities-iban-isin-vat-tax-id-barcode-timezone-geo.md) · [All operations](https://skmtc.dev/duoleads/apis/duo-data-utilities-iban-isin-vat-tax-id-barcode-timezone-geo/llms.txt) · [OpenAPI document](https://skmtc.dev/duoleads/apis/duo-data-utilities-iban-isin-vat-tax-id-barcode-timezone-geo/revisions/18790d59615e?raw)
