tutorial · paying agents
Fund your AI agent
Your agent calls sniffy_diagnose and Sniffy answers with HTTP 402 plus an x402 offer. The agent has to sign and pay — which means it needs its own externally-owned account (EOA) holding the payment token on Morph. Five minutes, no bridge gymnastics if you stay on Mainnet.
Why your agent needs a wallet
/api/v1/aso/diagnose is an x402-paywalled endpoint. The first request comes back as HTTP 402 Payment Required with the offer in the PAYMENT-REQUIRED header. The client (your agent, via the SDK / CLI / MCP) signs an EIP-3009 authorization, retries with PAYMENT-SIGNATURE, and receives the diagnosis plus a settled receipt.
The signing wallet lives on your side. Sniffy never holds your key. Payment is on-chain and non-refundable, so the wallet should be a dedicated agent EOA — not your personal hot wallet.
Generate a fresh EOA
Spin up a brand-new private key with viem. Don't reuse a wallet you keep meaningful balances in.
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
const privateKey = generatePrivateKey();
const account = privateKeyToAccount(privateKey);
console.log("address: ", account.address);
console.log("privateKey: ", privateKey); // testnet-only, never commitFund the EOA on Morph Mainnet
Mainnet is the path that actually settles today. $0.50 of USDC on Morph covers dozens of diagnose calls.
Fastest path: buy USDC on Bitget
Bitget lists Morph natively, so USDC withdrawals land directly on your agent's Morph Mainnet address — no L1↔L2 bridging required.
- Sign up or log in to Bitget.
- Buy USDC on the Bitget spot market.
- Withdraw → pick Morph Mainnet as the network → paste your agent EOA address → confirm. The withdrawal will show up on the Morph explorer once it settles.
Or bridge from L1
- Bridge: https://bridge.morphl2.io
- Payment token: USDC (Bridged Standard) at 0xCfb1186F4e93D60E60a8bDd997427D1F33bc372B · 6 decimals
- Explorer: https://explorer.morphl2.io
You also need a tiny amount of ETH on Morph Mainnet for gas if the facilitator falls back to a user-signed settlement path — the official relayer normally sponsors gas, but having $0.10 of ETH bridged is good hygiene.
How much per call?
| Line item | USD |
|---|---|
| base diagnosis | $0.03 |
| per keyword | $0.01 |
| per additional country | $0.01 |
| competitor trail (shallow) | $0.02 |
| competitor trail (deep) | $0.05 |
Five keywords + one country + shallow trail ≈ $0.10. Always quote the exact charge from pricing.estimatedTotal returned by sniffy_quote — the breakdown above is the source-of-truth recipe, not a fixed total.
Inject the key into your agent
The same key works across all three Sniffy surfaces.
MCP
Add it to the host config you set up in the Setup MCP guide:
{
"mcpServers": {
"sniffy": {
"command": "npx",
"args": ["-y", "@gosniffy/mcp"],
"env": {
"SNIFFY_PRIVATE_KEY": "0x...your fresh key..."
}
}
}
}CLI
export SNIFFY_PRIVATE_KEY=0x...your fresh key...
npx @gosniffy/cli diagnose --app 1234567890 --keywords "pickleball,tracker"SDK
import { createSniffy } from "@gosniffy/sdk";
import { privateKeyToAccount } from "viem/accounts";
const sniffy = createSniffy({
signer: privateKeyToAccount(process.env.SNIFFY_PRIVATE_KEY as `0x${string}`),
});
const quote = await sniffy.quote({ store: "ios", app: "1234567890", country: "US", keywords: ["pickleball"] });
const report = await sniffy.diagnose({ ...quote.input, sniffId: quote.sniffId });What your agent is actually signing
The signature is an EIP-3009 transferWithAuthorization — a one-time, off-chain authorization for a specific (from, to, value, validAfter, validBefore, nonce) tuple. It is not a generic ERC-20 approval.
- value is in atomic token units (USDC: 6 decimals → 50000 = $0.05). The SDK does the unit math.
- nonce is a random 32-byte hex string — scopes the signature to a single call, prevents replay.
- The facilitator can't pull more than value with this signature. If you ever see a UI asking you to approve unlimited spend, you're on the wrong endpoint.
Optional: use Hoodi testnet instead
Show the Hoodi flow
Hoodi is Morph's testnet (chain ID 2910, eip155:2910). Flip both env vars together:
# scraper/.env
MORPH_NETWORK=eip155:2910
# landing/.env.local
NEXT_PUBLIC_MORPH_NETWORK=eip155:2910Then visit the Hoodi faucet for gas ETH: