Kaspa x402

Kaspa x402 Binding v1

Status: draft

This document defines common rules for x402 v2 payments on Kaspa. Active scheme-specific behavior is defined in sibling documents:

x402 Relationship

x402 separates the logical payment scheme from the network-specific implementation. Kaspa x402 recognizes the following draft (scheme, network) identifier pairs:

exact              + kaspa:mainnet
exact              + kaspa:testnet-10
batch-settlement   + kaspa:mainnet
batch-settlement   + kaspa:testnet-10

Servers may advertise more than one option in PaymentRequired.accepts. Clients choose the entry they can satisfy. A PaymentRequired.accepts array from an upstream x402 server may also contain entries for schemes, networks, or assets outside this binding. Kaspa clients must not reject the envelope because such entries are present: they must skip entries that do not validate as Kaspa requirements during offer selection and fail with invalid_kaspa_x402_accepted only when no supported Kaspa entry remains. Kaspa servers, in contrast, must emit only entries defined by this binding. In the current alpha, kaspa:testnet-10 is the testnet validation target and kaspa:mainnet is a reserved profile name that requires explicit runtime opt-in plus the mainnet gates in docs/mainnet-readiness.md.

Scheme Selection

SchemeUse whenSettlement
exactThe price is known before the request. Example: buy a file or one fixed-price API result.One immediate native KAS transfer for the exact amount.
batch-settlementThe client expects repeated or variable-cost requests against the same service. Example: API metering or MCP tool usage.Per-request commitments accumulate and value is redeemed later.

The active schemes are intentionally separate. batch-settlement can represent one request, but it does not have the same x402 contract as exact.

x402 Version

Kaspa x402 v1 targets x402 v2 request envelopes.

Every PaymentRequired and PaymentPayload must use:

{
  "x402Version": 2
}

Implementations must reject unsupported x402 versions on request envelopes. SettlementResponse follows the upstream x402 v2 response schema and does not carry x402Version.

Networks

Initial network identifiers:

kaspa:mainnet
kaspa:testnet-10

The kaspa: namespace is CAIP-style but not yet a formal registry claim. Formal registry work is deferred until the binding is stable enough to submit upstream.

Implementations must reject non-colon network aliases such as mainnet, testnet-10, tn10, and any other non-listed network value.

Asset and Amounts

asset is "KAS" for native Kaspa in this draft. This is a proposed native asset convention, not a final registry decision.

All x402 amount fields are decimal strings in atomic sompi units:

{
  "asset": "KAS",
  "amount": "1000000"
}

This includes top-level amount, voucher amounts, funding amounts, charged amounts, claim amounts, and refund amounts unless a field explicitly says otherwise.

Amount and DAA-height strings are canonical unsigned 64-bit decimal strings. They must be "0" or a non-zero digit followed by digits, with no leading zeroes, and their numeric value must not exceed 18446744073709551615.

Display layers may show KAS or tKAS. Wire fields must not use floating point KAS values.

The optional metadata fields below may be included in extra for clarity, but clients must not require them to understand native KAS:

{
  "assetKind": "native",
  "assetDecimals": 8
}

Common Wire Encoding

Unless a scheme document overrides a rule:

Common PaymentRequirements Rules

Every Kaspa x402 PaymentRequirements object must use:

{
  "network": "kaspa:testnet-10",
  "asset": "KAS",
  "amount": "<decimal sompi string>",
  "payTo": "<kaspa address>",
  "maxTimeoutSeconds": 60
}

extra.binding identifies the concrete Kaspa binding:

Schemeextra.binding
exactkaspa-exact-v1
batch-settlementkaspa-escrow-v1

Unknown extra fields may be preserved by transports, but verifiers must ignore unknown fields unless the selected binding explicitly marks them as critical.

Example Accepts Array

{
  "x402Version": 2,
  "resource": {
    "url": "https://api.example.com/report.pdf",
    "description": "Research report",
    "mimeType": "application/pdf"
  },
  "accepts": [
    {
      "scheme": "exact",
      "network": "kaspa:testnet-10",
      "amount": "25000000",
      "asset": "KAS",
      "payTo": "kaspatest:...",
      "maxTimeoutSeconds": 60,
      "extra": {
        "binding": "kaspa-exact-v1",
        "finality": "accepted"
      }
    },
    {
      "scheme": "batch-settlement",
      "network": "kaspa:testnet-10",
      "amount": "25000000",
      "asset": "KAS",
      "payTo": "kaspatest:...",
      "maxTimeoutSeconds": 60,
      "extra": {
        "binding": "kaspa-escrow-v1",
        "templateId": "kaspa-x402-escrow-v1",
        "serverPublicKey": "<32-byte x-only hex>",
        "minDepositSompi": "100000000",
        "refundTimeoutDaa": "123456789"
      }
    }
  ]
}

Idempotency

Kaspa x402 implementations should support the x402 payment-identifier extension.

For paid retries, the server should bind the payment identifier to a normalized request fingerprint:

When a challenge advertises the payment-identifier extension, the retry payload must echo the advertised extension schema and preserve every advertised info field. The client may add the retry id and other schema-allowed fields, but it must not strip server-provided metadata such as tenant, route, or policy fields.

Scheme-specific replay protection still applies even when payment-identifier is absent.

Offer and Receipt Extension

The x402 offer and receipt extension is optional in v0.1 and recommended for mainnet-facing services.

For non-EVM Kaspa services, JWS is the preferred signing format for service offers and receipts. The receipt should be included at:

SettlementResponse.extensions["offer-receipt"].info.receipt

Receipts should bind:

SettlementResponse Conventions

For exact, a successful SettlementResponse.transaction is the Kaspa transaction id that moved value for the request.

For batch-settlement, a voucher-only success may have:

{
  "transaction": "<commitment id hex>",
  "amount": "<actual charge>",
  "extensions": {
    "kaspa": {
      "commitmentId": "<commitment id hex>",
      "chargedAmount": "<actual charge>"
    }
  }
}

For batch voucher-only settlement, transaction is the non-empty commitment id, top-level amount is the actual request charge, and extension metadata is carried in extensions.kaspa.

For deposit-voucher, top-level amount is the actual resource charge. Escrow funding is not reported as top-level amount; it is reported in extensions.kaspa.fundingAmount.

Toccata Alignment

Kaspa x402 must be designed as a UTXO-native protocol, not as an account-contract API.

For covenant-backed bindings:

The initial architecture should prefer L1 covenant lanes for escrow and channel state because these states naturally split by payer, service, and session. A based-app model is out of scope for v0.1 unless future shared-state requirements dominate.

Common Security Requirements

Implementations must:

Registry Status

The binding is not yet registered with x402 or CAIP registries. This is not a v0.1 blocker. Before a tagged v1.0.0, the project should submit or align with the upstream registry process for:

References

Source: /spec/kaspa-x402-v1.md