# x402 reference

> Limits, packages, facilitator URLs, API key scopes, buyer clients, /settle responses and every reason code of the Cryptonly x402 facilitator.

## Limits

| Limit | Value |
| --- | --- |
| Smallest payment | 0.005 of any token |
| `maxTimeoutSeconds` | 1 to 3600 |
| `/verify` | 600 requests per minute per account |
| `/settle` | 300 requests per minute per account |

Requests over the rate limits get HTTP `429`.

## Packages

The official packages send your API key and pick the facilitator URL for you.

  <ExternalLinkCard title="@cryptonly/x402-express" href="https://www.npmjs.com/package/@cryptonly/x402-express" icon="npm" description="Express middleware with prices from the dashboard." />
  <ExternalLinkCard title="@cryptonly/x402-fastify" href="https://www.npmjs.com/package/@cryptonly/x402-fastify" icon="npm" description="Fastify plugin with prices from the dashboard." />
  <ExternalLinkCard title="@cryptonly/x402-nestjs" href="https://www.npmjs.com/package/@cryptonly/x402-nestjs" icon="npm" description="NestJS module and @X402() decorator, on the Express or Fastify platform." />
  <ExternalLinkCard title="@cryptonly/x402" href="https://www.npmjs.com/package/@cryptonly/x402" icon="npm" description="Node.js. A facilitator client for @x402/express, @x402/fastify, @x402/hono and @x402/next, with prices in code." />
  <ExternalLinkCard title="cryptonly-x402" href="https://pypi.org/project/cryptonly-x402/" icon="pypi" description="Python. Facilitator clients for FastAPI and Flask, with prices in code." />

Source code: [cryptonly-net/x402](https://github.com/cryptonly-net/x402) on GitHub.

### Other x402 clients

Any x402 facilitator client works. Point it at the facilitator URL and send your API key in the `x-tenant-api-key` header.

```
https://api-merchant.cryptonly.net/x402
```

In the sandbox: `https://sandbox-api-merchant.cryptonly.net/x402`.

## API key scopes

An x402 key can only call x402 endpoints. It can't create invoices or withdrawals, so it's safe to keep on the server that sells your API.

| Scope | Allows |
| --- | --- |
| `x402.verify` | `POST /x402/verify`, `GET /x402/supported` and `GET /x402/config` |
| `x402.settle` | `POST /x402/settle` |
| `x402.list` | `GET /x402/settlements` and `GET /x402/settlements/{id}` |

## Buyer clients

The [quickstart](https://docs.cryptonly.net/guides/x402/quickstart.md) pays with TypeScript. The same call in Python and Go:

<IconTabs>
<IconTab label="Python" icon="python">

```bash
pip install "x402[httpx,evm]"
```

```python

from eth_account import Account
from x402 import x402Client
from x402.http.clients import wrapHttpxWithPayment
from x402.mechanisms.evm.exact import register_exact_evm_client
from x402.mechanisms.evm.signers import EthAccountSigner

client = x402Client()
register_exact_evm_client(client, EthAccountSigner(Account.from_key(os.environ["BUYER_PRIVATE_KEY"])))

async def main():
    async with wrapHttpxWithPayment(client) as http:
        response = await http.get("http://localhost:4021/v1/weather/paris")
        print(response.status_code, response.json())

asyncio.run(main())
```

</IconTab>
<IconTab label="Go" icon="go">

```bash
go get github.com/x402-foundation/x402/go
```

```go
package main

	"fmt"
	"io"
	"net/http"
	"os"

	x402 "github.com/x402-foundation/x402/go"
	x402http "github.com/x402-foundation/x402/go/http"
	evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client"
	evmsigners "github.com/x402-foundation/x402/go/signers/evm"
)

func main() {
	signer, err := evmsigners.NewClientSignerFromPrivateKey(os.Getenv("BUYER_PRIVATE_KEY"))
	if err != nil {
		panic(err)
	}
	client := x402.Newx402Client().Register("eip155:*", evm.NewExactEvmScheme(signer, nil))
	pay := x402http.WrapHTTPClientWithPayment(http.DefaultClient, x402http.Newx402HTTPClient(client))

	resp, err := pay.Get("http://localhost:4021/v1/weather/paris")
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	body, _ := io.ReadAll(resp.Body)
	fmt.Println(resp.StatusCode, string(body))
}
```

</IconTab>
</IconTabs>

## Settle responses

`/settle` sends the payment to the network and waits a few seconds for it to land in a block.

| Result | Response |
| --- | --- |
| Landed | `success: true` and the transaction hash. The buyer gets the response. |
| Not landed yet | `success: false`, `errorReason: settlement_pending` and the transaction hash. See [below](#pending-payments). |
| Refused | `success: false` and a [reason code](#reason-codes). Nothing is sent and no fee is charged. |

A successful response includes the expected fee in `extra.feeAtomic`, in the smallest unit of the token at `extra.feeAsset`. It's `0` within the free tier. The fee actually charged is on the payment and in its webhook.

Retries are safe. Sending the same signed payment again returns the original transaction and sends nothing new.

After the response, the payment becomes `confirmed`, `credited` or `failed`. See [Statuses](https://docs.cryptonly.net/guides/x402/payments-and-webhooks.md#statuses).

### Pending payments

`settlement_pending` means the payment was sent but hadn't landed when `/settle` answered. It usually lands a moment later. Stock x402 middleware still treats it as a failure and doesn't return your response to the buyer. Its final status shows up on the **Payments** tab and in [webhooks](https://docs.cryptonly.net/guides/x402/payments-and-webhooks.md#webhooks).

## Reason codes

`/verify` and `/settle` return failures as HTTP `200` with a reason, as the x402 specification requires. On top of the standard x402 reasons, Cryptonly uses these:

| Reason | What happened | What to do |
| --- | --- | --- |
| `settlement_disabled` | Your account is waiting for business verification, is suspended, or settlement is paused. | Finish business verification. Otherwise contact support. |
| `pay_to_rejected` | `payTo` isn't one of your wallets or your settlement address. | Use an address from **Settings → Payouts**. |
| `fee_balance_insufficient` | Your x402 credits don't cover the fee. | [Top up credits](https://docs.cryptonly.net/guides/x402/payouts-and-fees.md#x402-credits) or turn on auto top-up. |
| `compliance_rejected` | The buyer or `payTo` failed sanctions screening, or screening was unavailable. | Contact support if you think this is a mistake. |
| `authorization_already_used` | This signed payment was already settled. | Nothing. The buyer needs to sign a new payment. |
| `permit2_allowance_required` | The buyer paid through Permit2 without approving it for the token. | The buyer approves Permit2 for the token. |
| `settlement_pending` | Sent, but not in a block yet. | See [Pending payments](#pending-payments). |
| `invalid_exact_svm_recipient_token_account_missing` | Solana: your wallet has no token account for this token. | Send the token to your wallet once. See [Solana wallets](https://docs.cryptonly.net/guides/x402/payouts-and-fees.md#solana-wallets). |
| `invalid_exact_svm_recipient_token_account_frozen` | Solana: the token issuer froze your token account. | Use another wallet. |
| `invalid_exact_svm_recipient_token_account_invalid` | Solana: your token account's address holds something else. | Use another wallet. |
| `gas_ceiling_exceeded`, `gas_budget_exhausted`, `tenant_gas_budget_exhausted`, `fee_payer_reserve_low`, `fee_payer_busy` | Cryptonly hit a limit on the network fees it pays, or is busy. | Try again later. Daily limits reset at 00:00 UTC. |

Something not covered here? Write to **support@cryptonly.net**.
