# KaspaSeal demo API — instructions for autonomous agents

You are reading the canonical machine-readable guide to the KaspaSeal public
demo. Everything here is self-contained: an agent with HTTP access and a
SHA-256 implementation can complete the full lifecycle without a human.

**What this is:** KaspaSeal anchors tamper-proof audit trails to the Kaspa
BlockDAG. You declare an action before performing it (`INTENT`), seal the
outcome after (`RESULT`, chained to its intent via `parent_txid`), and anyone
can verify the records on the public chain without trusting KaspaSeal. The
demo hands you a disposable, budgeted wallet on the TN10 test network so you
can try the primitive for real: the transactions are real, the tokens are
worthless.

**Base URL:** `https://demo.kaspaseal.dev`
**Verify URLs:** `https://verify.kaspaseal.dev/v/<txid>` (no auth, no account)
**Network:** Kaspa testnet-10. Mainnet is on the roadmap, not in the demo.

## Constraints (read first)

| Constraint       | Value                                                                                                                                                       |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Sessions per IP  | 1 new per 10 min; max 2 live                                                                                                                                |
| Session lifetime | 30 minutes, then auto-sweep                                                                                                                                 |
| Anchor budget    | 50 anchors per session                                                                                                                                      |
| Anchor pacing    | ≥ 2 s between anchors (429 `RATE_LIMITED` with `retry-after` otherwise)                                                                                     |
| Payload size     | ≤ 4096 bytes serialized JSON                                                                                                                                |
| `parent_txid`    | must be a txid anchored by YOUR session                                                                                                                     |
| Privacy note     | this hosted demo receives your payload to anchor it; only its SHA-256 goes on-chain. Self-host the SDK if the payload itself must never leave your process. |

Etiquette: call `DELETE /v1/session` when you finish so the wallet sweeps
back to the shared treasury immediately instead of waiting out the TTL.

## Step 1 — solve the proof-of-work

```
GET /v1/challenge
→ 200 { "challenge": "<opaque string>", "difficulty": 20, "expires_at": "<iso>" }
```

Find a decimal-string `nonce` such that `sha256(utf8(challenge + ":" + nonce))`
has at least `difficulty` leading zero bits. Challenges expire in ~3 minutes
and are single-use. Reference implementation (Node):

```js
import { createHash } from 'node:crypto';
const bits = (b) => {
  let n = 0;
  for (const x of b) {
    if (x === 0) {
      n += 8;
      continue;
    }
    n += Math.clz32(x) - 24;
    break;
  }
  return n;
};
let nonce = 0; // ~1 s at difficulty 20
while (bits(createHash('sha256').update(`${challenge}:${nonce}`).digest()) < difficulty) nonce++;
```

## Step 2 — create a session

```
POST /v1/session
body: { "challenge": "<from step 1>", "nonce": "<string>" }
→ 201 { "session_id", "token", "status": "provisioning", "expires_at",
        "anchor_budget": 50, ... }
```

Store `token`; it is shown exactly once and is your bearer credential for
every other call. Provisioning funds a real wallet and fans it out on-chain —
typically 10–40 s.

## Step 3 — poll until ready

```
GET /v1/session
header: authorization: Bearer <token>
→ 200 { "status": "provisioning" | "ready" | "failed" | "sweeping",
        "address", "funding_txid", "anchors_used", "anchors_remaining",
        "expires_at", ... }
```

Poll every ~3 s. `failed` is terminal (start over); a `401` means the session
was swept and retired.

## Step 4 — anchor proofs

```
POST /v1/anchor
header: authorization: Bearer <token>
body: {
  "action_type": "INTENT" | "COMMIT" | "RESULT" | "VERIFY" | "DISPUTE",
  "payload": <any JSON ≤ 4096 bytes>,
  "parent_txid": "<64-hex txid from this session>"   // optional
}
→ 200 { "txid", "payload_hash", "action_type", "parent_txid",
        "status": "signed", "verify_url", "anchors_remaining", "bundle" }
```

Semantics that make trails meaningful:

- Anchor an `INTENT` **before** you perform an action; put the tool name and
  arguments in the payload (e.g. `{ "agent_id": "...", "tool_name": "...",
"args": { ... } }`).
- Anchor a `RESULT` **after**, with `parent_txid` set to the intent's txid.
- Anchor a `DISPUTE` instead when the action failed or was aborted.
- Chain the next action's `INTENT` to the previous `RESULT` to form one
  continuous, append-only trail.
- Only `sha256(JCS(payload))` goes on-chain (69 bytes total per proof:
  magic, action byte, payload hash, parent txid). Keep your own copy of the
  payload if you will need to prove its contents later.
- `bundle` is the signed proof bundle (public key, signed buffer, Schnorr
  signature). It is returned only here — `GET /v1/proofs` does not repeat
  it — so store it with your payload: offline verification needs both (the
  bundle proves the signature, the payload re-hashes against the anchored
  hash), long after the demo session is gone.

`status: "signed"` returns immediately; chain confirmation completes within
seconds to a few minutes and is visible at `verify_url`.

## Step 5 — inspect and finish

```
GET /v1/proofs        (bearer) → 200 { "proofs": [ { txid, action_type,
                       payload_hash, parent_txid, status, verify_url, ... } ] }
DELETE /v1/session    (bearer) → 200 { "status": "sweeping", ... }
```

After the sweep completes the session disappears (`401` on every call). The
proofs remain on the public TN10 chain. Honest scope: test networks are
periodically retired (Kaspa has replaced older testnets before), so demo
proofs share the testnet's lifespan — the demo demonstrates the mechanism;
mainnet-grade durability is a production property.

## Errors

| Code                                                                                                         | HTTP      | Meaning / what to do                                                                               |
| ------------------------------------------------------------------------------------------------------------ | --------- | -------------------------------------------------------------------------------------------------- |
| `DISABLED`                                                                                                   | 503       | demo killswitched — try much later                                                                 |
| `RATE_LIMITED`                                                                                               | 429       | honor the `retry-after` header (seconds)                                                           |
| `BAD_CHALLENGE` / `BAD_POW`                                                                                  | 400       | expired/reused challenge or wrong nonce — restart at step 1                                        |
| `CAPACITY` / `TOO_MANY_SESSIONS`                                                                             | 503 / 429 | all slots busy / your IP at its live cap — retry in minutes; your solved challenge is NOT consumed |
| `TREASURY_LOW` / `NODE_UNAVAILABLE`                                                                          | 503       | backend cannot fund/reach the chain — retry later; challenge NOT consumed                          |
| `INVALID_TOKEN`                                                                                              | 401       | session swept or token wrong — start over                                                          |
| `SESSION_NOT_READY`                                                                                          | 409       | still provisioning — keep polling                                                                  |
| `SESSION_ENDED` / `SESSION_EXPIRED`                                                                          | 410       | terminal — proofs remain valid on-chain                                                            |
| `BUDGET_EXHAUSTED`                                                                                           | 429       | 50-anchor budget spent — session auto-retires                                                      |
| `INVALID_ACTION_TYPE` / `MISSING_PAYLOAD` / `PAYLOAD_TOO_LARGE` / `INVALID_PARENT` / `PARENT_NOT_IN_SESSION` | 400/413   | fix the request per the table above                                                                |
| `ANCHOR_FAILED` / `LIST_FAILED` / `INTERNAL`                                                                 | 5xx       | transient backend trouble — retry once after a few seconds                                         |

## Verifying independently

Each proof's `verify_url` opens the open-source universal verify page on the
proof's txid, which checks the on-chain record against the public BlockDAG
(payload hash, parent linkage, confirmation status). To also verify the
Schnorr **signature**, paste the proof's `bundle` plus the original payload
into the same page — that check runs fully offline. The verifier is
Apache-2.0 and self-hostable with your own Kaspa node — verification never
requires trusting KaspaSeal's servers.

## Beyond the demo

The same primitives ship as the `@kaspaseal/sdk` library (self-hosted: your
keys, your store, only hashes leave your process), a 12-tool MCP server for
tool-calling agents, and a Claude Agent SDK adapter that maps
PreToolUse → INTENT, PostToolUse → RESULT, PostToolUseFailure → DISPUTE
automatically. npm release is staged; a hosted MCP endpoint is on the
roadmap. Human-readable overview: https://kaspaseal.dev
