Off-chain interaction policies are guardrails you configure per agent from your backend (via @abstraxn/agent-kit). Agent Kit evaluates them before every MCP tool call — agents and LLMs cannot bypass them.
Use interaction policies to restrict what on-chain actions an agent may attempt (contracts, calldata, recipients, amounts). For paid MCP tool budgets (x402), use spend policy instead.
Operators can view policies in the dashboard under All agents → Policies (read-only). Create and update policies from your server via the SDK.
Interaction policy vs spend policy
| Interaction policy | Spend policy |
|---|
| Scope | All MCP tools when rules apply | Paid x402 tools only |
| Configured via | createInteractionPolicy, listInteractionPolicies, … | updateSpendPolicy |
| Denial code | -32404 | -32403 |
| Example rule | Max 0.5 ETH per transfer | $5 daily x402 budget |
Enforcement order on tools/call:
- Interaction policy — all enabled policies must pass (AND).
- Spend policy — USD budget for paid tools.
- Tool execution — reads run directly; writes may need backend signing.
Call policy CRUD from your server only — use your dashboard application API key or the agent’s agent.apiKey. Never expose these keys in the browser.
Map your authenticated user → agent.id from SDK quickstart, then attach one or more policies per agent.
Rule types
All rules are per-chain (for example ethereum, base, polygon). You can combine multiple rule types in a single policy.
| Rule | Purpose | Example |
|---|
contractWhitelist | Only listed contract/mint addresses | USDC only on Ethereum |
methodWhitelist | Only matching calldata patterns (* = hex wildcard) | ERC-20 transfer(address,uint256) |
recipientBlacklist | Block listed recipients | Known scam addresses |
nativeAmountLimits | Min/max native transfer amount | Max 0.5 ETH |
tokenAmountLimits | Min/max per token symbol or contract | Max 1000 USDC |
Policy fields:
| Field | Default | Meaning |
|---|
enabled | true | When false, policy is skipped |
hardBlock | true | When false, violations are advisory (logged but call proceeds) |
If an agent has no enabled policies, all tool calls are allowed (subject to spend policy and signing).
SDK — create and manage policies
import { AgentKitClient } from '@abstraxn/agent-kit';
const agentKit = new AgentKitClient({
apiKey: process.env.ABSTRAXN_API_KEY!,
});
const policy = await agentKit.createInteractionPolicy('agent-uuid-here', {
name: 'transfer-guardrails',
enabled: true,
hardBlock: true,
rules: {
recipientBlacklist: [{
chain: 'ethereum',
addresses: ['0xBadAddress000000000000000000000000000001'],
}],
nativeAmountLimits: [{
chain: 'ethereum',
max: '0.5',
}],
contractWhitelist: [{
chain: 'ethereum',
addresses: ['0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'], // USDC
}],
methodWhitelist: [{
chain: 'ethereum',
contract: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
// Full calldata pattern — length must match; * = any hex digit
calldataPatterns: ['0xa9059cbb' + '*'.repeat(128)],
}],
tokenAmountLimits: [{
chain: 'ethereum',
token: 'USDC',
max: '1000',
}],
},
});
const { items, total } = await agentKit.listInteractionPolicies('agent-uuid-here');
const one = await agentKit.getInteractionPolicy('agent-uuid-here', policy.id);
await agentKit.updateInteractionPolicy('agent-uuid-here', policy.id, {
enabled: false,
});
await agentKit.deleteInteractionPolicy('agent-uuid-here', policy.id);
SDK methods
| Method | Purpose |
|---|
createInteractionPolicy(agentId, input) | Create a policy |
listInteractionPolicies(agentId) | List all policies for an agent |
getInteractionPolicy(agentId, policyId) | Fetch one policy |
updateInteractionPolicy(agentId, policyId, input) | Update name, rules, or flags |
deleteInteractionPolicy(agentId, policyId) | Remove a policy |
Authentication
| Credential | Scope |
|---|
| Application API key (dashboard Overview) | All agents under your app |
Per-agent agent.apiKey (from createAgent) | That agent only |
REST API
Same operations are available over REST if you prefer not to use the SDK:
| Method | Path |
|---|
POST | /agents/:agentId/policies |
GET | /agents/:agentId/policies |
GET | /agents/:agentId/policies/:policyId |
PATCH | /agents/:agentId/policies/:policyId |
DELETE | /agents/:agentId/policies/:policyId |
Base URL matches your Agent Kit host (same host as MCP without /mcp).
MCP denial (-32404)
When a tool call breaks a policy with hardBlock: true, MCP returns JSON-RPC error -32404:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32404,
"message": "Interaction policy denied",
"data": {
"interactionPolicy": {
"violations": [
{
"policyId": "uuid",
"policyName": "transfer-guardrails",
"reason": "recipient_blacklisted",
"message": "Recipient 0x… is blacklisted",
"hardBlock": true
}
]
}
}
}
}
Violation reason values:
| Reason | Meaning |
|---|
contract_not_whitelisted | Target contract not in contractWhitelist |
method_not_whitelisted | Calldata does not match any methodWhitelist pattern |
recipient_blacklisted | Recipient in recipientBlacklist |
native_amount_below_min | Native value below nativeAmountLimits.min |
native_amount_above_max | Native value above nativeAmountLimits.max |
token_amount_below_min | Token amount below tokenAmountLimits.min |
token_amount_above_max | Token amount above tokenAmountLimits.max |
invalid_policy_config | Malformed policy rules |
See Troubleshooting — interaction policy denied for common fixes.
Method whitelist tips
- Patterns are full hex calldata strings — include the 4-byte selector and encoded arguments.
- Use
* as a wildcard for any hex digit (0-9, a-f).
- Pattern length must match the calldata you expect (pad with
* for dynamic fields like addresses).
Example: ERC-20 transfer(address,uint256) selector is 0xa9059cbb, followed by 32-byte padded address and 32-byte amount — 136 hex chars after 0x for the arguments portion.
Interaction policy runs on MCP tools/call when the tool implies an on-chain interaction — for example transfer, token moves, and paid tools that settle on-chain. Read-only tools such as get_balance and discover_services are generally unaffected unless the tool extracts chain interaction context from arguments.
When in doubt, test with a restrictive policy in dev and inspect -32404 violations in your dashboard activity logs.
Security checklist
- Configure policies from your backend — not the browser.
- Use multiple policies only when you need separate rule sets; remember all enabled policies must pass (AND).
- Start with
hardBlock: true in production; use advisory mode (hardBlock: false) only for shadow testing.
- Pair policies with spend policy and ERC-8004 identity for full agent accountability.
Next steps