# 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 " ``` `GET /v3/top-ups` lists your top-ups, including the x402 ones. ### Create an API key A long-running agent can create an API key once and send it in the `X-API-KEY` header. This example gives the key every scope your account has: ```sh SCOPES=$(curl -s https://api.fluence.dev/v3/account \ -H "Authorization: Bearer " | jq -c '.permissions') curl -X POST https://api.fluence.dev/v3/api-keys \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d "{\"name\": \"my-agent\", \"scopes\": $SCOPES, \"expiresAt\": \"2027-10-01T00:00:00Z\"}" ``` - `name`: 1 to 25 characters, lowercase letters, digits, and hyphens. - `scopes`: what the key may do. A key can only get scopes that your account has. `GET /v3/account` lists them in `permissions`. A call outside the key's scopes returns `403`. - `expiresAt`: an RFC 3339 time in the future. The response is `201` with the key in `value` and its `id`. The API shows the key only once, so store it. To delete a key, send `DELETE /v3/api-keys/`. Creating a key has no `Idempotency-Key`. If the response is lost, a repeated request creates a second key. List your keys with `GET /v3/api-keys` and delete the one whose value you didn't receive. An agent can also use the API key with the Fluence MCP server. See [Connect an AI client through MCP](https://fluence.dev/docs/build_with_ai/mcp.md). ## Step 4: Rent compute To run a CPU VM, follow [CPU Cloud API: Create a VM](https://fluence.dev/docs/build/api/cpu_cloud.md#create-a-vm): 1. Choose a cluster with `GET /v3/clusters`, and a configuration with `GET /v3/clusters//vm-offerings`. 2. Choose an OS image with `GET /v3/images`. 3. Add your SSH public key with `POST /v3/ssh-keys`. 4. Create a draft with `POST /v3/vms` and an `Idempotency-Key`. Add a public interface to reach the VM from the internet. 5. Check the price with `GET /v3/vms//estimate`. 6. Start the VM with `POST /v3/vms//provision`. 7. Read `GET /v3/vms//interfaces` until the public interface has an address in `assignedIps`, then connect with `ssh @
`. For GPU containers, VMs, and bare metal servers, see the [GPU Cloud API](https://fluence.dev/docs/build/api/gpu_cloud.md). ### Billing for agents - CPU resources are billed per second and charged from the balance as they run. Nothing is reserved up front. - Fluence starts a CPU VM only if the balance can keep all your resources, including the new ones, running for at least 6 hours. - Terminating a VM stops billing for the VM only. Delete its disks with `DELETE /v3/storages/` and its public IP address with `DELETE /v3/public-ips/` to stop paying for them. - A wallet account has no email address, so it gets no low-balance warnings. Watch `GET /v3/account/balances` and top up before the balance runs out. - If the balance runs out and the debt exceeds 5 USD or stays unpaid for 3 days, Fluence removes your VMs. Your disks and public IP addresses stay. If the debt then reaches 20 USD or stays unpaid for 10 more days, Fluence deletes all your resources, including disks and public IP addresses. - GPU instances are billed by the hour from the moment they start. When the balance runs out, Fluence ends them at the next hourly charge or earlier. See [GPU Cloud billing](https://fluence.dev/docs/build/gpu_cloud/overview.md#billing-model).