> For the complete documentation index, see [llms.txt](https://docs.keeta.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.keeta.com/guides/using-x402-on-keeta.md).

# Using x402 on Keeta

[x402](https://www.x402.org/) is an open, HTTP-native payments standard built around the **402 Payment Required** status code. It lets any HTTP endpoint charge for access — per request, per token, per API call — without accounts, API keys, or subscription billing. A server responds `402` with machine-readable payment instructions, the client signs a payment and retries the request, and the server serves the resource once payment is confirmed.

This guide shows how to accept and make x402 payments **on Keeta**: as a client paying for a protected resource, as a server charging for one, and how the Keeta x402 facilitator verifies and settles those payments.

{% hint style="info" %}
x402 on Keeta is implemented by the `exact` payment scheme, defined in the [x402 Keeta scheme specification](https://github.com/x402-foundation/x402/blob/main/specs/schemes/exact/scheme_exact_keeta.md) and shipped as the reference [`@x402/keeta`](https://www.npmjs.com/package/@x402/keeta) package. The examples below follow the [Keeta x402 example app](https://github.com/sc4l3r/keeta-x402) developed by a community member.
{% endhint %}

## How x402 works on Keeta

Keeta's payment flow follows the general x402 pattern, with one Keeta-specific detail: instead of publishing a transaction itself, the client only **signs a block** and hands it to the resource server. The facilitator publishes it with a fee block it creates and signs itself as a single vote staple, so that the network fees are covered by the facilitator free of charge.

You can try it out yourself using the interactive demo on the [third-party Keeta x402 facilitator](https://facilitator.x402.keeta.com/).

Review the [third-party service notice](#third-party-service-notice) before using it.

{% stepper %}
{% step %}

### Client requests a resource

A client makes a normal HTTP request to a paid endpoint. No payment is attached yet.
{% endstep %}

{% step %}

### Server responds with 402

The resource server replies `402 Payment Required` with `PaymentRequirements`: `scheme` (`exact`), `network`, `asset`, `amount`, and `payTo`:

```json
{
  "x402Version": 2,
  "error": "Payment required",
  "resource": {
    "url": "https://facilitator.x402.keeta.com/weather",
    "description": "Get current weather data (demo endpoint)",
    "mimeType": "application/json"
  },
  "accepts": [
    {
      "scheme": "exact",
      "network": "keeta:1413829460",
      "amount": "1000000",
      "asset": "keeta_anyiff4v34alvumupagmdyosydeq24lc4def5mrpmmyhx3j6vj2uucckeqn52",
      "payTo": "keeta_aab7jq4fx7fl24qk36qpowlyasu3jekv4gdadrz6lhnda3n2upnj2dga7rxjf5a",
      "maxTimeoutSeconds": 300,
      "extra": {}
    },
    {
      "scheme": "exact",
      "network": "keeta:1413829460",
      "amount": "1000",
      "asset": "keeta_apna75yhhvnv4ei7ape55hndk4yepno7a7i2mhtiwahiygixjcnmvswxhnmnk",
      "payTo": "keeta_aab7jq4fx7fl24qk36qpowlyasu3jekv4gdadrz6lhnda3n2upnj2dga7rxjf5a",
      "maxTimeoutSeconds": 300,
      "extra": {}
    }
  ]
}
```

{% endstep %}

{% step %}

### Client signs a block (but doesn't publish it)

The client builds a Keeta block containing a single `SEND` operation that satisfies the server's requirements, signs it with its Keeta account, and serializes it (ASN.1 DER, Base64-encoded) into the `PaymentPayload`. It retries the request with a `PAYMENT-SIGNATURE` header carrying that payload.

```json
{
  "x402Version": 2,
  "payload": {
    "block": "MIH8AgEAAgRURVNUBQAYEzIwMjYwNzAyMTIwMTQwLjY5OVoEIgADAm6dCFFcNSQH4W8GXVEtN6TOPnKi0E8H989NDaWNL2kFAAQgJgvfwf+ZA9wHkB1phDyzxBjbk4PvTHbbtFrAfOEKqN4wUKBOMEwEIgAD9MOFv8q9cgrfoPdZeASptJFV4YYBxz5Z2jBtuqPanQwCAw9CQAQhA3CCl5XfALrRlHgMweHSwMkNcWLgyF6yL2Mwe+0+qnVKBEAGXojraVbFTUlN001p6XXlHpGeEtTsJGuPbCGWgoMLzksWivjcoyk0ZT/kaPFQICd8wa/m9jQIucYCR3B2xvZz"
  },
  "resource": {
    "url": "https://facilitator.x402.keeta.com/weather",
    "description": "Get current weather data (demo endpoint)",
    "mimeType": "application/json"
  },
  "accepted": {
    "scheme": "exact",
    "network": "keeta:1413829460",
    "amount": "1000000",
    "asset": "keeta_anyiff4v34alvumupagmdyosydeq24lc4def5mrpmmyhx3j6vj2uucckeqn52",
    "payTo": "keeta_aab7jq4fx7fl24qk36qpowlyasu3jekv4gdadrz6lhnda3n2upnj2dga7rxjf5a",
    "maxTimeoutSeconds": 300,
    "extra": {}
  }
}
```

{% endstep %}

{% step %}

### Server verifies via the facilitator

The resource server forwards the payload to the facilitator's `POST /verify`, which decodes the block and checks the signature, the operation, the amount/asset/recipient, and that the signer is authorized to send on behalf of the paying account.
{% endstep %}

{% step %}

### Facilitator settles and sponsors the fee

On `POST /settle`, the facilitator creates and signs its own fee block, collects votes from the network's representatives, and publishes the client's block together with the fee block as a single vote staple, sponsoring the fee itself. It returns a `SettlementResponse` with the transaction hash to the resource server.

```json
{
  "success": true,
  "payer": "keeta_aabqe3u5bbivynjea7qw6bs5kewtpjgohzzkfucpa7346tinuwgs62mfdqpmlsy",
  "transaction": "E247FE98A3925CB6D5D7CB8C66CE6BDE0C69646326EC3C0F60919C29528C6E99",
  "network": "keeta:1413829460"
}
```

{% endstep %}

{% step %}

### Server returns the resource

The resource server returns `200 OK` with the requested content and a settlement receipt header.

```json
{
  "report": {
    "weather": "sunny",
    "temperature": 70
  }
}
```

{% endstep %}
{% endstepper %}

{% hint style="warning" %}
Because Keeta accounts are ordered, per-account chains, a client **can't submit multiple payments from the same account in parallel**. It has to wait for each request to settle before signing the next one. Queue requests on a single account, or spread payments across multiple accounts if you need concurrency.
{% endhint %}

## Prerequisites

* A Keeta account for the paying client, and a Keeta account to receive payments on the server side
* Node.js, with the KeetaNet client SDK and the x402 packages for Keeta:

```bash
npm install @keetanetwork/keetanet-client @x402/core @x402/keeta @x402/fetch @x402/express
```

* For testnet development, fund your client account from the [testnet faucet](https://faucet.test.keeta.com/)

## Using x402 as a client

This is the "buyer" side, so an app or agent that pays to access someone else's endpoint. The example below uses fetch for payments but you can use any client the [x402 reference implementation supports](https://docs.x402.org/getting-started/quickstart-for-buyers#3-make-paid-requests-automatically) like axios.

See the full example [here](https://github.com/sc4l3r/keeta-x402/blob/main/apps/server/src/client.ts).

```typescript
import * as KeetaNet from "@keetanetwork/keetanet-client";
import { x402HTTPClient } from "@x402/core/http";
import { x402Client } from "@x402/core/client";
import { wrapFetchWithPayment } from "@x402/fetch";
import { ExactKeetaScheme, KEETA_TESTNET_CAIP2, toClientKeetaSigner } from "@x402/keeta";

// Derive the paying account. It must hold a balance of whatever asset it will pay with.
const account = KeetaNet.lib.Account.fromSeed(
  await KeetaNet.lib.Account.seedFromPassphrase(process.env.CLIENT_PASSPHRASE),
  0,
);

// toClientKeetaSigner opens a UserClient under the hood, dispose it when done via await using.
await using clientKeetaSigner = toClientKeetaSigner(account);

const client = new x402Client();
client.register(KEETA_TESTNET_CAIP2, new ExactKeetaScheme(clientKeetaSigner));

// Wrap fetch so 402 responses are handled transparently.
const fetchWithPayment = wrapFetchWithPayment(fetch, client);
const httpClient = new x402HTTPClient(client);

const response = await fetchWithPayment("https://facilitator.x402.keeta.com/weather", { method: "GET" });
const result = await httpClient.processResponse(response);

console.log("Response:", result.body);

if (result.paymentStatus === "settled") {
  console.log("Payment settled:", result.header);
} else if (result.paymentStatus === "settle_failed") {
  console.error("Settlement failed:", result.header);
}
```

`wrapFetchWithPayment` does the whole round trip: it sends the initial request, reads the `402`, signs a block with `clientKeetaSigner`, and retries with the `PAYMENT-SIGNATURE` header attached. `x402HTTPClient.processResponse` then gives you the payment status.

## Using x402 as a server

This is the "seller" side, so charging for an API route. The example below uses Express.js for the HTTP server but you can use any NodeJS framework the [x402 reference implementation supports](https://docs.x402.org/getting-started/quickstart-for-sellers#2-add-payment-middleware) like Next.js, Hono, or Fastify.

See the full example [here](https://github.com/sc4l3r/keeta-x402/blob/main/apps/server/src/main.ts).

```typescript
import express from "express";
import { x402ResourceServer, HTTPFacilitatorClient } from "@x402/core/server";
import { paymentMiddleware } from "@x402/express";
import { KEETA_TESTNET_CAIP2, KTA_TESTNET_ADDRESS } from "@x402/keeta";
import { ExactKeetaScheme } from "@x402/keeta/exact/server";

const app = express();
const payTo = process.env.SERVER_ADDRESS!; // your Keeta receiving address

// Point at the Keeta facilitator. The server trusts it to verify and settle
// correctly, so only use facilitators you trust.
// The one below is operated by the community.
const facilitatorClient = new HTTPFacilitatorClient({
  url: "https://facilitator.x402.keeta.com",
});

const server = new x402ResourceServer(facilitatorClient);
server.register(KEETA_TESTNET_CAIP2, new ExactKeetaScheme());

app.use(
  paymentMiddleware(
    {
      "GET /weather": {
        accepts: [
          {
            scheme: "exact",
            // Default unit is USDC; the token address on Keeta is derived automatically.
            price: "0.01",
            network: KEETA_TESTNET_CAIP2,
            payTo,
          },
          {
            scheme: "exact",
            // Or accept any other Keeta token directly, by asset address + raw amount.
            price: {
              asset: KTA_TESTNET_ADDRESS,
              amount: "1000", // raw units, 0.000001 KTA at 9 decimals
            },
            network: KEETA_TESTNET_CAIP2,
            payTo,
          },
        ],
        description: "Get current weather data for any location",
        mimeType: "application/json",
      },
    },
    server,
  ),
);

app.get("/weather", (req, res) => {
  res.send({ report: { weather: "sunny", temperature: 70 } });
});

app.listen(4021, () => console.log("Server listening at http://localhost:4021"));
```

A request without payment gets a `402` back with the `PaymentRequirements` above; a request from a properly configured x402 client gets a `200` with the JSON payload and a settlement receipt header.

## Fee sponsoring on the Keeta facilitator

Every settlement on Keeta's `exact` scheme is **fee-sponsored by the facilitator**. The client signs only a payment block for the exact amount owed but it never needs to build or fund a separate fee transaction.

The facilitator cannot redirect funds: it can only append its own fee block alongside the block the client already signed, so it never gains the ability to alter where the client's payment goes.

## Facilitators

The following facilitators are known to be available for use.

* Third-party operated: [https://facilitator.x402.keeta.com](https://facilitator.x402.keeta.com/) using the open-source implementation on [GitHub](https://github.com/sc4l3r/keeta-x402/tree/main/apps/facilitator).

### Third-Party Service Notice

{% hint style="warning" %}
This service is developed, operated, and maintained by an independent third party as part of the Keeta Grant Program.

Although this service is accessible through a Keeta-owned subdomain, it is not operated by Keeta, Inc. The use of a Keeta subdomain does not constitute an endorsement of the service or its operator.

Keeta does not control or assume responsibility for the service's operation, availability, content, security, or compliance.

Your use of this service is at your own risk and is subject to the terms and privacy policy provided by the third-party operator, where applicable.
{% endhint %}

## Further reading

* [Keeta x402 example repo](https://github.com/sc4l3r/keeta-x402): full client, server, and facilitator example apps
* [x402 Keeta `exact` scheme specification](https://github.com/x402-foundation/x402/blob/main/specs/schemes/exact/scheme_exact_keeta.md): protocol sequence, payload formats, verification and settlement rules
* [`@x402/keeta` on npm](https://www.npmjs.com/package/@x402/keeta)
* [x402 buyer quickstart](https://docs.x402.org/getting-started/quickstart-for-buyers.md), [x402 seller quickstart](https://docs.x402.org/getting-started/quickstart-for-sellers.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.keeta.com/guides/using-x402-on-keeta.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
