Intents API — Guardrails & Security
Part of the Intents API guide.
Transaction guardrails
Per-agent controls can be set when registering or updating an agent to limit what transactions the proxy will sign:
| Field | Type | Description |
|---|---|---|
tx_allowed_chains | string[] | Restrict to specific chain names (e.g. ["ethereum", "base"]). Empty = all chains allowed. |
tx_to_allowlist | string[] | Restrict recipient addresses. Empty = any address allowed. |
tx_max_value | string | Maximum value per transaction in native major units for the chain family (e.g. "0.01" = 0.01 BTC on Bitcoin, 0.5 ETH on EVM, 2 SOL on Solana). Null = no per-tx limit. |
tx_daily_limit | string | Rolling 24-hour spend cap in native major units, enforced per chain family (Bitcoin spend does not count against EVM limit). Null = no daily limit. See Per-chain spend tracking. |
tx_max_value_eth | string | Deprecated. Alias for tx_max_value (same unit semantics). |
tx_daily_limit_eth | string | Deprecated. Alias for tx_daily_limit. |
tx_token_allowlist | string[] | Restrict token contracts/mints the agent can interact with (e.g. ["0xA0b8..."]). Empty = all tokens. |
tx_known_tokens_only | boolean | Restrict to tokens in the known tokens registry. Default: false. |
xrpl_allowed_tx_types | string[] | Restrict XRPL transaction types (e.g. ["Payment", "TrustSet"]). Empty = all supported types except four dangerous ones (SetRegularKey, SignerListSet, AccountSet, AccountDelete), which are always blocked unless explicitly listed. |
per_chain_guardrails | object | Chain-specific overrides. See Per-chain guardrails below. |
- curl
- TypeScript
- Python
curl -X PATCH "https://api.1claw.xyz/v1/agents/$AGENT_ID" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tx_allowed_chains": ["ethereum", "base"],
"tx_to_allowlist": ["0xSafeAddress1", "0xSafeAddress2"],
"tx_max_value": "0.5",
"tx_daily_limit": "5.0",
"tx_token_allowlist": ["0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"],
"tx_known_tokens_only": true
}'
const { data: agent } = await client.agents.update(agentId, {
tx_allowed_chains: ["ethereum", "base"],
tx_to_allowlist: ["0xSafeAddress1", "0xSafeAddress2"],
tx_max_value: "0.5",
tx_daily_limit: "5.0",
tx_token_allowlist: ["0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"],
tx_known_tokens_only: true,
});
from oneclaw import create_client
client = create_client(api_key="1ck_...")
client.agents.update(
agent_id,
tx_allowed_chains=["ethereum", "base"],
tx_to_allowlist=["0xSafeAddress1", "0xSafeAddress2"],
tx_max_value="0.5",
tx_daily_limit="5.0",
)
| address_screening_policy | object | Recipient screening at signing: { "mode": "off" \| "deny" \| "approve" }. Env deny list: ONECLAW_SCREENING_DENY_LIST. |
| tx_approval_policy | object | Graduated tx HITL thresholds (v0.54+) — matching txs return 202 awaiting_approval. |
| typed_data_policy / simulation_failure_policy / raw_signing_policy | string | "deny" (default) or "approve" for EIP-712, simulation revert, or raw digest HITL. |
When a transaction violates any guardrail, the proxy returns 403 Forbidden with a descriptive detail message.
See Guardrail governance for Convention 6 execution shadow mode, widening approvals, revision history, and replay.
Token guardrails
Two complementary controls restrict which tokens an agent can transfer:
Token allowlist (tx_token_allowlist): An explicit list of token contract addresses or mints the agent may interact with. Applied to token_mint on non-EVM chains and the ERC-20 contract address on EVM token transfers. Case-insensitive. When empty, all tokens are permitted.
Known tokens only (tx_known_tokens_only): When enabled, the agent can only transact with tokens present in the known tokens registry. This is useful for restricting agents to verified, well-known tokens without maintaining a per-agent allowlist.
Both guardrails can be used together — the token must pass both checks (allowlist AND known registry) when both are set.
Per-chain guardrails
Override global guardrails on a per-chain basis using per_chain_guardrails. This is useful when an agent operates across multiple chains with different risk profiles — for example, a higher spend limit on a testnet than on mainnet.
{
"per_chain_guardrails": {
"ethereum": {
"max_value": "1.0",
"to_allowlist": ["0xSafeContract"],
"token_allowlist": ["0xUSDC"]
},
"solana": {
"max_value": "100"
}
}
}
Supported per-chain fields: max_value, daily_limit, to_allowlist, token_allowlist, max_per_day, overhead_budget, max_ata_creates_per_day, max_fee_per_gas_gwei, max_gas_limit, gas_daily_budget_native (v0.56.3 — UTC-day cumulative EVM gas budget). Legacy *_eth keys accepted. Keys are signing chains: ethereum, bitcoin, solana, xrp, cardano, tron. When both global and per-chain values are set, the strictest wins.
XRP transaction type allowlist
1Claw signs 31 XRPL transaction types via xrpl_tx_json — a supported subset, not every type the ledger accepts (DID, oracles, Batch, and others are rejected).
When using xrpl_tx_json, you can restrict which of those types an agent may submit:
curl -X PATCH "https://api.1claw.xyz/v1/agents/$AGENT_ID" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "xrpl_allowed_tx_types": ["Payment", "TrustSet", "OfferCreate"] }'
If the agent submits an xrpl_tx_json with a TransactionType not in the allowlist, the request is rejected with 403.
Deny-by-default dangerous types. SetRegularKey, SignerListSet, AccountSet, and AccountDelete can transfer account control. They are always blocked unless the agent's xrpl_allowed_tx_types explicitly includes that type — even when the allowlist is empty (empty otherwise means “all other supported types”).
Submit/sign still require top-level to and value even when xrpl_tx_json is present (use "0" for non-Payment types). The signed body is taken from xrpl_tx_json. Auto-filled when omitted: Account, Sequence, Fee ("12" drops), LastLedgerSequence (current ledger + 20), SigningPubKey, Flags (0x80000000 / tfFullyCanonicalSig), and SourceTag 482684816 (caller-supplied value wins; explicit 0 suppresses the default).
Known tokens registry
A curated registry of verified token contracts. Use GET /v1/tokens (filterable by ?chain=) or GET /v1/chains/{chain}/tokens to query it.
Admins can manage the registry via POST /v1/admin/tokens (add) and DELETE /v1/admin/tokens/{id} (remove). Each entry includes chain, contract_address, symbol, name, decimals, and an optional logo_url.
Extended token balance
The signing key balance endpoint now supports querying specific token balances alongside native balance:
# Query native + specific ERC-20 token balances
curl "https://api.1claw.xyz/v1/agents/$AGENT_ID/signing-keys/ethereum/balance?tokens=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48,0xdAC17F958D2ee523a2206206994597C13D831ec7" \
-H "Authorization: Bearer $TOKEN"
The ?tokens= parameter accepts comma-separated contract addresses or mints. Works across all chains: ERC-20 (EVM), SPL (Solana), TRC-20 (Tron).
Per-chain daily spend tracking
GET /v1/agents/{id} returns tx_spent_today_by_chain (keys: evm, bitcoin, solana, xrp, cardano, tron) and tx_spent_today (cross-family sum). Daily limits (tx_daily_limit) compare against that chain family's spend from tx_spent_today_by_chain, not the cross-chain total. Legacy tx_spent_today_eth is a deprecated alias for tx_spent_today.
Shroud TEE signing (optional)
When Shroud is deployed, transaction signing moves into a Trusted Execution Environment (AMD SEV-SNP on GKE). The POST /v1/agents/:id/transactions endpoint on shroud.1claw.xyz uses Shroud's own signing engine — private keys are only decrypted inside confidential memory. All other Intents API endpoints (list, get, simulate, simulate-bundle) are proxied to the Vault API.
Both api.1claw.xyz and the TEE hosts serve the full Intents API. Choose based on your security requirements:
| Surface | Submit | List/Get/Simulate | Key isolation |
|---|---|---|---|
api.1claw.xyz | HSM-backed signing (Cloud Run) | Direct | Cloud KMS HSM |
shroud.1claw.xyz | TEE signing (GKE SEV-SNP) | Proxied to Vault API | TEE + KMS |
intents.1claw.xyz | TEE signing (same backend as Shroud) | Proxied to Vault API | TEE + KMS |
intents.1claw.xyz is an alias for the same GKE backend as shroud.1claw.xyz — use it when you want a dedicated hostname for the Intents API. Shroud also provides LLM proxy capabilities; see the Shroud guide.
Security model
- Keys never leave the HSM boundary — the vault decrypts the key, signs the transaction, and zeroes the memory. The plaintext key is never returned to the caller.
- Full audit trail — every transaction is logged with the agent ID, chain, recipient, value, and resulting
tx_hash. - Policy enforcement — the agent still needs a policy granting access to the vault path that holds the signing key. The proxy doesn't bypass access control.
- Transaction guardrails — per-agent chain allowlists, recipient allowlists, per-tx caps, and daily spend limits enforced server-side before signing.
- Rate limiting — standard rate limits apply to transaction endpoints.
Replay protection
Idempotency-Key header
Submit an Idempotency-Key header (e.g. a UUID) with POST /v1/agents/:id/transactions to prevent duplicate submissions. If the same key is sent within 24 hours, the server returns the cached transaction response instead of signing and broadcasting again.
The SDK and MCP server auto-generate an idempotency key on every submitTransaction call. You can override with your own key for explicit retry control.
| Scenario | Response |
|---|---|
| First request with key | 201 Created (normal flow) |
| Duplicate request (completed) | 200 OK (cached response) |
| Duplicate request (in progress) | 409 Conflict (retry later) |
| No header | No idempotency enforcement |
Server-side nonce management
When the nonce field is omitted, the server atomically reserves the next nonce per agent+chain+address combination. This prevents nonce collisions when multiple transactions are submitted concurrently. The server tracks the highest nonce used and takes the maximum of its tracked value and the on-chain pending nonce.