APPROVAL Tier Policies: When Your AI Agent Must Ask Permission
APPROVAL Tier Policies: When Your AI Agent Must Ask Permission
Giving an AI agent a wallet without guardrails is like giving a toddler a credit card — and if you're building crypto applications where agents control real funds, the absence of human oversight isn't a feature, it's a liability. WAIaaS addresses this directly with a layered policy engine that includes an explicit APPROVAL tier: a hard stop that requires a human to sign off before any transaction executes.
Why This Actually Matters
The optimistic framing around autonomous AI agents tends to skip over an uncomfortable truth: agents make mistakes. They misinterpret instructions, hit edge cases in logic, and occasionally do something completely unexpected. When the agent controls a wallet with real assets, "unexpected" can mean "drained." The question isn't whether you trust your agent in the average case — it's whether you've planned for the tail cases.
The stakes are specific. A bug in your trading logic could instruct an agent to swap your entire balance. A prompt injection attack could redirect a transfer. A misconfigured action could approve an unlimited token spend to an unknown contract. None of these scenarios require a sophisticated attacker — they just require the agent to be wrong once, with no human in the loop.
WAIaaS is built around the assumption that agents will sometimes need to ask permission. That's not a limitation — it's the point.
Three Layers Between Your Agent and Your Funds
Before getting to the APPROVAL tier specifically, it helps to understand where it sits in the broader security architecture.
WAIaaS implements a 3-layer security model: session authentication → time delay + approval → monitoring and kill switch. Every transaction passes through all relevant layers before executing. There's no shortcut.
Authentication itself uses three distinct methods:
- masterAuth (Argon2id) — system administrator operations like wallet creation and policy management
- ownerAuth (SIWS/SIWE signatures) — fund owner operations like approving transactions and recovery
- sessionAuth (JWT HS256) — what AI agents use for day-to-day operations
An agent operating with a session token cannot escalate its own privileges. It can't modify its own policies. It can't approve its own pending transactions. Those operations require different credentials held by different parties.
The Policy Engine: 21 Types, 4 Tiers, Default-Deny
The policy engine is where WAIaaS gets precise about what agents can and can't do. There are 21 policy types covering everything from spending limits to DeFi-specific constraints. But the architecture that matters most for security is the 4-tier system.
Every transaction gets assigned to exactly one tier:
INSTANT — Execute immediately, no notification
NOTIFY — Execute immediately, send notification to owner
DELAY — Queue for N seconds, then execute (cancellable during window)
APPROVAL — Require explicit human approval before executing
The APPROVAL tier is a hard block. The transaction will not execute until the fund owner cryptographically signs an approval. It doesn't time out into execution. It doesn't retry. It waits.
Configuring APPROVAL Tier with SPENDING_LIMIT
The most common way to reach the APPROVAL tier is through a SPENDING_LIMIT policy. You define thresholds for each tier, and any transaction exceeding the DELAY maximum automatically requires approval.
Here's how to set that up:
curl -X POST http://127.0.0.1:3100/v1/policies \
-H "Content-Type: application/json" \
-H "X-Master-Password: my-secret-password" \
-d '{
"walletId": "<wallet-uuid>",
"type": "SPENDING_LIMIT",
"rules": {
"instant_max_usd": 100,
"notify_max_usd": 500,
"delay_max_usd": 2000,
"delay_seconds": 900,
"daily_limit_usd": 5000
}
}'
With this configuration, the tier assignment works as follows:
- ≤ $100: INSTANT — executes immediately
- $101–$500: NOTIFY — executes immediately, owner gets notified
- $501–$2,000: DELAY — queued for 15 minutes, cancellable
- > $2,000: APPROVAL — blocked until owner explicitly approves
Your agent can freely operate within the INSTANT range without friction. As transaction size increases, the guardrails tighten proportionally. Anything over $2,000 goes nowhere without your signature.
Default-Deny: The Policy Engine's Baseline
APPROVAL tier is the most visible guardrail, but default-deny is arguably more important as a baseline. When ALLOWED_TOKENS or CONTRACT_WHITELIST policies are not configured, transactions are denied outright — not approved, not queued, denied.
This means the safe default state of a WAIaaS wallet is one where the agent can do very little. You opt in to capabilities explicitly, rather than opting out of risks after the fact.
For token transfers, you whitelist specific tokens:
{
"tokens": [
{
"address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"symbol": "USDC",
"chain": "solana"
}
]
}
For contract interactions, you whitelist specific contracts:
{
"contracts": [
{
"address": "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4",
"name": "Jupiter",
"chain": "solana"
}
]
}
An agent attempting to interact with any unlisted token or contract receives a policy denial immediately. There's no edge case where an unknown contract gets called because a policy wasn't set up.
The error response is explicit:
{
"error": {
"code": "POLICY_DENIED",
"message": "Transaction denied by SPENDING_LIMIT policy",
"domain": "POLICY",
"retryable": false
}
}
retryable: false matters here. The agent knows this isn't a transient network issue. It's a policy block. It should surface that to the operator, not retry indefinitely.
How Approval Actually Works
When a transaction hits the APPROVAL tier, it enters a pending state and the owner receives a notification through one of three signing channels: push relay, Telegram, or WalletConnect. The owner reviews the pending transaction and either approves or rejects it with a cryptographic signature.
To approve a pending transaction as the fund owner:
curl -X POST http://127.0.0.1:3100/v1/transactions/<tx-id>/approve \
-H "X-Owner-Signature: <ed25519-or-secp256k1-signature>" \
-H "X-Owner-Message: <signed-message>"
The approval requires ownerAuth — a SIWS or SIWE signature from the wallet that holds the owner role. This is not a password check. It's a cryptographic proof that the actual fund owner authorized this specific action. An attacker who compromises the master password cannot approve transactions on their own — they'd also need the owner's private key.
This separation of concerns is deliberate. The master password manages infrastructure (creating wallets, setting policies, issuing session tokens). The owner signature manages fund authorization. The session token is what agents use. Compromising any one of them doesn't give access to the others.
DeFi-Specific Guardrails
The policy engine includes several types specifically designed for DeFi risk management, which is worth noting if your agents interact with lending protocols or perpetual markets.
For lending, you can cap the loan-to-value ratio with LENDING_LTV_LIMIT and restrict which assets can be used as collateral with LENDING_ASSET_WHITELIST. An agent that's been instructed to maximize yield can't inadvertently open a position that puts collateral at liquidation risk beyond the threshold you've set.
For perpetual futures via Hyperliquid, three policy types apply:
PERP_MAX_LEVERAGE — Maximum allowed leverage multiplier
PERP_MAX_POSITION_USD — Maximum position size in USD
PERP_ALLOWED_MARKETS — Specific markets the agent can trade
If your agent is authorized to trade ETH-PERP with up to 5x leverage and positions under $10,000, a policy misconfiguration or compromised prompt can't push it to 50x leverage on an obscure market. The policy layer enforces the constraint before the transaction reaches the execution stage.
Simulating Before Executing
One practical tool for understanding how policies will behave before deploying an agent is the dry-run API. You can submit any transaction with dryRun: true and see exactly what would happen — including which policy tier would apply — without committing anything to the chain.
curl -X POST http://127.0.0.1:3100/v1/transactions/send \
-H "Content-Type: application/json" \
-H "Authorization: Bearer wai_sess_<token>" \
-d '{
"type": "TRANSFER",
"to": "recipient-address",
"amount": "0.1",
"dryRun": true
}'
This is useful both during development (verifying your policy configuration behaves as intended) and during agent operation (an agent can check whether a proposed action will be blocked before attempting it).
The Full Set of Policy Types
To give a complete picture of what's configurable, here are all 21 policy types currently supported:
SPENDING_LIMIT — Amount-based 4-tier security
WHITELIST — Allowed recipient addresses
TIME_RESTRICTION — Allowed transaction hours
RATE_LIMIT — Max transactions per period
ALLOWED_TOKENS — Token transfer whitelist (default-deny)
CONTRACT_WHITELIST — Contract call whitelist (default-deny)
METHOD_WHITELIST — Allowed function selectors
APPROVED_SPENDERS — Token approval whitelist (default-deny)
APPROVE_AMOUNT_LIMIT — Max approve amount, block unlimited
APPROVE_TIER_OVERRIDE — Force tier for APPROVE transactions
ALLOWED_NETWORKS — Network restriction
X402_ALLOWED_DOMAINS — x402 payment domain whitelist
LENDING_LTV_LIMIT — Max loan-to-value ratio for DeFi lending
LENDING_ASSET_WHITELIST — Allowed lending assets
PERP_MAX_LEVERAGE — Max perpetual futures leverage
PERP_MAX_POSITION_USD — Max position size in USD
PERP_ALLOWED_MARKETS — Allowed perpetual markets
REPUTATION_THRESHOLD — ERC-8004 onchain reputation threshold
ERC8128_ALLOWED_DOMAINS — ERC-8128 HTTP signing domains
VENUE_WHITELIST — Allowed trading venues
ACTION_CATEGORY_LIMIT — DeFi action category limits
APPROVE_AMOUNT_LIMIT deserves specific mention: it blocks unlimited token approvals — the approve(spender, type(uint256).max) pattern that has been exploited repeatedly across DeFi. If your agent is interacting with EVM contracts that request token approvals, this policy ensures it can't grant unlimited spend authority to any contract, regardless of what the agent was instructed to do.
Quick Start: Setting Up Approval Policies
Here's the minimal path to get a wallet running with APPROVAL tier protection:
Step 1: Install and start
npm install -g @waiaas/cli
waiaas init
waiaas start
Step 2: Create a wallet
curl -X POST http://127.0.0.1:3100/v1/wallets \
-H "Content-Type: application/json" \
-H "X-Master-Password: my-secret-password" \
-d '{"name": "trading-wallet", "chain": "solana", "environment": "mainnet"}'
Step 3: Set a spending limit with APPROVAL tier
curl -X POST http://127.0.0.1:3100/v1/policies \
-H "Content-Type: application/json" \
-H "X-Master-Password: my-secret-password" \
-d '{
"walletId": "<wallet-uuid>",
"type": "SPENDING_LIMIT",
"rules": {
"instant_max_usd": 100,
"notify_max_usd": 500,
"delay_max_usd": 2000,
"delay_seconds": 900,
"daily_limit_usd": 5000
}
}'
Step 4: Create an agent session
curl -X POST http://127.0.0.1:3100/v1/sessions \
-H "Content-Type: application/json" \
-H "X-Master-Password: my-secret-password" \
-d '{"walletId": "<wallet-uuid>"}'
Step 5: Review the interactive API docs
open http://127.0.0.1:3100/reference
The Scalar interactive reference at /reference lets you explore the full REST API and test policy configurations without writing additional code.
What's Next
The policy engine covers a lot of ground — if you want to go deeper on the MCP integration that connects WAIaaS to AI agent frameworks like Claude, the GitHub repository includes the full source for the MCP package with all 45 tools. For production deployments, the Docker secrets overlay (docker-compose.secrets.yml) is worth reviewing before putting real funds on any agent. More documentation and guides are available at waiaas.ai.