Warns

Quickstart

Warns checks every payment your AI agent is about to make over x402, before anything is signed. It allows the payment, holds it for a human, or blocks it, and the signer it wraps refuses to sign anything that was not approved. This page takes you from nothing to a guarded payment on a test network in about five minutes.

Warns is in early access. On Base Sepolia, a test network, every mode is open: start there, with a wallet made for testing. Testnet USDC has no value. On Base mainnet, Warns runs in monitor mode only: it checks every payment and tells you what it would have stopped, and it never blocks or holds one.

Your agent pays with USDC transfers through Coinbase AgentKit rather than x402? Follow AgentKit instead.

1. Get a test wallet and testnet USDC

Any wallet works, as long as it is only for testing. Get free testnet USDC on Base Sepolia from Circle's faucet. The wallet needs no ETH: in x402, the merchant's side pays the gas when it settles the payment.

2. Create your workspace and an agent

Sign in at app.warns.xyz with GitHub. Create an agent: a name, the agent id your code will pass, the address of the wallet it pays from, and its network. Choose Base Sepolia for this guide: the agent and its key go to the test environment. A Base mainnet agent goes to the live environment, in monitor mode. Keep it in Monitor to start: Warns then records what it would have decided without enforcing it, so you can watch it on real traffic first. The form also sets a cap per payment and a daily cap, 0.50 and 10 USDC by default, which become the agent's starter policy.

Right after, you get an API key. It is shown once: keep it in an environment variable.

Terminal
export WARNS_KEY=warns_test_...export AGENT_PRIVATE_KEY=0x...   # the test wallet, never a real one

3. Install

Terminal
npm i @warns/sdk viem @x402/evm @x402/fetch

viem, @x402/evm and @x402/fetch stay yours: the guard uses the signer and the x402 client you already have.

4. Wrap the fetch your agent pays with

agent.ts
import { createGuard } from "@warns/sdk"import { toClientEvmSigner } from "@x402/evm"import { createPublicClient, http } from "viem"import { privateKeyToAccount } from "viem/accounts"import { baseSepolia } from "viem/chains" const guard = createGuard({  apiKey: process.env.WARNS_KEY!,  agentId: "research-agent",  baseUrl: "https://api.warns.xyz",  rootAddress: "0xA26aa29cF9b429AD85E7a0F7FA6aBd8edE301e8a",}) // The signer your agent pays with. Use base instead of baseSepolia on mainnet.const account = privateKeyToAccount(process.env.AGENT_PRIVATE_KEY as `0x${string}`)const signer = toClientEvmSigner(account, createPublicClient({ chain: baseSepolia, transport: http() })) // A drop in replacement for the fetch you pass to the x402 client.const pay = guard.x402Fetch(signer, {  intent: () => ({ expectedMaxUsd: 0.05, purpose: "market-data" }),}) const res = await pay("https://trap.warns.xyz/trap/honest")console.log(res.status)

Replace research-agent with the agent id you chose. intent says what your agent meant to buy: the most it expects to pay, and why. rootAddress pins the key that signs the decisions, so a decision signed by anything else is rejected.

5. Run it

Terminal
npx tsx agent.ts# 200

Open Transactions in the dashboard: the payment is there, with its decision and its reasons.

6. Try the traps

The public traps behave like a merchant that was hacked. Your agent already paid /trap/honest in step 5, which is how Warns learned that merchant's usual address. Now point it at the others.

TrapIn Protect mode
/trap/price-spikeBlocked: above your cap per payment, and far above what your agent meant to pay.
/trap/payto-swapHeld for review: the merchant usually gets paid elsewhere. Approve it once in Reviews, then retry the same request.
/trap/long-windowBlocked before signing: the authorization would stay valid for an hour.
/trap/unlockBlocked: above your cap, to an address that is not the merchant's.

In Monitor mode they are all paid except /trap/long-window, because the guard never signs an authorization valid for more than 120 seconds, whatever the mode. The dashboard shows what Protect would have done with each. When the decisions look right, switch the agent to Protect in Agents.

Where to go next