Pay with x402 (for agents)
Fluence accepts balance top-ups over the x402 protocol. 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:
- Top up the balance with USDC through x402. The first payment from a wallet creates a Fluence account for that wallet.
- Sign in with the same wallet (Sign-In with Ethereum) to get an access token.
- Call the Fluence API with that token, or create an API key with it.
- 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, token0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913. You don't need ETH for gas. The x402 facilitator submits the transfer. - An x402 v2 client. The
@x402/*packages (@x402/fetchor@x402/axios, with@x402/evmfor EVM payments) speak v2. The unscopedx402-fetchandx402-axiospackages 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:
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. 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.
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:
{
"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 |
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 message with the wallet that paid, and exchange it for an access token.
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
domainmust be exactlyapi.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.
userDataholds the accountidand a placeholder emailwallet-<address>@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 once and use it instead.
Step 3: Use the API
Send the access token as a bearer token. For example, check the balance:
curl https://api.fluence.dev/v3/account/balances \
-H "Authorization: Bearer <ACCESS_TOKEN>"
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:
SCOPES=$(curl -s https://api.fluence.dev/v3/account \
-H "Authorization: Bearer <ACCESS_TOKEN>" | jq -c '.permissions')
curl -X POST https://api.fluence.dev/v3/api-keys \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-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/accountlists them inpermissions. A call outside the key's scopes returns403.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/<id>.
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.
Step 4: Rent compute
To run a CPU VM, follow CPU Cloud API: Create a VM:
- Choose a cluster with
GET /v3/clusters, and a configuration withGET /v3/clusters/<cluster_id>/vm-offerings. - Choose an OS image with
GET /v3/images. - Add your SSH public key with
POST /v3/ssh-keys. - Create a draft with
POST /v3/vmsand anIdempotency-Key. Add a public interface to reach the VM from the internet. - Check the price with
GET /v3/vms/<vm_id>/estimate. - Start the VM with
POST /v3/vms/<vm_id>/provision. - Read
GET /v3/vms/<vm_id>/interfacesuntil the public interface has an address inassignedIps, then connect withssh <username>@<address>.
For GPU containers, VMs, and bare metal servers, see the GPU Cloud API.
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/<storage_id>and its public IP address withDELETE /v3/public-ips/<public_ip_id>to stop paying for them. - A wallet account has no email address, so it gets no low-balance warnings. Watch
GET /v3/account/balancesand 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.