Kaspa x402: pay-per-request KAS payments for APIs and AI agents

TL;DR

x402 is an open standard that lets websites, APIs, and AI agents charge and pay for individual HTTP requests. I have built a complete alpha implementation of native Kaspa support for it: specs, JSON schemas, test vectors, TypeScript packages, and a live testnet gateway that has settled real testnet-10 payments.

Everything is public at https://kaspa-x402.org.

Before I take this to the two standards bodies involved (CASA, which registers cross-chain network identifiers, and then the x402 Foundation), I want the community’s eyes on it. One decision in particular, the network-identifier convention, is hard to change later. Objections and feedback are welcome until 24 July 2026; after that I will proceed as described below.

What x402 is and why Kaspa fits

When a server wants payment for a request, it replies with HTTP status 402 Payment Required plus a machine-readable price offer. The client pays, retries the request with proof of payment attached, and the server verifies the payment and serves the response. That is the whole protocol. It was started by Coinbase, is now governed by a Linux Foundation project (the x402 Foundation, founded by Coinbase and Cloudflare), and is becoming the default way AI agents pay for APIs and tools.

Kaspa is unusually well-shaped for this. Paying per request only works when payment confirmation is not the slow path, and Kaspa’s block cadence makes one-shot native payments practical at request time: my live gateway verifies accepted payments roughly a second after broadcast. Every blockchain currently in x402 (Solana, TON, Algorand, Stellar, Aptos, Hedera, and the EVM chains) is account-based. Kaspa would be the first UTXO chain, and this implementation is UTXO-native throughout: a payment is identified by its transaction id and outputs, not by account allowances.

What exists today (all public, all testnet-only)

  • Standards site: kaspa-x402 has the specs, JSON schemas, test vectors, and immutable release snapshots.
  • Reference implementation: GitHub - elldeeone/kaspa-x402: Kaspa x402 is a proposed native Kaspa binding for x402, the HTTP 402 payment protocol. · GitHub with @kaspa-x402/core, client, server, and covenant packages on npm, plus a CLI and runnable examples.
  • Live gateway: https://demo.kaspa-x402.org is a public testnet-10 server you can pay right now. It runs an automated public health check and holds no spending keys.
  • Recorded live evidence: funded end-to-end payment runs on testnet-10, covering one-shot payments, safe handling of replayed and reused transactions, and escrow deposit/voucher settlement. Transaction ids are in the gateway docs and check out on the testnet explorer.
  • Browser test client: Browser Test Client — Kaspa x402 for connectivity checks and payment-header rehearsal (keys stay in browser memory).
  • Threat model, mainnet-readiness gates, versioning policy, and implementer guide, all published on the site.

To be explicit about limits: this is alpha, testnet-10 only. The wire format is not frozen, and mainnet use is blocked by published gates (independent audit among them). Nothing here claims production readiness.

The two payment schemes I ship, and the two I deliberately do not

x402 defines four payment schemes. This implementation ships two:

  • exact: a fixed-price one-shot KAS transfer. One caveat for implementers: KIP-9’s storage-mass rules put a floor on standard output size (roughly 0.1 KAS), so exact prices cannot go below that.
  • batch-settlement: the micropayment path, for prices below that floor. A client locks funds in an escrow once, then signs a small voucher for each paid request; the chain is only touched again at claim or refund time. The demo gateway charges 500 sompi per request this way. The escrow covenant is written in SilverScript and validated against Rusty Kaspa consensus.

The other two schemes (upto and auth-capture) are missing for a technical reason, not oversight. Both need a payment authorisation that expires at a deadline, enforced on-chain. Kaspa’s on-chain script (the layer SilverScript compiles down to) only supports lower-bound time locks, because a once-valid transaction must never become invalid. So an expiry can only be approximated by a refund race, and shipping that under upstream’s stricter definition would overstate the guarantee. I built and consensus-validated a capped-authorisation covenant anyway (archived on the archive/capped-authorization-experiment branch) and shelved it until upstream clarifies whether a refund-race expiry qualifies. The full write-up is the native-profile-boundary doc on the site.

What happens next, and where you can object

Step 1: register the kaspa network identifier (CASA). Cross-chain standards, x402 included, need one agreed way to write “which network is this?”. The convention is CAIP-2 identifiers: Ethereum mainnet is eip155:1, Stellar is stellar:pubnet. Kaspa has never registered one. I intend to open a PR at ChainAgnostic/namespaces registering:

  • kaspa:mainnet
  • kaspa:testnet-10

These are the names RK, explorers, and wallets already use. Some chains register a genesis-block hash instead; I chose names because that is how Kaspa already talks, and hash aliases can be added later if needed. The registration also sets how account addresses are written: the address without its kaspa:/kaspatest: prefix, since the identifier already names the network.

This is an objection check. The identifier convention is the one decision that is hard to change later, so before I lodge the registration: if kaspa:mainnet-style identifiers would break or fight anything you know of, say so in this thread before 24 July 2026. If nothing blocking comes up, I will open the PR.

Step 2: propose the Kaspa bindings to the x402 Foundation. Once the identifier registration is in review, I will open a feature request at x402-foundation/x402 proposing Kaspa support for the exact and batch-settlement schemes, following the same path Stellar, Aptos, and Hedera took.

Step 3: external implementers. After that, I am looking for a few people to test their own clients against the live gateway and report what breaks. There is an implementer guide, a public faucet for testnet funds, and issue templates in the repo.

What I am asking

  1. Objections to the kaspa: identifier convention (the time-sensitive one, open until 24 July 2026).
  2. Technical review of the specs, especially from anyone who has built on the WASM SDK.
  3. Anyone interested in being an early external implementer.
  4. Corrections: if anything published overstates what Kaspa or this implementation can do, I want to know first.
18 Likes

This is very cool!

No objections to the kaspa:mainnet / kaspa:testnet-10 identifiers, this makes sense. The network-to-address-prefix mapping may be worth making explicit though, to avoid confusion:
kaspa:mainnet → kaspa:
kaspa:testnet-* → kaspatest:

I reviewed the specs from the WASM SDK’s angle and have some findings (I reviewed this with Claude’s help so these points should probably be verified by someone from the core dev side before acting on them):

  • kaspa-exact-v1, PaymentPayload section: the spec requires transaction as a hex string but the WASM SDK currently only does JSON serialization. The byte format should be written into the spec itself. A new serializeToBytes() / deserializeFromBytes() may need to be added to the SDK.

  • kaspa-batch-settlement-v1, Voucher Digest section: the WASM SDK can only sign transactions and text messages (via signMessage). So it cannot produce a Schnorr signature over the spec’s raw digest, suggestion: define the voucher as a plain text message, e.g. kaspa:x402:escrow-voucher:v1|<network>|<script>|<txid>|<index>|<amount>, signed with the standard signMessage.

  • One small correction: the ChannelConfig section defines the scriptPublicKey serialization as uint16_le version || script bytes, but rusty-kaspa’s covenant introspection opcodes (OpTxInputSpk / OpTxOutputSpk) push the version big-endian, the two only agree because this profile pins version to 0. Worth either correcting to uint16_be or noting the version-0 pin explicitly.

4 Likes

Hi! Thank you for joining and posting.
The overview is great and I am with you on the identifiers names.
Looking forward to dig into the code, I’ll get to that later this week =]

2 Likes

@carlssonk Thanks, always great to have another set of eyes (or LLM) over this! I verified all three findings and shipped fixes as v0.1.0-alpha.4 (npm, the spec on the site, and the redeployed gateway).

Prefix mapping: yes, that is 100% the intention. mainnet maps to kaspa:, testnet- to kaspatest:. The registration PR will state it explicitly.

Endianness: confirmed, spec now reads uint16_be. One wrinkle: consensus hash preimages encode the version little-endian (hashing/tx.rs, sighash.rs), so the transaction builder keeps LE in that layer only.

Voucher signing: confirmed. The covenant checks a raw sha256(voucherMsg) Schnorr signature, while the gateway was accepting SDK personal-message signatures. Fixed in alpha.4: spec, gateway verifier, state reset, and fresh funded evidence all now use raw-digest signing.

The hard bit is wallet support. The covenant needs the exact outpoint-bound digest, so plain-text SDK message signing does not map cleanly to the script. For now, batch implementers need a Schnorr library that can sign raw 32-byte digests. I would appreciate input here (from anyone), is a raw-hash Schnorr signing API the right shape, or is there a safer interface this should be asking for? Might need to brainstorm this one..

Transaction hex: I’m leaning towards dropping it. The spec asks for serialised transaction hex, but the SDK does not expose a stable signed-transaction byte format, and the gateway already verifies exact payments from transactionId + paymentOutputIndex + payTo UTXO evidence.

3 Likes

This is a very exciting effort!

I think the network identifiers proposed makes sense. Also, I intend to spend some time going through https://kaspa-x402.org over the coming weeks.

6 Likes

Quick follow up on the tx hex point I mentioned above.

I have pushed `v0.1.0-alpha.5`. The `exact` payment payload no longer carries serialised transaction hex. It now carries `transactionId` and `paymentOutputIndex`.

The server verifies the selected pay to output from chain evidence.

The original shape came from trying to stay close to a “client sends transaction, server verifies or broadcasts it” flow but that ended up being the wrong fit.

Everything is updated, docs and fresh hosted evidence are live at https://kaspa-x402.org and https://demo.kaspa-x402.org.

Sorry for the churn :folded_hands:

6 Likes

A couple feedback by only surfacing the implementation and proposal.

The flow without a facilitator is: server verifies payload and settles (submit the transaction to the network).
With a facilitator: server round trip (up to twice) with facilitator and facilitator settles.

Current implementation is wrong because the client settles.


I think we can work around exact, make merchant address a P2SH, and use the borrow technique described in KIP-10. batch-settlement shouldn’t exists if exact works at internet speed.

1 Like

@IzioDev thanks again for taking a look. I reworked exact around KIP10 as you suggested, and agree it is better not to lock this into simple address-payment assumptions. The server now advertises reservation terms, the client returns a signed transaction artifact, and the server/facilitator verifies, settles, observes finality, then serves the response.

I also get your point on batch-settlement too. Kaspa at internet speed is why exact should be the default for normal per-request payments. The reason I still see warrant for batch is less about speed and more about prepaid usage. A user can fund once, make many small x402 requests over time via vouchers, and the merchant claims later. That may be useful for API credits, sessions, or very small requests where the operator wants a committed balance instead of a fresh payment every time. Still open to being wrong on that, but it feels worth keeping as an option while this is alpha.

Also, correction to my earlier comment about Kaspa being the first UTXO x402 binding. My mistake, Cardano was first. Hopefully Kaspa can still be the first internet-speed, decentralised PoW on x402! :grin:

3 Likes

I’m the author of x402 PR #1729 (the Kaspa exact scheme based on standard native transfers). After discussing consolidation, I’ve closed it in favour of a single coordinated proposal — with one integration request below.

Thanks for reaching out. I fully agree that Kaspa should have one coordinated upstream proposal rather than competing specifications — that’s why I’ve already closed #1729, and I support consolidating around your submission.

That said, I’d like to ask for one thing to be integrated: the substance of #1729 — an exact variant based on standard native transfers, with no KIP-10 reservation required — included in the consolidated spec as the baseline. My reasoning:

1. Adoption cost. The reservation-backed scheme requires merchants to operate borrow-UTXO inventory and a reservation provider. A standard-transfer variant works with nothing more than a receiving address in a config. Most x402 adopters (API operators, AI-agent platforms) won’t be Kaspa specialists, and this is where the entry barrier gets decided.

2. Client compatibility. Standard transfers can be signed today by any existing wallet or the WASM SDK. Agent-side tooling will support the simplest form first.

3. Audit surface. Standard transfers ride entirely on rusty-kaspa’s standard validation path, so the audit scope shrinks to server logic. That gives the spec a production-usable entry point on mainnet without waiting for the covenant paths to be audited.

4. Risk surface. The baseline avoids the reservation-specific issues — the verify-to-broadcast race on shared inventory and the top-up griefing vector that the spec itself mitigates only by operator convention. This isn’t a proposal to replace the reservation scheme. Having both variants — standard transfer as the baseline, reservation-backed as an optimization for UTXO efficiency — seems like the best outcome for both adoption and safety.

I can contribute the spec text and schemas from #1729 as-is and do the integration work myself. I’d also be glad to review the implementation, and I’ll take you up on the walk-through offer.

6 Likes

Thanks @Ross.

I dug into how other x402 bindings support different ways of settling the same exact scheme. The EVM binding supports EIP-3009, Permit2 and ERC-7710 through extra.assetTransferMethod, while XRPL uses a similar approach for sequence and ticket-based payments. That led me to try a similar structure for Kaspa in alpha.8.

Kaspa now has one exact binding with an explicit profile.

profile = "standard-native"  // default
profile = "additive"         // optional KIP-10

standard-native is the baseline you described. The on-chain payment is an ordinary native KAS transaction and requires no KIP-10 head inventory. It uses transaction primitives available through the WASM SDK, while the x402 layer provides the request authorisation and facilitator verification.

The more I’ve thought about the overall path forward, the more I think supporting both options may be the most useful approach. Some operators will want the simplest possible route, while others will benefit from KIP-10. Giving them that flexibility feels better than forcing everyone into one model, especially when other x402 bindings already support multiple transfer methods.

This does not make the KIP-10 audit surface disappear from the combined reference implementation, but operators who do not need it can use the standard path without operating head inventory. This is where I have landed for alpha.8, but I am interested in whether you see any problems with the profile split or how I have drawn the boundary between them.

The additive profile rolls payments into a reusable KIP-10 head instead of accumulating separate merchant UTXOs. Settlement recreates the same-script successor with exactly the advertised amount added. Issuing its 402 includes a challenge but does not exclusively reserve, spend or retire the head.

The transaction-level economic distinction is straightforward.

standard-native  merchant output pays exactly the advertised amount
additive         same-script successor increases by exactly that amount

Both profiles share the outer x402 flow, with separate transaction and state checks where their designs differ.

The repo is still changing heavily as I work through the design and contains substantially more implementation and test scaffolding than an upstream integration will need.

Just for context, kaspa-exact-v2 reflects the iteration history in this alpha repo. I do not think upstream needs to inherit that naming or all of the surrounding scaffolding. My current thought is to distil it into one clean Kaspa exact proposal using x402’s conventions, with batch-settlement remaining separate, but I am open to how that should ultimately be structured.

The alpha.8 exact specification reflects where the design currently stands. I’d really value feedback or anything I may have missed. :folded_hands:

3 Likes