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.
19 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:

4 Likes

Thanks. I really appreciate how quickly and thoroughly you turned this around.

I’ve been working on a Rust implementation of the v2 binding (server/facilitator side — very much in progress), deliberately from the spec text alone rather than the TypeScript packages, since that seemed like the most useful way to test the spec as a spec. A few places where I got stuck or wasn’t sure I was reading things correctly. Quite possibly these are my misreadings, so please correct me where I’m wrong:

1. Recomputing the transaction id and authorization digest. This is the one place my implementation is currently stuck at a structural check rather than full cryptographic verification. I couldn’t find a normative definition of kaspa-sdk-safe-json-v2.0.0 beyond the name (the schema types transaction as an opaque string), and the exact-profile vectors pin the expected transactionIds — a great end-to-end check — but don’t carry a serialized hash-preimage the way the tx-v1 batch vectors do. The request-authorization digest is the same: the fixture ships the final digest and signature but no preimage, and the general digest conventions in kaspa-x402-v1.md (UTF-8 strings, _le64 concatenation) appear not to apply here — as far as I can tell from exact-authorization.ts, the actual construction is SHA-256 over key-sorted canonical JSON. Is that reading correct? For now my verifier enforces the authorization structurally (version, digest/signature shapes, expiry) because I can’t recompute the digest independently. If preimage fixtures or a short digest-layout section (like the batch profile already has) were ever added, I’d wire them in the same day — and I’d gladly draft that text for your review if it would save you time.

2. Expiry relationships. I wasn’t sure what I should enforce among maxTimeoutSeconds, challengeExpiresAt, and authorization.expiresAt — each has a per-field constraint, but I couldn’t find ordering rules between them or which side (server vs facilitator vs adapter) is meant to check which. I ended up inventing local rules (e.g. authorization.expiresAt ≤ challengeExpiresAt, both within the offer window) and I’m not confident they match your intent. Is there an intended relationship, or is this deliberately left open?

3. Finality numbers. Is there a confirmation depth you’d recommend coding an adapter against for accepted/confirmed, or is that intentionally left to adapter policy for now? Completely understandable at alpha stage — I’m mostly asking so my adapter doesn’t bake in a wrong assumption before mainnet-readiness discussions happen.

4. Additive external-advance and retry policy. One scenario I couldn’t convince myself was harmless — though I may well be missing a mitigation you already have in mind. Since anyone can advance a head by its threshold (0.1 KAS at the spec’s example and the reference deployment’s value, paid to the merchant), it looks to me like a third party could repeatedly stale the expected head transition for every in-flight payer, and with maxPaymentRetries: 0 each affected payer would need a fresh explicit wallet authorization each round. Is the intended answer per-client or auth-gated additive offers, or is standard-native-as-fallback considered sufficient here? If it’s the former, it might be worth a line in the threat model.

I’ll file interop reports through the templates as the Rust implementation progresses.

3 Likes

Hey mate, I’ve been working on something similar and have already deployed a mainnet proof of concept. If you want to join forces, my github repo is open at GitHub - Kali123411/kaspa-402: k402 service exchange — agent-payable services on Kaspa (kaspa-402.org) · GitHub It’s an open marketplace where anyone can register their endpoints and get paid in Kaspa. Live at https://www.kaspa-402.org/

2 Likes

Thanks for sharing. I had a look through both repos. k402 appears to be a separate protocol built around HTTP 402 rather than an implementation of x402-foundation/x402. It seems to use its own wire format, headers, schemes and payment lifecycle, so it is not compatible with existing x402 clients or facilitators.

My work is specifically focused on creating a Kaspa binding for the existing x402 v2 standard, so I do not think combining the projects would make sense. Best of luck with the marketplace.

1 Like

Hello…

We’re building Vida — an agentic wallet for Kaspa that handles session-gated spending, SilverScript covenants, and MCP-compatible agent tools. x402 is exactly the payment protocol this stack needs.

On the identifier convention: kaspa:mainnet and kaspa:testnet-10 are the right choices. They match what RK, explorers, and wallets already use. No objections here.

On the address prefix: Worth making explicit in the spec text that the address is included without its kaspa:/kaspatest: prefix, since the identifier already names the network. A clear example would prevent a common bug class.

Offer to test: We’d like to be an early external implementer. We have a working agent loop, session-gated policy enforcement, and a SilverScript module. The exactscheme maps naturally to session caps. We’ll test against the live gateway and report what breaks.

On the facilitator model: For agents that don’t manage their own Kaspa wallets, could a third party run as an x402 facilitator — handling session-gated signing and broadcast on their behalf? Our MCP server already exposes agent tools to Claude Desktop, Cursor, and Grok Build. Extending that to x402 facilitation seems like a natural path for agent adoption.

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

2 Likes

Thanks for checking it out. And you’re right, k402 was built with covenants in mind (Kaspa native) which will not be possible within constraints of the x402 model and schemes. Moving forward I plan to add the x402 compatibility layer on top of the existing k402 protocol.

This is factually incorrect. Nothing in x402 prevents the use of covenants. x402 is the protocol and lifecycle that a network binding aligns with. The settlement mechanism itself can be network-specific.

The proof is already in my implementation. It uses a SilverScript covenant for batch settlement and optionally uses KIP-10 for exact payments, all within the x402 v2 model.

I would suggest doing more research into what x402 actually defines. Creating different headers, wire formats, schemes and payment lifecycles does not extend x402. It creates another incompatible protocol.

Without a clear requirement that x402 cannot support, that simply adds fragmentation and confusion, with no interoperability with existing x402 clients or facilitators and no direct path into the emerging standard.

1 Like

Hmm clear path into the emerging standard sounds like shaky ground to me. But I agree, no reason to reinvent the wheel here.

1 Like

Thanks again @Ross . I dug into the points you raised over the weekend and you’re right - there were quite a few gaps in my doco. I’ve gone back through the exact binding in particular and updated the spec (and batch too) so they should stand independently from TS.

kaspa-sdk-safe-json-v2.0.0 is only the interchange envelope. Transaction IDs are calculated from the normalised Kaspa consensus fields, not the JSON bytes or key order. The authorisation digest is SHA-256 over recursively key-sorted canonical JSON.

The new exact interop vector includes both transaction profiles, canonical UTF-8 preimages, digests, public key, signature and expected transaction IDs.

On expiry, I overlooked this. I was checking the individual timestamps, but I had not fully accounted for an authorisation expiring while tx verification was still running.

I have now made the ordering explicit. The authorisation must still be valid, must not exceed now + maxTimeoutSeconds, and for additive it must not outlive the challenge. The implementation now checks this before protected work and again after any awaited verification.

accepted is the alpha interoperability baseline and means accepted chain state under the configured trusted-node policy, not mempool presence. confirmed remains adapter policy for now. An adapter offering it must document and consistently enforce its stronger depth, time or virtual-chain rule.

On additive, you are right. Anyone being able to advance the head is a known property of KIP-10’s public borrower branch, but I had not properly documented what that means for an in-flight x402 payment. Alpha.9 now calls this out and covers the mitigations, including multiple head shards, sensible thresholds, reconciliation and standard-native fallback. Additive remains optional, and a stale replacement still requires fresh wallet approval.

The updated alpha.9 exact specification now documents all of this.

I would really appreciate it if you could point the Rust implementation at alpha.9 and let me know whether anything still requires reading the TypeScript. LMK how you go!

4 Likes

Thanks @elldeeone

and that was fast. I pointed a Rust implementation at alpha.9 over the weekend.

To your question: for exact I didn’t have to fall back to the TypeScript at all — the vector was enough to reproduce everything I needed (both transaction-id constructions, the v1 computeBudget handling, the string-encoded uint64s, storageMass). That was the piece I’d been missing, so thank you.

One thing I want to make sure I’m reading right: is successor-delta-only locked for additive in alpha.9, or still in flux? Just don’t want to build against a shape that’ll move.

Separately — and I’m probably getting ahead of the roadmap — I’ve been putting the same flow through a full stablecoin (covenant token) on the side, and two of the native model’s assumptions didn’t carry over. First, reaching accepted doesn’t mean the recipient has unconditional custody once the issuer keeps freeze/seize authority — a different axis from chain finality. Second, the authorization digest assumes a single P2PK signer at inputIndex; when a script authorizes the transfer, there may not be one. Tokens are out of scope for alpha.9, so nothing needed here — just flagging in case it’s useful when the covenant binding comes around.

Thanks again !

One thing worth separating first: interop here doesn’t mean a Base or Solana client settles a payment on Kaspa — it can’t, it holds no KAS. Interoperability means everyone speaks the same wire format: the 402 response shape, the accepts[ ] array, the header names and the request → 402 → pay → retry lifecycle, and the discovery format. A generic x402 v2 client, facilitator or indexer can then parse and route a Kaspa offer even though the signing happens through a Kaspa-aware signer.

Our gateway already sits inside that envelope — it’s built on the @kaspa-x402 binding and emits a standard x402 v2 offer. A decoded PAYMENT-REQUIRED from it:

{“x402Version”:2,“accepts”:[{“scheme”:“exact”,“network”:“kaspa:mainnet”,“asset”:“KAS”,“payTo”:“kaspa:qzws…”,“maxTimeoutSeconds”:300,“extra”:{“binding”:“kaspa-exact-v2”,“profile”:“standard-native”,“finality”:“accepted”,“transactionEncoding”:“kaspa-sdk-safe-json-v2.0.0”}}]}

Any x402 v2 parser reads that today. From there, interop is concrete:

  • A resource can advertise multiple accepts[ ] entries in one 402 — Base-USDC, Solana-USDC, Kaspa-KAS — and each client picks the rail it can settle. One endpoint, every chain.
  • x402 discovery/indexers can list the Kaspa offer alongside the rest.
  • For agents that don’t hold a KAS wallet, a third party can run as an x402 facilitator that verifies/settles KAS (covenants, session-gated signing) on their behalf — the standard facilitator model, and the natural home for Kaspa-specific settlement. @VidaWallet — that’s a direct yes to your question: session-gated signing + broadcast behind a facilitator is exactly the pattern, and an agentic wallet like Vida is a natural fit to run one.

The true gap is that no mainstream client settles KAS yet, so today that’s @kaspa-x402/client or KAS support added upstream. The way we close it is the network-binding path — getting Kaspa recognized as an x402 network — not a parallel protocol. We’re conforming, not extending. If anyone hits a concrete requirement x402 genuinely can’t express, that’s the thing to surface specifically, and I’d like to hear about it.

1 Like