# Pay with x402 (for agents) Fluence accepts balance top-ups over the [x402 protocol](https://www.x402.org/). An HTTP client pays USDC on Base, and Fluence credits the amount to a balance in the same request. The paying wallet is the account, so the client needs no signup, email, or visit to the Fluence Console. An AI agent or a script works with Fluence in four steps: 1. Top up the balance with USDC through x402. The first payment from a wallet creates a Fluence account for that wallet. 2. Sign in with the same wallet (Sign-In with Ethereum) to get an access token. 3. Call the Fluence API with that token, or create an API key with it. 4. Rent compute with the balance. ## Requirements - An EVM wallet controlled by a private key (an externally owned account). Smart-contract wallets cannot sign in. - USDC on Base mainnet: network `eip155:8453`, token `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`. You don't need ETH for gas. The x402 facilitator submits the transfer. - An x402 v2 client. The `@x402/*` packages (`@x402/fetch` or `@x402/axios`, with `@x402/evm` for EVM payments) speak v2. The unscoped `x402-fetch` and `x402-axios` packages are the older v1 line and cannot read the Fluence payment challenge. The examples are JavaScript modules for Node.js 20 or later. Install the packages they use: ```sh npm install @x402/fetch @x402/evm viem ``` Save an example as a `.mjs` file and run it with `node`. Pass the wallet key in the `EVM_PRIVATE_KEY` environment variable. ## Limits | Parameter | Value | |-----------|-------| | Minimum top-up | 10 USD | | Maximum top-up | 1000 USD per request | | Precision | Whole cents, at most two decimal places | 1 USDC is credited as 1 USD. ## Endpoints Base URL: `https://api.fluence.dev` | Method | Path | Credentials | What it does | |--------|------|------|-------------| | `GET` | `/v2/x402/payment-info?amountUsd=N` | None | Returns the x402 payment challenge for `N` USD without paying | | `POST` | `/v2/x402/top-up?amountUsd=N` | Optional | Without a payment, answers `402 Payment Required`. With a payment, settles it and credits `N` USD. | | `GET` | `/v1/auth/siwe/nonce` | None | Issues a single-use sign-in nonce | | `POST` | `/v1/auth/siwe` | None | Exchanges a signed Sign-In with Ethereum message for an access token | | `GET` | `/v3/account/balances` | Access token or API key | Returns your balance | | `GET` | `/v3/top-ups` | Access token or API key | Lists your top-ups, including x402 ones | | `GET` | `/v3/account` | Access token or API key | Returns your account and its `permissions` | | `POST` | `/v3/api-keys` | Access token or API key | Creates an API key | The x402 and sign-in endpoints are not in the [API reference](https://api.fluence.dev/scalar). This page is their documentation. The reference covers the `/v3/...` endpoints. ## Step 1: Top up Wrap `fetch` with an x402 client and call the top-up endpoint. The client handles the exchange: it gets the `402` challenge, signs the payment, and sends the request again. ```js import { wrapFetchWithPaymentFromConfig } from "@x402/fetch"; import { ExactEvmScheme } from "@x402/evm"; import { privateKeyToAccount } from "viem/accounts"; const account = privateKeyToAccount(process.env.EVM_PRIVATE_KEY); const fetchWithPayment = wrapFetchWithPaymentFromConfig(fetch, { schemes: [{ network: "eip155:8453", client: new ExactEvmScheme(account) }], // @x402/fetch refuses to pay more than $1 per payment unless you raise the cap. spendControls: { maxAmountPerPayment: "$10" }, }); const response = await fetchWithPayment( "https://api.fluence.dev/v2/x402/top-up?amountUsd=10", { method: "POST" }, ); console.log(response.status, await response.json()); ``` Set `maxAmountPerPayment` to at least the amount you top up. With the default cap of `$1`, the client refuses to sign, and nothing is paid. A successful top-up returns `200`: ```json { "amountUsd": "10", "network": "eip155:8453", "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "transaction": "0x…", "payer": "0x…" } ``` `transaction` is the Base transaction hash, and `amountUsd` is a decimal string. The `PAYMENT-RESPONSE` header carries the x402 settlement response. Other responses: | Status | Meaning | What to do | |--------|---------|------------| | `400` | The amount is out of range or has more than two decimal places, or the payment is malformed | Fix the request | | `402` | Payment required, or the payment was rejected, for example because the wallet has too little USDC. The `error` field of the challenge says why. | Fix the cause and pay again | | `409` | The payment was submitted and is under review | Do not sign a new payment: the transfer may already be on chain. Contact support@fluence.ai with the payer address. | | `503` | Top-ups are unavailable, or the payment did not reach the facilitator. Nothing was charged. | Retry later | :::tip If you already have a Fluence account, send your API key in the `X-API-KEY` header, or an access token in `Authorization: Bearer`, with the top-up request. Fluence then credits that account instead of a wallet account. ::: ## Step 2: Sign in with the wallet Request a nonce, sign a [Sign-In with Ethereum](https://eips.ethereum.org/EIPS/eip-4361) message with the wallet that paid, and exchange it for an access token. ```js import { privateKeyToAccount } from "viem/accounts"; import { createSiweMessage } from "viem/siwe"; const account = privateKeyToAccount(process.env.EVM_PRIVATE_KEY); const { nonce } = await (await fetch("https://api.fluence.dev/v1/auth/siwe/nonce")).json(); const message = createSiweMessage({ domain: "api.fluence.dev", address: account.address, uri: "https://api.fluence.dev", version: "1", chainId: 8453, nonce, }); const signature = await account.signMessage({ message }); const login = await fetch("https://api.fluence.dev/v1/auth/siwe", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ message, signature }), }); const { accessToken, userData } = await login.json(); ``` - The message `domain` must be exactly `api.fluence.dev`. The API rejects any other domain. - A nonce works once and expires 10 minutes after it is issued. The nonce response has the time in `expiresAt`. - Send the message exactly as signed. - `userData` holds the account `id` and a placeholder email `wallet-
@x402.invalid`. The wallet address is the identity of the account. The access token expires after a few minutes. The response also has a `refreshToken`, but the public API has no endpoint that accepts it. When the access token expires, sign in again, or [create an API key](#create-an-api-key) once and use it instead. ## Step 3: Use the API Send the access token as a bearer token. For example, check the balance: ```sh curl https://api.fluence.dev/v3/account/balances \ -H "Authorization: Bearer