Skip to content
kascov
explore tokens playground API guide

the covenant explorer for Kaspa L1

Kaspa coins just learned to carry rules.

like a token explorer, but for coins that carry their own rules: kascov watches every smart coin on the Kaspa testnet — born, moving, retiring — and saves the history the network deletes after 3 days.

the last 24 hours

how to read this

  1. Borna coin gets an identity and rules
  2. Movesit changes hands or state — identity travels with it
  3. Retiredits story ends, recorded forever here

new here? take the 30-second tour →

wait — what is a smart coin, really?

Normal KAS is like cash: interchangeable bills with no memory. Spend some, and brand-new bills come out the other side — nothing connects them to the old ones.

Since the Toccata upgrade, a transaction can take ordinary KAS from any wallet and wrap it into something new: an output stamped with a permanent identity (a covenant id) and, usually, a program. That moment is a birth — ordinary money becoming a named coin that carries rules. The id is a fingerprint of that exact moment, so it can't be faked.

When its owner spends it and the transaction stamps the same identity onto new outputs, that's a move: same coin, new state — maybe a new owner, maybe split into pieces, maybe merged back. The name travels with it, however many hands it passes through.

And when it's spent without passing the identity on, the KAS inside flows back out as ordinary cash and the identity ends — retired. The network forgets the whole story within days. kascov doesn't.

Why bother? Because the program travels with the identity: a coin can refuse to move more than 10% a week, demand two signatures, wait for a delivery confirmation, or verify a zero-knowledge proof — the coin itself enforces its rules, no middleman.

the latest stories

    open the explorer →

    the galaxy

    every app at once, live — one zoomable map of the whole network. each dot is a smart coin, each link a shared transaction.

    script decoder

    paste any Kaspa script, read its post-Toccata opcodes — covenant ops highlighted. runs in your browser, nothing leaves the page.

    JSON API

    everything kascov sees, as plain JSON with CORS on. build a bot, a chart, a better explorer.

    make a smart coin

    build a covenant without writing code and deploy it on testnet in one click — it reveals itself here, named forever.

    built with covenants

    what builders are shipping on Kaspa’s smart coins — real projects, their contracts verifiable right here.

    new here? how to read this →

    your coins — the ones you starred

    life on the testnet

    record holders

    what’s running here

    apps · coins that move together

    a single transaction moving several smart coins is a multi-contract flow — a covenant app.

    based-app activity · by namespace

    smart coins whose transactions carry an app payload, grouped by its namespace — the first per-namespace view of Kaspa's based apps.

    inscriptions · what’s being written on-chain

    the JSON payloads, decoded straight from the bytes — each covenant’s protocol, operation and token ticker, exactly as written. no registry, no labels we invented.

    the galaxy · the whole network

    every app at once — each dot is a smart coin, each link a shared transaction. scroll to zoom, drag to pan, click a dot to open the coin.pinch to zoom · tap a dot

    how long do smart coins live?

    the lifespan of every retired coin — from birth to burn.

    analytics · the network at a glance

    charts

    the same feeds behind this page, drawn as charts — births against retirements over the whole history, the population by contract type, and how long coins survive.

    births vs retirements over time

    survival curve

    coins by contract type

    recent reorgs

    latest stories

      all smart coins

      📄 read a script ✎ write a covenant 🛫 check a transaction

      read a script

      paste any Kaspa script as hex and read it as opcodes — including the post-Toccata set: transaction introspection (KIP-17), covenant ops (KIP-20), zk verification (KIP-16). recognizing, disassembling & linting run in your browser; simulate, verify-proof & compile call the kascov node. recognized contracts can be re-made with your own parameters.

      try an example:
      what the colors mean
      • push data pushed onto the stack
      • standard the classic script opcodes (checks, math, stack)
      • introspection KIP-17 — the script reads its own transaction
      • covenant KIP-20 — smart-coin identity & state rules
      • zk KIP-16 — zero-knowledge proof verification
      • unknown not in the post-Toccata opcode table
      📄 read a script ✎ write a covenant 🛫 check a transaction

      the lab

      Make your own smart coin.

      Deploy a real covenant on Kaspa testnet-10 and watch it run itself — no Solidity, no VM bytecode, just Kaspa script. One command births a contract and spends it under its own rules, and it reveals itself right here on kascov.

      cargo run -p kascov-lab -- escrow-demo click to copy

      build one without writing code

      Pick a covenant, fill in the parties, amounts and timelocks in plain terms, and kascov assembles byte-perfect Kaspa script in your browser — the exact bytes the silverc compiler emits, live as you type. Then deploy it in one click on testnet-10 — no local toolchain — or download a ready-to-run deploy.sh.

      write & compile SilverScript

      Write a covenant in SilverScript and compile it to real Kaspa script right here — powered by the actual silverc compiler. Edit the source, set the constructor args, and get deployable hex.

      start from a template:

      the whole loop

      1. 1
        Decoderead any covenant on-chain as SilverScript — its rules, its parameters, labeled.
      2. 2
        Editchange the constructor arguments in your browser; verified byte-for-byte on every keystroke.
      3. 3
        Deployone command births it on testnet — a real coin, its rules committed as a P2SH state.
      4. 4
        Spendsatisfy the contract's own rules; the transaction reveals the program on-chain.
      5. 5
        Revealedkascov names the coin its contract, forever — for everyone, hash-verified.
      ⌘ prefer the command line? run the whole loop from the CLI

      start here — one command

      You need the repo and a faucet-funded key. Then a single command runs the entire loop and prints a kascov link so you can watch it happen.

      escrow-demo

      An escrow is deployed with you as the arbiter, then you settle it — the contract itself forces the payout to the buyer. A real dispute resolution, on-chain.

      cargo run -p kascov-lab -- escrow-demo

      contract-demo

      A Mecenas is deployed reclaimable by your key, then reclaimed — it reveals itself as SilverScript · Mecenas on kascov, with every argument labeled.

      cargo run -p kascov-lab -- contract-demo

      examples

      Prints every copy-paste recipe — setup, the demos, and the manual decode → deploy → spend flow with your own parameters. Needs no key or network.

      cargo run -p kascov-lab -- examples

      the contracts you can make

      Three canonical SilverScript covenants ship with kascov. Open one in the builder above, put your own keys and amounts in, and it compiles to deployable hex in your browser.

      do it yourself, step by step

      01

      Get a key, fund it

      Make a throwaway testnet key and fund the address it prints at the faucet.

      cargo run -p kascov-lab -- keygen
      02

      Generate your contract

      In the builder above, pick Mecenas / Escrow / LastWill, edit the fields (use the pubkey and blake2b that keygen printed), and copy the compiled hex — or download the ready-to-run deploy.sh.

      03

      Deploy it

      Births the coin as a hidden P2SH commitment. It appears on kascov within a minute.

      cargo run -p kascov-lab -- deploy --program-hex <hex> --value 1000000000
      04

      Reveal it — spend it

      Satisfy the contract to reveal its program on-chain, so kascov names it your contract forever.

      cargo run -p kascov-lab -- spend --program-hex <hex> --entrypoint reclaim

      Escrow instead? settle-escrow --program-hex <hex> --release-to buyer

      Full walkthrough in docs/Covenant Lab.md. Every command has --help.

      📄 read a script ✎ write a covenant 🛫 check a transaction

      will this transaction pass?

      paste a transaction as JSON (the SDK / RPC shape) and find out before you broadcast: every input’s compute budget checked against the classic “script units exceeded” trap, masses measured against the block limit, an honest fee estimate — and for inputs that carry both their witness and their UTXO’s script, a real run through Kaspa’s script engine.

      try an example:

      your transaction goes into the preflight call and nowhere else — the worker computes the verdict and forgets it (no-store). nothing is broadcast, nothing is kept.

      reference

      The kascov API.

      Every covenant on Kaspa, indexed live and kept long after nodes prune it — as plain JSON. No keys, no rate cards, CORS open to everyone. Build a bot, a chart, a better explorer.

      Start
      Overview Networks Client libraries
      Feeds
      Live feed Full snapshot Event feed Event stream Price Atom feed
      Coins
      One coin Coins by id Transaction Address
      Analytics
      24h digest Templates Activity Apps Galaxy Based-app lanes One lane Inscriptions Tokens One token Lifespans Reorgs Consistency
      Find
      Search Spend debugger
      Share
      Share cards
      Write
      Simulate a spend Preflight a tx Compile Publish source Verified source Webhooks One-click deploy

      Overview

      The indexer follows Kaspa's chain tip live, classifies every covenant event (born / moved / retired), decodes spend-time script reveals, and serves the whole index as static JSON from a CDN. Reads are cheap and cacheable — poll as often as you like.

      Base URLhttps://kascov.io
      FormatJSON · application/json
      AuthNone — public
      CORSCORS enabled incl. preflight — call any route, GET or POST, straight from a browser page
      CachingCDN s-maxage + stale-while-revalidate; responses carry tip_daa + tip_at_ms so you always know how fresh they are

      Networks

      Every path takes a network segment. Swap testnet-10 for mainnet anywhere. Mainnet's first smart coins arrived July 2, 2026; their full history starts there.

      Client libraries

      Two tiny zero-dependency clients ship in the repo — clients/js/kascov.mjs (Node 18+ and browsers) and clients/py/kascov.py. Each is a single file wrapping the endpoints below. One sharp edge: for the event stream, construct the client with the worker origin as its base — new Kascov('testnet-10', 'https://kascov-worker-12056584181.europe-west4.run.app') — because the default kascov.io base sits behind a CDN that buffers SSE. Everything else works fine through the default.

      GET/data/{network}-live.json

      The small, fast feed — network stats, the chain tip, and the ~150 newest life events. This is the one to poll (a few KB, refreshes every few seconds).

      Request
      curl -s https://kascov.io/data/testnet-10-live.json
      Response · 200
      {
        "network": "testnet-10",
        "stats": { "covenants": 192852, "active": 14190, "burned": 178662,
                   "events": 876383, "live_value": 307204412838957,
                   "last_activity_daa": 513875477 },
        "tip_daa": 513875491,
        "tip_at_ms": 1783746272524,
        "processed_daa": 513875490,
        "generated_at_ms": 1783746272524,
        "recent_events": [
          { "covenant_id": "2ab7dcd2…35115",
            "kind": "transition", "txid": "f9bbca…f2ba",
            "accepting_daa": 513875477, "seq": 5, "tx_index": 50 }
        ]
      }
      FieldTypeNotes
      stats.covenantsintdistinct smart coins ever seen
      stats.activeintcoins with a live UTXO right now
      tip_daa · processed_daaintchain tip vs. last block applied — the gap is the honest sync lag
      recent_events[].kindstringgenesis · transition · burn
      recent_events[].seqintthe event's 0-based position in its own coin's timeline
      recent_events[].tx_indexint?0-based index in the accepting block's accepted-tx list (consensus acceptance order); omitted on rows indexed before capture
      GET/data/{network}.json?after_daa=&after_id=&limit=

      The grid — stats plus one summary row per covenant, ordered by last activity, newest first. A bare request is a first page capped at 20,000 rows; when more remain the response carries next_after_daa + next_after_id — pass them back to keep walking.

      QueryTypeNotes
      after_daaintexclusive cursor — resume below this last_activity_daa
      after_idhextie-breaker within the boundary DAA (the last row's covenant_id)
      limitintpage size, default 5000, capped at 20000; invalid values degrade to the bare first page
      Response · 200
      {
        "stats": { … },
        "covenants": [
          { "covenant_id": "e55322e7…60697", "name": "sleepy-olive-crane",
            "status": "active", "born_value": 460831908462, "live_value": 230415954231,
            "event_count": 2, "live_utxos": 1, "lineage_complete": true,
            "genesis_daa": 513863444, "last_activity_daa": 513870198,
            "template": "p2pk state" }
        ],
        "next_after_daa": 513870178,
        "next_after_id": "a348a978…f3a29"
      }
      FieldTypeNotes
      namestringthe coin's friendly name — derived deterministically from the id, the same name everywhere kascov shows it
      statusstringactive or burned
      born_value · live_valueintsompi held at birth / right now
      last_activity_daaintthe DAA of the coin's newest life event — the sort key of this feed
      templatestring?recognized contract, or a state shape like p2sh commitment
      next_after_daa · next_after_idint? · hex?present only when another page exists — feed them to ?after_daa=&after_id=
      GET/data/{network}/events?after_daa=&after_seq=&limit=

      The chain-wide event feed — every life event on the network, oldest first, in the canonical deterministic order: accepting_daa, then tx_index, then txid. Every event-shaped surface (this feed, the live feed, the stream, webhooks) serves the same object, so you write one parser. Walk history from any point by passing the response's cursor pair back.

      QueryTypeNotes
      after_daaintresume at this DAA — 0 starts from the beginning of history
      after_seqinthow many events of that boundary DAA were already taken — pass the returned pair straight back; a stable cursor because order inside a DAA is total and history only appends at higher DAAs
      limitintpage size, clamped server-side
      Response · 200
      {
        "events": [
          { "covenant_id": "2ab7dcd2…35115", "seq": 5, "kind": "transition",
            "txid": "f9bbca…f2ba", "accepting_daa": 513875477,
            "accepting_block": "58ef8d…c44f0", "tx_index": 50,
            "payload_len": 137 }
        ],
        "next_after_daa": 513875477,
        "next_after_seq": 12
      }
      FieldTypeNotes
      events[].seqint0-based position in the event's own coin's timeline
      events[].tx_indexint?consensus acceptance order within the accepting block; omitted (not null) on rows indexed before capture
      events[].payload_lenint?byte length of the transaction's v1 payload; omitted when it carried none
      next_after_daa · next_after_seqintthe resume cursor — feed to ?after_daa=&after_seq= to keep walking
      GET/data/{network}/stream?covenant=

      Server-sent events — one JSON message the moment the indexer sees each life event. Connect to the worker origin directly: the kascov.io CDN (Firebase) buffers streams, so an SSE connection opened there never delivers. The stream opens with a : connected hello and sends a : ka keep-alive comment every 25s. Treat messages as hints and confirm through the polled feeds.

      QueryTypeNotes
      covenanthexoptional — exactly 64 hex characters narrows the stream to one coin's events; anything else is a 400, never a silent wildcard
      Request — note the worker origin
      curl -N 'https://kascov-worker-12056584181.europe-west4.run.app/data/testnet-10/stream'
      The stream
      : connected
      
      data: {"covenant_id":"2ab7dcd2…","kind":"transition",
             "txid":"f9bbca…","accepting_daa":513875477,
             "tx_index":50}
      FieldTypeNotes
      kindstringgenesis · transition · burn — plus reorg notices {"kind":"reorg","rolled_back":N} (filtered streams never see them)
      GET/data/price.json

      The KAS→USD rate behind the site's ≈ $ hints — one tiny object, no network segment. Answers 503 while no fresh rate is available; treat any non-200 as "no price right now".

      Request
      curl -s https://kascov.io/data/price.json
      Response · 200
      {
        "kas_usd": 0.1132,
        "updated_at_ms": 1751799000000,
        "source": "median of spot venues"
      }
      FieldTypeNotes
      kas_usdnumberUS dollars per 1 KAS
      updated_at_msintwhen the rate was last refreshed (unix ms)
      sourcestringwhere the rate came from
      GET/feed.xml

      What’s new, as an Atom feed — the same milestones as the changelog, one entry each with a stable id, newest first. Lives on the site root next to /sitemap.xml (no network segment), cached for an hour. Point any feed reader at it. Served by newer workers; older deploys answer 404.

      Request
      curl -s https://kascov.io/feed.xml
      GET/data/{network}/c/{covenant_id}.json

      One coin's whole life — the complete event timeline and every UTXO with decoded scripts, recognized templates, and spend-time reveals. 404 if the id is unknown.

      Response · 200
      {
        "covenant_id": "a348a978…f3a29", "name": "brave-jade-osprey",
        "status": "burned", "event_count": 3, "lineage_complete": true,
        "genesis_txid": "82aabd…25dcb", "genesis_daa": 513863030,
        "last_activity_daa": 513870178,
        "events": [
          { "seq": 0, "kind": "genesis", "txid": "82aabd…25dcb",
            "accepting_daa": 513863030, "accepting_block": "bc5aaf…8daac",
            "tx_index": 56 },
          { "seq": 2, "kind": "burn", "txid": "8e7040…3e2bb",
            "accepting_daa": 513870178, "accepting_block": "3d1c00…45e7e2",
            "tx_index": 18 }
        ],
        "events_truncated": false,
        "utxos": [
          { "outpoint": "82aabd…25dcb:0", "value": 230415954231, "live": false,
            "template": "p2sh commitment",
            "state_fields": [ { "name": "program_hash", "value": "d9a9e982…f475d17" } ],
            "revealed_template": "SilverScript · Escrow",
            "revealed_fields": [ { "name": "arbiter_hash", "value": "f4445661…" } ] }
        ]
      }
      FieldTypeNotes
      namestringthe coin's friendly name — deterministic from the id
      lineage_completeboolfalse means kascov started watching mid-life; earlier history is honestly missing
      events_truncatedbooltrue when the timeline was capped — event_count still counts everything
      events[].payload · payload_lenhex? · int?the tx's v1 payload — inlined as hex when ≤ 512 bytes, collapsed to its byte length above that
      events[].with_covenantsarray?up to 4 other coins the same transaction moved (multi-contract flows)
      utxos[].revealed_templatestring?the contract a P2SH state actually ran, decoded and hash-verified when it was spent
      …_fields[]array{ name, value } — labeled constructor arguments
      holders[]arrayup to 100 p2pk-state owners: { pubkey, controls_now, states_seen, first_seen_daa, last_seen_daa }
      utxos[].zk_systemstring?on zk-using states, a size heuristic over the proof push: risc0 (≥1024 B) or groth16 (128–256 B)
      utxos[].revealed_zk_systemstring?the same heuristic applied to the program revealed at spend
      GET/data/{network}/coins?ids=

      Batch summaries — several coins in one request, each row in the exact shape the snapshot grid serves. ids is comma-separated 64-hex covenant ids; ids the index doesn't know are simply absent from the answer, never an error.

      Request
      curl -s 'https://kascov.io/data/testnet-10/coins?ids=e55322e7…,a348a978…'
      Response · 200
      {
        "coins": [
          { "covenant_id": "e55322e7…60697", "name": "sleepy-olive-crane",
            "status": "active", "last_activity_daa": 513870198, … },
          { "covenant_id": "a348a978…f3a29", "name": "brave-jade-osprey",
            "status": "burned", "last_activity_daa": 513870178, … }
        ]
      }
      GET/data/{network}/tx/{txid}.json

      What did this transaction do, in covenant terms? Newer workers answer the whole story — the per-covenant events, the cells created and spent, and the decoded token actions — behind the site's #/{network}/tx/{txid} pages. Older workers answer only covenant_id / covenant_ids; every added field is additive, so feature-detect and fall back gracefully.

      Response · 200
      {
        "txid": "8e7040…3e2bb",
        "covenant_id": "b11acf6c…459c6",
        "covenant_ids": [ "b11acf6c…459c6" ],
        "accepting_daa": 513870178, "accepting_block": "3d1c00…45e7e2",
        "events": [
          { "covenant_id": "b11acf6c…459c6", "name": "brave-jade-osprey",
            "seq": 2, "kind": "burn", "tx_index": 18 }
        ],
        "cells": {
          "created": [ { "covenant_id": "…", "index": 0,
                         "value": 230415954231, "template": "p2sh commitment" } ],
          "spent": [ { "covenant_id": "…", "txid": "82aabd…25dcb", "index": 0,
                       "value": 230415954231,
                       "revealed_template": "SilverScript · Escrow",
                       "has_witness": true } ]
        },
        "token_actions": [
          { "token_id": "9cc4fb51…68f50", "name": "humble-crimson-magpie",
            "token_kind": "transfer", "amount": 1000000 }
        ]
      }
      Not covenant traffic · 404
      { "error": "not found" }
      FieldTypeNotes
      covenant_id · covenant_idshex · arraythe coin(s) this transaction touched — the only fields every worker serves
      accepting_daa · accepting_blockint? · hex?newer workers — where the chain accepted this transaction
      events[]array?newer workers — one row per covenant life event: covenant_id, name, seq, kind (genesis · transition · burn), tx_index?
      cells.created[]array?newer workers — covenant state this transaction made: covenant_id, output index, value (sompi), template?
      cells.spent[]array?newer workers — covenant state it consumed: the outpoint's txid + index, value, revealed_template?, and has_witness (the captured unlocking script — replayable through the spend debugger)
      token_actions[]array?newer workers — the decoded token view: token_id, name, token_kind (mint · transfer · burn), amount? in raw token units
      GET/data/{network}/addr/{address-or-pubkey}.json

      Which smart coins has this address touched? Accepts kaspa:… / kaspatest:… or raw 32/33-byte pubkey hex. Matches p2pk covenant states.

      Response · 200
      {
        "address": "kaspatest:qp9…hzy0",
        "pubkey": "4b3402be…e9f2",
        "covenants": [
          { "covenant_id": "…", "name": "…", "role": "controls_now" }
        ]
      }
      FieldTypeNotes
      covenants[].rolestringcontrols_now · states_seen
      GET/data/{network}/digest.json

      The last 24 hours in one object — births, moves, burns, value born, the busiest coin, the biggest birth, and how many coins are alive. Refreshes about once a minute.

      Response · 200
      {
        "births": 24762, "moves": 25948, "burns": 55074,
        "value_born": 4831200000000, "alive": 6566,
        "busiest": { "covenant_id": "…", "name": "curious-jade-zebra-6366", "events": 1185 },
        "biggest_birth": { "covenant_id": "…", "name": "rapid-violet-seal-b788", "value": 937465200000000 }
      }
      GET/data/{network}/templates.json

      What runs on this network — recognized script templates aggregated over every state UTXO. Unrecognized scripts are counted, never hidden.

      Response · 200
      {
        "templates": [
          { "name": "p2sh commitment", "live_states": 6297, "live_value": 62970000000,
            "ever_seen": 14459, "covenants": 5990, "revealed_runs": 3 }
        ],
        "unrecognized": { "ever_seen": 12, "live_states": 4 }
      }
      FieldTypeNotes
      revealed_runsintcompiled contracts proven at spend time; a tx sweeping N states counts N
      GET/data/{network}/activity.json?range=24h

      The histogram behind the activity chart — life-event counts per DAA bucket. Empty buckets are omitted; treat them as zeros.

      QueryTypeNotes
      rangeenum1h · 6h · 24h · 48h · all (default 24h)
      Response · 200
      {
        "range": "24h", "bucket_daa": 6000,
        "buckets": [ { "daa": 509540000, "births": 812, "moves": 903, "burns": 1740 } ]
      }
      GET/data/{network}/families.json

      Covenant apps — clusters of coins that moved together in a transaction (multi-contract flows), union-found over shared txids. Each family lists its members with their recognized template.

      Response · 200
      {
        "families": [
          { "size": 2, "members": [
              { "covenant_id": "09ef275e…", "template": "p2sh commitment", "shared_txs": 8 },
              { "covenant_id": "901be291…", "template": "p2sh commitment", "shared_txs": 8 }
          ] }
        ]
      }
      GET/data/{network}/galaxy.json?fmt=2&tier=core

      The whole-network app graph behind the galaxy map — precomputed positions, weighted edges, and status for every smart coin. Built server-side and kept warm, so even a 168k-coin network answers instantly.

      QueryTypeNotes
      fmtenum2 — columnar arrays instead of one object per node (much smaller payload)
      tierenumcore — the big clusters only, for a fast first paint; fetch the full graph after

      Unknown params and unknown values degrade to the legacy full-object shape — old clients keep working unchanged.

      GET/data/{network}/lanes.json

      Based-app traffic by namespace — KIP-21 lanes, 4-byte app tags, and the JSON-inscription bucket, sorted by event count. Printable tags get their ASCII label; the rest show as 0x….

      Response · 200
      {
        "tip_daa": 509571904,
        "lanes": [
          { "label": "kspr", "hex": "6b737072", "ascii": true,
            "kind": "tag", "events": 40312, "covenants": 6120 },
          { "label": "JSON inscriptions", "hex": null, "ascii": false,
            "kind": "inscription", "events": 8123, "covenants": 950 }
        ]
      }
      FieldTypeNotes
      lanes[].kindstringlane (KIP-21 namespace) · tag (4-byte app tag) · inscription (JSON payloads)
      lanes[].hexhex?the raw 4-byte namespace; null for the JSON-inscription bucket
      GET/data/{network}/lane/{ns}

      One namespace's dashboard — headline counts, the 50 newest events, and an hourly activity series over the lane's whole life. {ns} is the 4-byte tag as exactly 8 hex characters — anything else is a 400.

      Request
      curl -s https://kascov.io/data/testnet-10/lane/6b737072
      Response · 200
      {
        "namespace": "6b737072",
        "events": 40312, "covenants": 6120,
        "recent": [ { "covenant_id": "…", "txid": "…",
                      "accepting_daa": 509571333, "kind": "transition" } ],
        "activity": [ { "daa": 509540000, "count": 812 } ],
        "bucket_daa": 36000
      }
      FieldTypeNotes
      bucket_daaintbucket width of the activity series — 36,000 DAA ≈ 1 hour
      GET/data/{network}/inscriptions.json

      The JSON-inscription breakdown — events and distinct coins per decoded label (KRC-20 ops and friends).

      Response · 200
      {
        "inscriptions": [
          { "label": "krc-20 mint", "events": 5123, "covenants": 640 }
        ]
      }
      GET/data/{network}/tokens.json

      The covenant-token directory behind the tokens page — every KCC20-shaped coin the indexer decoded, its ticker and fields read straight from the chain's bytes, plus a conservative validation verdict per token: status is verified only when every event in the token's history matched a known KCC20 rule and supply is conserved; anything unknown or ambiguous stays unvalidated with a reason — never a false "valid". The response explains itself in note — surface it to your users too. Older workers answer the pre-validation shape (status is the coin's active/burned liveness, no supply fields) — treat those tokens as unvalidated.

      Response · 200
      {
        "note": "validated from chain — verified means every event matched …",
        "tip_daa": 513875491, "tip_at_ms": 1783746272524,
        "tokens": [
          { "covenant_id": "9cc4fb51…68f50", "name": "humble-crimson-magpie",
            "template": "KCC20 token",
            "fields": { "tick": "NACHO", "op": "deploy" },
            "live_value": 100000000,
            "status": "verified",
            "supply": 2100000000, "minted": 2100000000, "burned": 0,
            "holders": 12,
            "last_activity_daa": 513875477 }
        ]
      }
      FieldTypeNotes
      tokens[].fieldsobjectthe decoded key/values exactly as the covenant wrote them — no registry, no labels kascov invented
      tokens[].live_valueint?sompi the coin holds right now
      tokens[].statusstringverified · invalid · unvalidated — conservative: verified means every event in the history matched a known rule
      tokens[].invalid_reasonstring?why the verdict isn't verified — present on invalid (and unvalidated) tokens
      tokens[].supplyint?live supply in raw token units — minted − burned
      tokens[].minted / burnedint?lifetime totals in raw token units
      tokens[].holdersint?owners with a non-zero balance right now
      GET/data/{network}/token/{covenant_id}

      One token's whole story behind its token page — the directory row, the top 100 balances, every event classified as mint / transfer / burn with amounts and owners, and the validation verdict. Same conservative contract as the directory: a token is verified only when every checked event matched a known KCC20 rule. 404 when the id isn't a token this worker knows (or the worker predates token pages).

      Response · 200
      {
        "token": { "covenant_id": "9cc4fb51…68f50",
                   "name": "humble-crimson-magpie", "template": "KCC20 token",
                   "fields": { "tick": "NACHO" }, "status": "verified",
                   "supply": 2100000000, "minted": 2100000000, "burned": 0,
                   "holders": 12, "last_activity_daa": 513875477 },
        "balances": [ { "owner": "3f9a…c221", "balance": 1250000000 } ],
        "events": [ { "txid": "…", "accepting_daa": 513875477,
                      "kind": "transition", "token_kind": "mint",
                      "amount": 1000000, "owner_to": "3f9a…c221" } ],
        "validation": { "checked": 266 }
      }
      FieldTypeNotes
      tokenobjectthe same row the directory serves for this token
      balancesarraythe top 100 balances, largest first — owner is the controlling pubkey, balance is raw token units
      events[].token_kindstringmint · transfer · burn — the canonical event object plus the token classification, amount and owner_from/owner_to
      validationobjectthe verdict's working: checked events walked; reason says what stopped a verified verdict when the status isn't verified
      GET/data/{network}/lifespans.json

      How long do smart coins live? A bucketed lifespan histogram over every retired coin, plus the median. Times derive from DAA at 10 per second, so median_ms is an estimate.

      Response · 200
      {
        "buckets": [ { "label": "< 1 min", "count": 41230 } ],
        "median_daa": 1840, "median_ms": 184000, "total": 83181
      }
      GET/data/{network}/reorgs.json

      The indexer's own reorg ledger — the last 500 virtual-chain reorgs it applied, newest first. Every entry is a rewind the index actually performed, not a heuristic.

      Response · 200
      {
        "reorgs": [ { "daa": 509571904, "at_ms": 1751799000000, "rolled_back": 2 } ]
      }
      GET/data/{network}/consistency.json

      An automated cross-check between independent ecosystem indexers — kascov's decoded token set compared against another indexer's, token by token. Differences usually mean one of us has a bug; we fix ours and share theirs kindly. Served by newer workers; older ones 404.

      Response · 200
      {
        "network": "mainnet", "checked_at_ms": 1783948200000,
        "our_tip_daa": 513875477, "other_source": "…",
        "other_blue_score": 513875470,
        "tokens_ours": 270, "tokens_other": 268, "intersection": 265,
        "agree": 261, "differ": 4,
        "only_kascov": 5, "only_other": 3, "not_comparable": 0,
        "details": [ { "token_id": "…", "field": "supply",
                       "ours": 2100000000, "theirs": 2099999000 } ],
        "note": "tips differ — small disagreements near the tip are expected"
      }
      FieldTypeNotes
      network · checked_at_msstring · intwhich network was compared, and when the check ran
      our_tip_daaintkascov's chain tip at check time
      other_source · other_blue_scorestring · intthe other indexer's identity and its chain position — two indexers at different tips can honestly disagree
      tokens_ours · tokens_other · intersectioninthow many tokens each side knows, and how many both do
      agree · differintof the intersection: tokens whose compared fields match, and tokens where they don't
      only_kascov · only_otherinttokens one side has indexed that the other hasn't (yet)
      not_comparableinttokens skipped because the two sides expose incompatible shapes for them
      details[]arraythe actual disagreements, per token — what we say, what they say
      notestringplain-language context for reading the numbers
      GET/data/{network}/search?q=&limit=

      Find a coin — by covenant-id hex prefix (4+ characters), friendly-name prefix, or template substring. Each hit says which way it matched.

      QueryTypeNotes
      qstringrequired, 1–64 characters; 400 otherwise
      limitintmax results, default 10, clamped
      Request
      curl -s 'https://kascov.io/data/testnet-10/search?q=mece'
      Response · 200
      {
        "query": "mece",
        "results": [
          { "id": "b4ade48e…", "name": "brave-amber-lynx-b4ad",
            "template": "SilverScript · Mecenas",
            "status": "active", "matched": "template" }
        ]
      }
      FieldTypeNotes
      results[].matchedstringid · name · template
      GET/data/{network}/debug/{txid}

      Replay a real on-chain covenant spend through the actual script engine, with the witness captured at index time — a concrete per-opcode trace of what really ran. The transaction context is fabricated, so signature/introspection checks may diverge from the original; the response says so in note.

      Response · 200
      {
        "ok": true, "pass": true, "verdict": "script accepted",
        "covenant_id": "…", "outpoint": { "txid": "…", "index": 0 },
        "value": 500000000,
        "trace": [ { "op": "OpBlake2b", "dstack": ["…"], "astack": [] } ],
        "trace_truncated": false,
        "note": "replayed with a fabricated tx context"
      }
      FieldTypeNotes
      okboolfalse when the txid spent no tracked state, or no witness was captured (reason says which)
      trace_truncatedboolthe trace is capped at 2,000 opcodes
      GET/share/{network}/{covenant_id}

      The crawler-visible page for one coin (the SPA is hash-routed, so scrapers never see #/… urls) — OG/Twitter meta plus a redirect into the app for humans. Its picture is a server-rendered PNG card, and /sitemap.xml lists every share page so search engines find every coin. These live on the site root, not under /data.

      The card image
      GET /og/{network}/{covenant_id}.png
      → 1200×630 Open Graph card (name, avatar,
        holdings, story), rendered on demand
      The index
      GET /sitemap.xml
      → every coin's /share/… url
      POST/data/{network}/simulate

      Run a hypothetical spend of a compiled contract through the real script engine, off-chain — the same PASS/FAIL a node would decide, with the violated rule in plain English on failure. Pure computation: the network segment is cosmetic, and responses are no-store.

      Request body
      {
        "program_hex": "20d9a9…87",   // ≤ 20,000 hex chars
        "entrypoint": "spend",        // spend · reclaim · cold · inherit
        "recipient": "buyer",         // buyer · seller · other · self
        "value": 500000000,           // the state coin, sompi
        "amount": 499999000,          // output 0; default value − 1000
        "trace": true                 // capture per-opcode stacks
      }
      Response · 200
      {
        "ok": true, "pass": false,
        "verdict": "…", "rule": "output 0 must pay the buyer exactly value − 1000",
        "template": "SilverScript · Escrow",
        "trace": [ { "op": "OpDup", "dstack": ["…"], "astack": [] } ],
        "note": "simulated with a stand-in signer"
      }
      POST/data/{network}/preflight

      Will this transaction pass? Post a transaction as JSON (the SDK / RPC shape — {version, inputs, outputs, lockTime, …}) and get a verdict before you broadcast: per-input compute-budget checks (the classic “script units exceeded” trap), compute/storage mass against the block limit, an honest fee estimate — and for inputs that carry both their signatureScript and their utxo.scriptPublicKey, a real run through the script engine with the budget the transaction declares. Nothing is broadcast, nothing is stored: responses are no-store and the transaction goes into the call and nowhere else. The network segment picks the mass limits. Served by newer workers; older ones answer 404. Also behind the playground’s check-a-transaction mode.

      Request body — the transaction itself
      {
        "version": 1,
        "inputs": [
          { "previousOutpoint": { "transactionId": "…", "index": 0 },
            "signatureScript": "…", "sequence": 0,
            "sigOpCount": 1, "computeBudget": 20,
            "utxo": { "amount": 1000000000,
                      "scriptPublicKey": { "version": 0, "script": "…" } } }
        ],
        "outputs": [ { "value": 999999000,
                       "scriptPublicKey": { "version": 0, "script": "…" } } ],
        "lockTime": 0
      }
      Response · 200
      {
        "ok": true, "verdict": "will_fail",
        "findings": [
          { "severity": "error", "code": "compute_budget_missing",
            "message": "input 0 is a v1 input with no computeBudget — its
                        effective allowance is 9,999 script units and one
                        CheckSig needs 100,000",
            "input_index": 0, "suggestion": "set computeBudget: 10" }
        ],
        "masses": { "compute": 12345, "storage": 0,
                    "transient": 512, "limit": 500000 },
        "fee": { "estimate_sompi": 202400, "note": "an estimate, not consensus" },
        "executed": [
          { "input_index": 0, "pass": false,
            "script_units_used": 100000, "allowance": 9999 }
        ]
      }
      FieldTypeNotes
      verdictstringready — every check passed · will_fail — a node would reject this as-is · incomplete — not enough of the transaction to decide
      findings[]arrayeach check’s answer: severity (error · warn · info), a stable machine-readable code, a plain-English message, the offending input_index?, and a concrete suggestion? (the fix, e.g. set computeBudget: 10)
      massesobject?compute / storage / transient against the network’s block limit; omitted when budget findings block the mass calculation
      feeobject?estimate_sompi + note — labeled an estimate honestly: no consensus min-fee primitive exists
      executed[]array?per executable input: pass, script_units_used, allowance — the real engine, the transaction’s own declared budget
      POST/data/{network}/compile

      Compile SilverScript source server-side. Body is { source, args } — source up to 40,000 characters, at most 16 constructor args of ≤200 characters each.

      Response · 200
      { "ok": true, "hex": "20d9a9…87" }
      // or
      { "ok": false, "error": "compile error: …" }
      POST/data/{network}/publish

      Verify-and-publish, Etherscan-style: submit { source, args }; the worker compiles it and stores the source keyed by the compiled program's blake2b-256 hash. Any coin whose revealed program hashes the same now shows your source as community-verified.

      Response · 200
      { "ok": true, "hash": "d9a9e982…f475d17",
        "template": "SilverScript · Mecenas" }
      GET/data/{network}/verified/{hash}

      The published source for a program hash — what /publish stored. { "ok": false } when nothing is published for that hash.

      Response · 200
      { "ok": true, "source": "contract Mecenas(…) { … }",
        "args": "…", "template": "SilverScript · Mecenas",
        "verified_at": 1752130000000 }
      POST/data/{network}/subscribe

      Register a webhook: your URL gets one JSON POST per matching covenant event, delivered as it happens. Filter to one coin with covenant_id (must be exactly 64 hex characters — anything else is rejected, never a silent wildcard) and/or one event kind; omit both for everything. The response hands you a generated secret — shown once, never readable back: every delivery is signed with it, and only someone holding it can unsubscribe the hook. Unsubscribe with POST /data/{network}/unsubscribe, the returned id, and that secret.

      Request body
      {
        "url": "https://example.com/hook",
        "covenant_id": "b4ade48e…",  // optional, 64 hex
        "kind": "burn"               // optional: genesis · transition · burn
      }
      // → { "ok": true, "id": 7, "secret": "9f2ab4…" }  // save it — shown once
      // unsubscribe: { "id": 7, "secret": "9f2ab4…" }
      //            → { "ok": true, "deleted": true }
      Each delivery
      POST your-url  ·  application/json
      X-Kascov-Signature: 3f9c41…  (keyed with your subscription's secret)
      {
        "network": "testnet-10",
        "covenant_id": "b4ade48e…",
        "kind": "burn",
        "txid": "1461f8…07ed",
        "accepting_daa": 509571520,
        "tx_index": 18
      }
      SemanticsNotes
      authenticityevery delivery carries X-Kascov-Signature: the hex keyed blake2b-256 of the exact request body, keyed with the secret /subscribe returned — recompute it over the raw bytes you received and compare before trusting the event
      deliveryup to 3 attempts with backoff, 5s timeout, redirects never followed; a subscription that keeps failing is retired automatically
      targetspublic http(s) hosts only — every resolved address is checked, and loopback / private / link-local targets are rejected (SSRF guard)
      guaranteesbest-effort hints, not a durable feed — confirm through the polled endpoints
      POST/data/{network}/deploy

      One-click deploy: the server births your compiled contract as a real covenant on testnet-10 using its own faucet key — no local toolchain. Gated off by default: the route exists only when the server is armed (KASCOV_DEPLOY_KEY) and the network is testnet-10; otherwise it answers 404. Never on mainnet.

      Request body
      {
        "program_hex": "20d9a9…87",  // ≤ 20,000 hex chars
        "value": 1000000000          // 1–10 TKAS, in sompi
      }
      Response · 200
      { "ok": true,
        "covenant_id": "b4ade48e…",
        "network": "testnet-10" }
      LimitNotes
      globaltoken bucket — 5 burst, refilling 1 per 10 minutes (≈144/day); throttled requests get 429
      per IP20 deploys per day (best-effort)
      in flightone deploy at a time — they share the funding wallet

      Served by an always-on indexer that follows the chain live. Want the raw index or to run your own? github.com/Knitser/kascov.

      what’s new

      the milestones — what kascov learned to do, newest first.

        Kaspa nodes forget after roughly 30 hours. kascov remembers.

        explorer · playground · JSON API & docs · the 15-minute guide · what’s new · feed

        github.com/Knitser/kascov

        data streams live from the kascov indexer — it never stops watching

        not affiliated with the Kaspa Foundation