# x402 Protocol

x402 is an open payment standard for machine-to-machine transactions. It allows an AI agent to pay for a resource at request time, without a credit card, OAuth token, or pre-negotiated contract.

HelmutPay implements x402 natively. Solana accounts for approximately 65% of all x402 transactions on the internet. When your agent makes a request to an x402-enabled API, it can handle the payment automatically using the HelmutPay HTTP API.

## How it works

The x402 flow is based on the HTTP `402 Payment Required` status code. When an agent requests a paid resource:

1. **Initial request.** The agent makes a standard HTTP request to the resource.
2. **402 response.** The server responds with `402 Payment Required` and a payment descriptor in the response body. The descriptor specifies the amount, currency, and recipient.
3. **Automatic payment.** Your code reads the payment descriptor, checks it against the agent's spending policy, and — if approved — submits a USDC transfer to HelmutPay.
4. **Proof header.** Once the payment confirms, your code retries the original request with an `X-Payment` header containing the Solana transaction signature.
5. **Resource delivered.** The server verifies the payment proof and delivers the requested resource.

The entire flow, from 402 response to resource delivery, typically completes in under one second.

## Handling x402 in your HTTP client

Detect 402 responses, parse the payment descriptor, call HelmutPay to submit payment, then retry with the proof.

{% tabs %}
{% tab title="TypeScript" %}

```typescript
import axios from "axios";

const HELMUT_API_KEY = process.env.AGENT_API_KEY;

async function fetchWithX402(url: string): Promise<any> {
  try {
    return (await axios.get(url)).data;
  } catch (err: any) {
    if (err.response?.status !== 402) throw err;

    const descriptor = err.response.data.payment;

    // Submit payment via HelmutPay
    const paymentRes = await axios.post(
      "https://api.helmutpay.com/v1/transfers",
      {
        to: descriptor.recipient,
        amount: descriptor.amount,
        currency: descriptor.currency ?? "USDC",
        confidential: true,
      },
      {
        headers: {
          Authorization: `Bearer ${HELMUT_API_KEY}`,
          "Content-Type": "application/json",
        },
      },
    );

    const signature = paymentRes.data.signature;

    // Retry with payment proof
    return (await axios.get(url, { headers: { "X-Payment": signature } })).data;
  }
}

const result = await fetchWithX402("https://api.example.com/search?q=solana");
```

{% endtab %}

{% tab title="Python" %}

```python
import os
import requests

HELMUT_API_KEY = os.environ["AGENT_API_KEY"]

def fetch_with_x402(url: str) -> dict:
    resp = requests.get(url)

    if resp.status_code != 402:
        resp.raise_for_status()
        return resp.json()

    descriptor = resp.json()["payment"]

    # Submit payment via HelmutPay
    payment_resp = requests.post(
        "https://api.helmutpay.com/v1/transfers",
        headers={
            "Authorization": f"Bearer {HELMUT_API_KEY}",
            "Content-Type": "application/json",
        },
        json={
            "to": descriptor["recipient"],
            "amount": descriptor["amount"],
            "currency": descriptor.get("currency", "USDC"),
            "confidential": True,
        },
    )
    signature = payment_resp.json()["signature"]

    # Retry with payment proof
    return requests.get(url, headers={"X-Payment": signature}).json()

result = fetch_with_x402("https://api.example.com/search?q=solana")
```

{% endtab %}
{% endtabs %}

## Payment evaluation

Before paying a 402 response, check the payment descriptor against the agent's spending policy. If the payment would violate the policy, raise an error rather than paying.

```typescript
async function fetchWithX402(url: string, maxAmountUsdc = 0.10): Promise<any> {
  try {
    return (await axios.get(url)).data;
  } catch (err: any) {
    if (err.response?.status !== 402) throw err;

    const descriptor = err.response.data.payment;

    if (parseFloat(descriptor.amount) > maxAmountUsdc) {
      throw new Error(`Payment blocked: ${descriptor.amount} USDC exceeds limit of ${maxAmountUsdc}`);
    }

    // ... submit payment and retry
  }
}
```

## Manual x402 payments

Parse the 402 response body to inspect the payment descriptor before deciding whether to pay:

```typescript
// Parse the 402 response
const descriptor = response.data.payment;

console.log(descriptor.amount);    // "0.05"
console.log(descriptor.currency);  // "USDC"
console.log(descriptor.recipient); // "7xKp..."

// Decide whether to pay
if (parseFloat(descriptor.amount) <= 0.10) {
  const paymentRes = await axios.post(
    "https://api.helmutpay.com/v1/transfers",
    {
      to: descriptor.recipient,
      amount: descriptor.amount,
      currency: descriptor.currency,
      confidential: true,
    },
    { headers: { Authorization: `Bearer ${HELMUT_API_KEY}`, "Content-Type": "application/json" } },
  );

  // Retry with proof
  const result = await axios.get(url, {
    headers: { "X-Payment": paymentRes.data.signature },
  });
}
```

## Building an x402-enabled API

If you are building a service that AI agents will pay to use, you can add x402 support to your API.

When a request arrives without payment (or with an invalid payment), return:

```http
HTTP/1.1 402 Payment Required
Content-Type: application/json
X-Payment-Descriptor: <descriptor>

{
  "error": "payment_required",
  "message": "This endpoint requires a payment of 0.05 USDC",
  "payment": {
    "amount": "0.05",
    "currency": "USDC",
    "recipient": "YOUR_SOLANA_ADDRESS",
    "network": "solana-mainnet",
    "description": "Search query — 1 result page"
  }
}
```

When the retry arrives with an `X-Payment` header, verify the Solana transaction signature on-chain and serve the response. Verification only requires a Solana RPC endpoint — look up the transaction by signature and confirm the transfer amount and recipient match the descriptor.

```typescript
app.get("/search", async (req, res) => {
  const paymentHeader = req.headers["x-payment"];

  if (!paymentHeader) {
    return res.status(402).json({ payment: paymentDescriptor });
  }

  // Verify the Solana transaction signature on-chain
  const connection = new Connection("https://api.mainnet-beta.solana.com");
  const tx = await connection.getTransaction(paymentHeader, { commitment: "confirmed" });

  if (!tx || !isValidPayment(tx, { amount: "0.05", recipient: process.env.MY_SOLANA_ADDRESS })) {
    return res.status(402).json({ error: "invalid_payment" });
  }

  res.json({ results: [...] });
});
```


---

# Agent Instructions: 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:

```
GET https://docs.helmutpay.com/agent-payments/x402.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
