Skip to main content

Intents API

The Intents API lets an agent submit on-chain transactions — transfers, swaps, contract calls — while never having access to the raw private key. The server signs the transaction using keys stored in the vault and broadcasts it through a dedicated RPC for the target chain.

Try it out

Try out the examples: Transaction Simulation (guardrails + Tenderly simulation), Shroud Demo (Intents API via Shroud TEE), Multi-Chain Keys (provision keys for 6 blockchains), EVM Signing (EIP-191, EIP-712, tx types 0–2), and Agentic TX (real mainnet transactions with guardrails).

Quickstart: Your first transaction (~5 min)

  1. Create an agent with intents_api_enabled: true (Dashboard → Agents → Create, or API below). Note the agent ID and API key.
  2. Store a signing key in a vault the agent can read: either provision a per-chain signing key via POST /v1/agents/:id/signing-keys (recommended), or put a secp256k1 private key at a path like keys/ethereum-signer or wallets/hot-wallet (see Secrets). Grant the agent read access to that path via a policy.
  3. Get an agent JWT: POST /v1/auth/agent-token with agent_id and api_key.
  4. Submit a transaction: POST /v1/agents/:agent_id/transactions with chain, to, value, and optionally signing_key_path. Use testnets (e.g. chain: "sepolia") first.
  5. Optional: Set simulate_first: true to run a Tenderly simulation before signing; if the simulation reverts, the API returns 422 and does not sign. See Transaction simulation (Tenderly) and Error codes.
tip

Default signing key path auto-resolves: if the agent has a per-chain signing key provisioned (via POST /v1/agents/:id/signing-keys), the key at agents/{id}/chains/{chain}/private_key is used; otherwise falls back to keys/{chain}-signer (e.g. keys/base-signer). Network names like sepolia and base automatically map to canonical signing key chains like ethereum. You can override with signing_key_path in the request. Allowed path prefixes: keys/, wallets/, agents/{id}/keys/, agents/{id}/chains/.

How it works

Agent                       1claw Vault                  Blockchain
│ │ │
│ POST /v1/agents/:id/ │ │
│ transactions │ │
│ { chain, to, value, │ │
│ data, signing_key_path } │ │
│ ─────────────────────────► │ │
│ │ 1. Decrypt private key │
│ │ from vault via HSM │
│ │ 2. Build & sign tx │
│ │ 3. Broadcast via RPC ───► │
│ │ │
│ ◄───────────────────────── │ tx_hash, status │
│ { id, tx_hash, status } │ │
  1. The agent calls POST /v1/agents/:agent_id/transactions with the chain, recipient, value, calldata, and the vault path to the signing key.
  2. The vault decrypts the private key inside the HSM boundary, constructs and signs the transaction, and broadcasts it to the chain's RPC endpoint.
  3. The agent receives an id and tx_hash — it never sees the raw key material.

Enabling the Intents API

Set intents_api_enabled: true when registering or updating an agent:

curl -X POST "https://api.1claw.xyz/v1/agents" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "DeFi Bot",
"intents_api_enabled": true
}'

What changes when enabled

Behaviourintents_api_enabled: falseintents_api_enabled: true
Read api_key, password, etc.AllowedAllowed
Read private_key or ssh_keyAllowedBlocked (403)
Submit proxy transactionsNot availableAllowed
Audit trail per transactionN/AFull trace with tx_id

The enforcement is two-sided: the flag both grants access to the transaction endpoints and blocks direct reads of signing keys through the standard secrets endpoint. This guarantees the agent can only use keys through the proxy.

Submitting a transaction

curl -X POST "https://api.1claw.xyz/v1/agents/$AGENT_ID/transactions" \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"chain": "ethereum",
"to": "0xRecipientAddress",
"value": "1.0",
"data": "0x",
"signing_key_path": "wallets/hot-wallet"
}'

Response

{
"id": "a7e2c...",
"tx_hash": "0xabc123...",
"chain": "ethereum",
"status": "broadcast"
}

Querying transactions

# List all transactions for this agent
curl "https://api.1claw.xyz/v1/agents/$AGENT_ID/transactions" \
-H "Authorization: Bearer $AGENT_TOKEN"

# Get a specific transaction
curl "https://api.1claw.xyz/v1/agents/$AGENT_ID/transactions/$TX_ID" \
-H "Authorization: Bearer $AGENT_TOKEN"

Sign-only mode (BYORPC)

Sometimes you want the server to sign the transaction inside the HSM (or Shroud TEE) but not broadcast it. This lets you:

  • Use your own RPC endpoint for broadcasting
  • Implement MEV protection (e.g. Flashbots, MEV Blocker)
  • Queue transactions for batch submission
  • Broadcast to multiple RPCs simultaneously

Call POST /v1/agents/:agent_id/transactions/sign with the same request body as submit. The server signs the transaction and returns the raw signed_tx hex without broadcasting.

curl -X POST "https://api.1claw.xyz/v1/agents/$AGENT_ID/transactions/sign" \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"chain": "ethereum",
"to": "0xRecipientAddress",
"value": "0.1",
"signing_key_path": "keys/ethereum-signer"
}'

Response

{
"signed_tx": "0x02f870018203...signed hex...",
"tx_hash": "0xabc123...",
"from": "0xDerivedSenderAddress",
"to": "0xRecipientAddress",
"chain": "ethereum",
"chain_id": 1,
"nonce": 42,
"value_wei": "100000000000000000",
"status": "sign_only"
}

All agent guardrails (allowlists, value caps, daily limits) are enforced exactly as for submit. The transaction is recorded for audit and daily-limit tracking.

TEE signing

When using Shroud (shroud.1claw.xyz), the /transactions/sign endpoint performs signing inside the TEE — the private key never leaves the secure enclave, and you get full control over broadcasting.

Transaction simulation (Tenderly)

Every transaction can be simulated before signing. Simulation executes the full transaction against the current chain state in a sandboxed environment, returning decoded traces, balance changes, gas estimates, and human-readable error messages — without consuming real gas.

Standalone simulation

Call the simulate endpoint to preview a transaction without committing:

curl -X POST "https://api.1claw.xyz/v1/agents/$AGENT_ID/transactions/simulate" \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"chain": "base",
"to": "0xRecipientAddress",
"value": "0.5",
"data": "0x",
"signing_key_path": "wallets/hot-wallet"
}'

The response includes:

{
"simulation_id": "sim_a7e2c...",
"status": "success",
"gas_used": 21000,
"balance_changes": [
{ "address": "0xSender...", "token": "ETH", "before": "2.5", "after": "1.99", "change": "-0.51" },
{ "address": "0xRecipient...", "token": "ETH", "before": "0.0", "after": "0.5", "change": "+0.5" }
],
"tenderly_dashboard_url": "https://dashboard.tenderly.co/..."
}

Simulate-then-sign (single call)

Add "simulate_first": true to the standard transaction submission. The server simulates first; if the simulation reverts, it returns HTTP 422 and does not sign or broadcast:

curl -X POST "https://api.1claw.xyz/v1/agents/$AGENT_ID/transactions" \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"chain": "base",
"to": "0xRecipientAddress",
"value": "0.5",
"simulate_first": true
}'

Bundle simulation

Simulate multiple transactions sequentially (e.g. ERC-20 approve followed by a swap):

curl -X POST "https://api.1claw.xyz/v1/agents/$AGENT_ID/transactions/simulate-bundle" \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"transactions": [
{ "chain": "base", "to": "0xToken", "value": "0", "data": "0xapprove..." },
{ "chain": "base", "to": "0xRouter", "value": "0", "data": "0xswap..." }
]
}'

Enforcing simulation

Org admins can require simulation for all agent transactions by setting the intents_api.require_simulation org setting to "true" via PUT /v1/admin/settings/intents_api.require_simulation. When enabled, any transaction submitted without simulate_first: true will be automatically simulated, and reverts will block signing.

EIP-1559 (Type 2) transactions

Set max_fee_per_gas and max_priority_fee_per_gas instead of gas_price to use EIP-1559 fee mode:

curl -X POST "https://api.1claw.xyz/v1/agents/$AGENT_ID/transactions" \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"chain": "base",
"to": "0xRecipientAddress",
"value": "0.1",
"max_fee_per_gas": "30000000000",
"max_priority_fee_per_gas": "1500000000",
"simulate_first": true
}'

Multi-chain signing keys

Instead of manually storing a raw private key in a vault, you can provision HSM-backed signing keys directly on the agent. 1claw generates the keypair inside the HSM and stores the private key in the org's __agent-keys vault — the key never leaves hardware.

Supported chains

ChainCurveAddress format
Ethereumsecp256k10x (EIP-55 checksum)
Bitcoinsecp256k1P2WPKH bech32 (bc1q… / tb1q…) — via rust-bitcoin
SolanaEd25519Base58 — via solana-sdk
XRPEd25519Base58Check (r…)
CardanoEd25519Bech32 enterprise (addr1…)
Tronsecp256k1Base58Check (T…)

Provisioning a key

curl -X POST "https://api.1claw.xyz/v1/agents/$AGENT_ID/signing-keys" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "chain": "ethereum" }'

The response includes the public_key, derived address, curve, and key_version. The private key is stored in the HSM-backed __agent-keys vault.

Key lifecycle

OperationEndpointSDK
ProvisionPOST /v1/agents/{id}/signing-keysclient.signingKeys.create(agentId, { chain })
ListGET /v1/agents/{id}/signing-keysclient.signingKeys.list(agentId)
RotatePOST /v1/agents/{id}/signing-keys/{chain}/rotateclient.signingKeys.rotate(agentId, chain)
DeactivateDELETE /v1/agents/{id}/signing-keys/{chain}client.signingKeys.deactivate(agentId, chain)
ExportPOST /v1/agents/{id}/signing-keys/{chain}/exportclient.signingKeys.export(agentId, chain, { password })

Only human users can provision, rotate, and export keys — agents get 403. Export requires password re-authentication via the X-Auth-Confirm header and is audit-logged as signing_key.export. Failed re-auth increments failed_login_attempts and can trigger account lockout. Keys for non-EVM chains (Bitcoin, Solana, XRP, Cardano, Tron) support both address derivation and on-chain transaction signing + broadcast — see Non-EVM transaction signing below.

Platform API auto-provisioning

If you're using the Platform API, signing keys can be auto-provisioned during bootstrap by including a signing_keys array in your template spec — no separate API call needed.


Non-EVM transaction signing

The Intents API signs and broadcasts native transactions for Bitcoin, Solana, XRP, Cardano, and Tron in addition to EVM chains. The same endpoints (POST /v1/agents/:id/transactions for sign + broadcast, POST /v1/agents/:id/transactions/sign for sign-only) dispatch by chain family — you only change the chain and provide chain-appropriate fields. Signing happens in the HSM (or the Shroud TEE); the private key never leaves hardware.

Bitcoin signing uses the official rust-bitcoin crate (v0.32) with full support for P2PKH, P2SH, P2WPKH, P2WSH, and P2TR (Taproot) recipient addresses. Solana signing uses the official solana-sdk crate (v4) with native PDA derivation and SPL token transfer support. XRP uses xrpl-rust for 30+ transaction types.

1claw fetches the chain-specific data it needs automatically (UTXOs and fee rate for Bitcoin, latest blockhash for Solana, account sequence for XRP, protocol parameters and UTXOs for Cardano, the reference block for Tron), signs, and (unless you use the sign-only endpoint) broadcasts via the chain's RPC.

Value units

value is always the human-readable major unit as a decimal string (e.g. "0.5" for 0.5 BTC). 1claw converts to base units internally:

ChainBase unitDecimalsAddress format
Bitcoinsatoshi8bech32 P2WPKH (bc1q…)
Solanalamport9Base58
XRPdrop6Base58Check (r…)
Cardanolovelace6Bech32 enterprise (addr1…)
Tronsun6Base58Check (T…)

Chain-specific request fields

All fields are optional and ignored on chains where they don't apply:

FieldTypeChainPurpose
destination_tagnumberXRPDestination tag for exchange deposits
memostringXRP, SolanaOptional memo (planned; currently accepted but not applied — use Memos inside xrpl_tx_json for XRP)
fee_rate_sat_per_vbytenumberBitcoinOverride the fetched fee rate
fee_limit_sunnumberTronTRC-20 energy fee limit (default: 100,000,000 = 100 TRX)
token_mintstringSolana (SPL), Tron (TRC-20)Token mint / contract address
token_decimalsnumberSolana, TronToken decimals (default 6)
ttlnumberCardanoTime-to-live (absolute slot; default: current slot + 7200)
xrpl_tx_jsonobjectXRPFull XRPL transaction JSON for 30+ transaction types (e.g. TrustSet, OfferCreate, NFTokenMint). Overrides to/value/destination_tag when present.

For a token transfer, set token_mint (and token_decimals); omit it for a native transfer.

Supported networks & testnets

All non-EVM chains support both mainnet and testnet signing. Use the chain field to select the network:

ChainMainnet chainTestnet chainTestnet explorerFaucet
Bitcoinbitcoinbitcoin-testnet, bitcoin-signetmempool.space/signetfaucet.coinbin.org (signet, no captcha, 0.001–0.09 sBTC), signetfaucet.com (captcha)
Solanasolanasolana-devnet, solana-testnetexplorer.solana.com/?cluster=devnetfaucet.solana.com (GitHub login), solana airdrop <SOL> <address> --url devnet
XRPxrpxrp-testnettestnet.xrpl.orgxrpl.org/resources/dev-tools/xrp-faucets
Cardanocardanocardano-preprod, cardano-previewexplorer.cardano.org/preprodfaucet.preprod.world.dev.cardano.org (web or API)
Trontrontron-shasta, tron-nileshasta.tronscan.orgshasta.tronex.io (2,000 TRX + 1,000 USDT)
Testnet address formats

Bitcoin testnet/signet addresses use the tb1q… prefix (derived from the same key as mainnet bc1q…). Cardano preprod addresses use addr_test1… (derived from the same key as mainnet addr1…). Solana, XRP, and Tron use the same address format on all networks.

External API dependencies

ChainExternal serviceRequired config
Bitcoinmempool.spaceNone (public API)
SolanaSolana JSON-RPCNone (public endpoints: api.devnet.solana.com, api.mainnet-beta.solana.com)
XRPXRPL HTTP JSON-RPCNone (public: xrplcluster.com, s.altnet.rippletest.net:51234)
CardanoBlockfrostBLOCKFROST_PROJECT_ID (generic fallback), or per-network: BLOCKFROST_PROJECT_ID_PREPROD, BLOCKFROST_PROJECT_ID_PREVIEW, BLOCKFROST_PROJECT_ID_MAINNET. Also accepts BLOCKFROST_API_KEY as an alias. Free tier: 50k req/day.
TronTronGridNone (public API: api.trongrid.io, api.shasta.trongrid.io)

Cardano Preprod faucet (API)

The Cardano preprod faucet supports programmatic requests (api key is optional):

curl -X POST "https://faucet.preprod.world.dev.cardano.org/send-money/<YOUR_ADDR_TEST1_ADDRESS>?api_key=ooseiteiquo7Wie9oochooyiequi4ooc"

Rate limit: one request per address per 24 hours. The default API key above is public; you can also submit without one.

Example — native transfers

# Bitcoin (testnet): send 0.001 BTC
curl -X POST "https://api.1claw.xyz/v1/agents/$AGENT_ID/transactions" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"chain": "bitcoin-testnet",
"to": "tb1q...",
"value": "0.001"
}'

# Solana (devnet): send 0.25 SOL
curl -X POST "https://api.1claw.xyz/v1/agents/$AGENT_ID/transactions" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "chain": "solana-devnet", "to": "9xQ...", "value": "0.25" }'

# XRP (testnet): send 10 XRP with a destination tag
curl -X POST "https://api.1claw.xyz/v1/agents/$AGENT_ID/transactions" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "chain": "xrp-testnet", "to": "rPT1...", "value": "10", "destination_tag": 12345 }'

The response shape matches EVM: { tx_hash, signed_tx, from, to, value_wei, status }. For non-EVM chains, the value_wei field contains the chain-native base unit (satoshis for Bitcoin, lamports for Solana, drops for XRP, lovelace for Cardano, sun for Tron), signed_tx contains the signed payload (hex or base64 depending on the chain), and tx_hash is the chain-native transaction id (reversed-hex txid for Bitcoin, base58 signature for Solana, uppercase hex for XRP, blake2b-256 hex for Cardano, SHA-256 txID hex for Tron). For sign-only responses, chain_id and nonce are 0 for non-EVM chains.

Tenderly simulation is EVM-only

simulate_first and the /simulate endpoints only apply to EVM chains. For non-EVM chains they are a no-op — use the sign-only endpoint if you want to inspect the signed transaction before broadcasting it yourself.


Unified sign endpoint

The unified POST /v1/agents/{id}/sign endpoint supports three intent types: EIP-191 message signing, EIP-712 typed data signing, and transaction signing across all EIP-2718 types.

EIP-191 personal_sign

Sign an arbitrary human-readable message. Requires message_signing_enabled: true on the agent.

curl -X POST "https://api.1claw.xyz/v1/agents/$AGENT_ID/sign" \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"intent_type": "personal_sign",
"chain": "ethereum",
"message": "Hello from my agent!"
}'

EIP-712 typed data

Sign structured typed data (e.g. ERC-20 Permit, gasless approvals). The agent's eip712_domain_allowlist must include the verifyingContract, or eip712_default_policy must be "allow".

curl -X POST "https://api.1claw.xyz/v1/agents/$AGENT_ID/sign" \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"intent_type": "typed_data",
"chain": "ethereum",
"typed_data": {
"types": { "Permit": [{"name":"owner","type":"address"},{"name":"spender","type":"address"},{"name":"value","type":"uint256"},{"name":"nonce","type":"uint256"},{"name":"deadline","type":"uint256"}] },
"primaryType": "Permit",
"domain": { "name": "USD Coin", "version": "2", "chainId": 1, "verifyingContract": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" },
"message": { "owner": "0x...", "spender": "0x...", "value": "1000000", "nonce": "0", "deadline": "1735689600" }
}
}'

Raw digest signing (ERC-1271 / ERC-7739)

Some protocols compute a canonical EIP-712 digest client-side — notably ERC-1271 / ERC-7739 nested TypedDataSign payloads used by smart-contract accounts (e.g. Polymarket CLOB orders). For these, re-deriving the hash server-side from typed_data can diverge from the verifier's expected hash and cause the signature to be rejected. The eip712_digest intent signs a pre-computed 32-byte digest directly, returning a 65-byte r‖s‖v signature that recovers to the agent's EOA.

Blind signing

eip712_digest is blind signing: 1Claw cannot inspect what the digest authorizes, so transaction guardrails are bypassed. It is gated behind the per-agent raw_signing_enabled flag (off by default — a human must enable it; agents cannot self-enable), and every use is audit-logged as signing_key.raw_digest_sign. Only enable it for agents that genuinely need ERC-1271/ERC-7739 flows.

curl -X POST "https://api.1claw.xyz/v1/agents/$AGENT_ID/sign" \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"intent_type": "eip712_digest",
"chain": "ethereum",
"hash": "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"
}'
const { data } = await client.agents.sign(agentId, {
intent_type: "eip712_digest",
chain: "ethereum",
hash: "0x59c6...690d", // client-computed canonical 32-byte digest
});
console.log(data.signature, data.from);

Transaction types (EIP-2718)

The unified sign endpoint supports all EIP-2718 envelope types via the tx_type field:

tx_typeNameKey fields
0Legacy (EIP-155)gas_price
1EIP-2930 (access list)gas_price, access_list
2EIP-1559max_fee_per_gas, max_priority_fee_per_gas
3EIP-4844 (blob)max_fee_per_blob_gas, blob_versioned_hashes
4EIP-7702authorization_list
const { data } = await client.agents.sign(agentId, {
intent_type: "transaction",
chain: "sepolia",
tx_type: 2,
to: "0xRecipient",
value: "0",
max_fee_per_gas: "30000000000",
max_priority_fee_per_gas: "2000000000",
gas_limit: 21000,
});

Message signing guardrails

FieldTypeDescription
message_signing_enabledbooleanMust be true for EIP-191 personal_sign (default: false).
eip712_default_policy"deny" | "allow"Default policy for EIP-712 domains not in the allowlist (default: "deny").
eip712_domain_allowlistJSON[]List of allowed domains, e.g. [{"verifying_contract": "0xA0b..."}]. Known dangerous types (Permit, Permit2) always require explicit allowlisting.
raw_signing_enabledbooleanMust be true for the eip712_digest (raw/blind digest) intent (default: false). Human-set only; agents cannot enable it.

MCP tools

The MCP server provides transaction tools for the full lifecycle:

simulate_transaction — simulate without signing:

Tool: simulate_transaction
Args:
chain: "base"
to: "0xRecipientAddress"
value: "0.5"
signing_key_path: "wallets/hot-wallet"

submit_transaction — sign and broadcast (simulation on by default):

Tool: submit_transaction
Args:
chain: "base"
to: "0xRecipientAddress"
value: "0.5"
signing_key_path: "wallets/hot-wallet"
simulate_first: true

sign_transaction — sign only, no broadcast (for BYORPC):

Tool: sign_transaction
Args:
chain: "base"
to: "0xRecipientAddress"
value: "0.5"
signing_key_path: "wallets/hot-wallet"
simulate_first: true

list_transactions — list recent transactions:

Tool: list_transactions
Args:
include_signed_tx: false

get_transaction — get details of a specific transaction:

Tool: get_transaction
Args:
transaction_id: "uuid-of-transaction"
include_signed_tx: false

provision_signing_key — provision an HSM-backed signing key for a chain:

Tool: provision_signing_key
Args:
chain: "ethereum"

list_signing_keys — list all signing keys for the current agent:

Tool: list_signing_keys

sign_message — sign an EIP-191 personal message:

Tool: sign_message
Args:
message: "Hello from my agent"
chain: "ethereum"

sign_typed_data — sign EIP-712 typed structured data:

Tool: sign_typed_data
Args:
chain: "ethereum"
typed_data: { types: {...}, primaryType: "Permit", domain: {...}, message: {...} }

sign_digest — sign a client-computed 32-byte digest directly (raw/blind signing; requires raw_signing_enabled). For ERC-1271 / ERC-7739 nested EIP-712 flows (e.g. Polymarket):

Tool: sign_digest
Args:
chain: "ethereum"
hash: "0x59c6...690d" // canonical 32-byte digest computed client-side

Supported chains

The proxy can broadcast transactions to any chain in the registry. All mainnet chains below are configured with dedicated dRPC endpoints for reliable transaction delivery.

Querying chains via API

You can always fetch the live list with GET /v1/chains. The response includes chain_id, rpc_url, explorer_url, and native_currency for every chain.

Mainnet chains (29)

ChainChain IDNative tokenExplorer
Ethereum1ETHetherscan.io
Optimism10ETHoptimistic.etherscan.io
Cronos25CROcronoscan.com
BNB Smart Chain56BNBbscscan.com
Gnosis100xDAIgnosisscan.io
Polygon137POLpolygonscan.com
Sonic146Ssonicscan.org
Fantom250FTMftmscan.com
zkSync Era324ETHexplorer.zksync.io
World Chain480ETHworldscan.org
Metis1088METISandromeda-explorer.metis.io
Polygon zkEVM1101ETHzkevm.polygonscan.com
Moonbeam1284GLMRmoonscan.io
Sei1329SEIseitrace.com
Mantle5000MNTmantlescan.xyz
Kaia8217KAIAkaiascan.io
Base8453ETHbasescan.org
Mode34443ETHmodescan.io
Arbitrum One42161ETHarbiscan.io
Arbitrum Nova42170ETHnova.arbiscan.io
Celo42220CELOceloscan.io
Avalanche C-Chain43114AVAXsnowtrace.io
Linea59144ETHlineascan.build
Berachain80094BERAberascan.com
Blast81457ETHblastscan.io
Taiko167000ETHtaikoscan.io
Scroll534352ETHscrollscan.com
Zora7777777ETHexplorer.zora.energy
Robinhood Chain4663RBHrobinhoodchain.com

Testnet chains

EVM testnets

ChainChain IDNative tokenExplorer
Sepolia11155111ETHsepolia.etherscan.io
Base Sepolia84532ETHsepolia.basescan.org
Arc Testnet5042002USDCtestnet.arcscan.app
Robinhood Testnet46630RBHtestnet.robinhoodchain.com

Non-EVM testnets

ChainNetworkNative tokenExplorerFaucet
Bitcoinbitcoin-signetsBTCmempool.space/signetfaucet.coinbin.org (no captcha), signetfaucet.com
Bitcoinbitcoin-testnettBTCmempool.space/testnet— (testnet3 faucets are scarce)
Solanasolana-devnetSOLexplorer.solana.com (devnet)faucet.solana.com
XRPxrp-testnetXRPtestnet.xrpl.orgxrpl.org faucets
Cardanocardano-preprodtADAexplorer.cardano.org/preprodCardano faucet
Trontron-shastaTRXshasta.tronscan.orgshasta.tronex.io
Trontron-nileTRXnile.tronscan.orgnileex.io

Adding a chain

Admins can add new chains via the admin API:

curl -X POST "https://api.1claw.xyz/v1/admin/chains" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "my-chain",
"display_name": "My Chain",
"chain_id": 12345,
"rpc_url": "https://rpc.mychain.io",
"explorer_url": "https://explorer.mychain.io",
"native_currency": "MCH"
}'

See the Admin API reference for update and delete endpoints.


Transaction guardrails

Per-agent controls can be set when registering or updating an agent to limit what transactions the proxy will sign:

FieldTypeDescription
tx_allowed_chainsstring[]Restrict to specific chain names (e.g. ["ethereum", "base"]). Empty = all chains allowed.
tx_to_allowliststring[]Restrict recipient addresses. Empty = any address allowed.
tx_max_valuestringMaximum 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_limitstringRolling 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_ethstringDeprecated. Alias for tx_max_value (same unit semantics).
tx_daily_limit_ethstringDeprecated. Alias for tx_daily_limit.
tx_token_allowliststring[]Restrict token contracts/mints the agent can interact with (e.g. ["0xA0b8..."]). Empty = all tokens.
tx_known_tokens_onlybooleanRestrict to tokens in the known tokens registry. Default: false.
xrpl_allowed_tx_typesstring[]Restrict XRPL transaction types (e.g. ["Payment", "TrustSet"]). Empty = all supported types.
per_chain_guardrailsobjectChain-specific overrides. See Per-chain guardrails below.
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
}'

When a transaction violates any guardrail, the proxy returns 403 Forbidden with a descriptive detail message.

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 (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. Daily limits compare against that chain family's spend today (tx_spent_today_by_chain), not a cross-chain total.

XRP transaction type allowlist

When using xrpl_tx_json for advanced XRP transactions, you can restrict which transaction types are permitted:

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.

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:

SurfaceSubmitList/Get/SimulateKey isolation
api.1claw.xyzHSM-backed signing (Cloud Run)DirectCloud KMS HSM
shroud.1claw.xyzTEE signing (GKE SEV-SNP)Proxied to Vault APITEE + KMS
intents.1claw.xyzTEE signing (same backend as Shroud)Proxied to Vault APITEE + 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.

ScenarioResponse
First request with key201 Created (normal flow)
Duplicate request (completed)200 OK (cached response)
Duplicate request (in progress)409 Conflict (retry later)
No headerNo 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.

Response field gating

By default, the signed_tx field (raw signed transaction hex) is omitted from GET responses to reduce exfiltration risk. Pass ?include_signed_tx=true to include it:

curl "https://api.1claw.xyz/v1/agents/$AGENT_ID/transactions?include_signed_tx=true" \
-H "Authorization: Bearer $AGENT_TOKEN"

The initial POST submission always returns signed_tx for the originating caller.

Best practices

  1. One key per agent — give each agent its own signing key in its own vault path so you can revoke independently.
  2. Set expires_at — register agents with an expiry so leaked API keys have a bounded blast radius.
  3. Use scoped policies — grant the agent access only to the specific vault path containing its signing key, not the entire vault.
  4. Monitor transactions — query GET /v1/agents/:id/transactions regularly or set up audit webhooks.
  5. Use testnets first — use testnets to verify the flow before moving to mainnet. For EVM: Sepolia, Base Sepolia. For non-EVM: Bitcoin Signet, Solana Devnet, XRP Testnet, Cardano Preprod, Tron Shasta. See Non-EVM networks for faucet links.

Execution Intents (Pro+)

Execution Intents extend the Intents API beyond blockchain transactions. Agents can make HTTP calls, database queries, and external service interactions through pre-configured bindings — without ever seeing the underlying credentials.

Tier requirements
  • Pro: HTTP and GraphQL binding types
  • Team+: All binding types (Postgres, MySQL, Redis, gRPC, SMTP, Cloud SDK, S3, Custom)
  • Business+: TEE execution mode (requests execute inside Shroud's confidential enclave)

How it works

  1. A human creates a binding on the agent — a named credential handle (e.g. stripe-api, analytics-db) with connection details and authentication.
  2. The agent calls POST /v1/agents/:id/execute with the binding name and request parameters.
  3. The server injects credentials server-side, executes the request, and returns the response — the agent never sees API keys, database passwords, or tokens.

Enabling Execution Intents

Set execution_intents_enabled: true when creating or updating an agent:

curl -X PATCH "https://api.1claw.xyz/v1/agents/$AGENT_ID" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "execution_intents_enabled": true }'

Creating a binding

Bindings are human-only — agents cannot create or modify their own bindings.

curl -X POST "https://api.1claw.xyz/v1/agents/$AGENT_ID/bindings" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "stripe-api",
"binding_type": "http",
"credential": "sk_live_...",
"config": {
"base_url": "https://api.stripe.com",
"auth_type": "bearer",
"allowed_hosts": ["api.stripe.com"],
"allowed_paths": ["/v1/*"],
"timeout_ms": 10000
}
}'

Vault-ref credentials (live pointers)

Instead of copying a credential into the binding, you can reference an existing vault secret. The server resolves the secret at execution time — if you rotate the upstream secret, every binding referencing it picks up the new value automatically.

import { CredentialSource } from "@1claw/sdk";

const vaultRef: CredentialSource = {
type: "vault_ref",
vault_id: "550e8400-e29b-41d4-a716-446655440000",
path: "integrations/stripe-key",
};

const { data: binding } = await client.bindings.create(agentId, {
name: "stripe-api",
binding_type: "http",
config: { base_url: "https://api.stripe.com", auth_type: "bearer" },
credential_source: vaultRef,
});
// binding.credential_source_type === "vault_ref"
// binding.credential_vault_id, binding.credential_path are set
tip

Use vault-ref credentials when multiple bindings share the same upstream API key, or when you have an existing secret rotation workflow. Changes to the vault secret are reflected immediately — no manual credential rotation needed.

Executing a request

curl -X POST "https://api.1claw.xyz/v1/agents/$AGENT_ID/execute" \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"binding": "stripe-api",
"intent_type": "http",
"params": {
"method": "GET",
"path": "/v1/customers?limit=10"
}
}'

Binding types

TypeTierDescription
httpProREST API calls with credential injection
graphqlProGraphQL queries/mutations
postgresTeam+PostgreSQL queries
mysqlTeam+MySQL queries
redisTeam+Redis commands
grpcTeam+gRPC calls
smtpTeam+Email sending
cloud_sdkTeam+Cloud provider SDK calls
s3Team+S3-compatible storage operations
customTeam+Custom integrations

Binding lifecycle

OperationEndpointSDK
CreatePOST /v1/agents/{id}/bindingsclient.bindings.create(agentId, data)
ListGET /v1/agents/{id}/bindingsclient.bindings.list(agentId)
GetGET /v1/agents/{id}/bindings/{bid}client.bindings.get(agentId, bindingId)
UpdatePATCH /v1/agents/{id}/bindings/{bid}client.bindings.update(agentId, bindingId, data)
DeleteDELETE /v1/agents/{id}/bindings/{bid}client.bindings.delete(agentId, bindingId)
TestPOST /v1/agents/{id}/bindings/{bid}/testclient.bindings.test(agentId, bindingId)
Rotate credentialPOST /v1/agents/{id}/bindings/{bid}/rotate-credentialclient.bindings.rotateCredential(agentId, bindingId, { credential })
ExecutePOST /v1/agents/{id}/executeclient.bindings.execute(agentId, data)
List executionsGET /v1/agents/{id}/executionsclient.bindings.listExecutions(agentId)

Binding responses include credential_set (boolean) so you can confirm a credential is stored without ever exposing the value. Deleting a binding purges the stored credential.

GraphQL example

curl -X POST "https://api.1claw.xyz/v1/agents/$AGENT_ID/execute" \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"binding": "github-graphql",
"intent_type": "graphql",
"params": {
"query": "query { viewer { login } }"
}
}'

The GraphQL executor POSTs { query, variables, operationName }, surfaces errors[] from the upstream API, and uses introspection for connectivity tests.

Agent execution guardrails

Set per-agent limits with execution_guardrails (JSON) on create/update:

{
"allowed_hosts": ["api.stripe.com"],
"allowed_binding_types": ["http", "graphql"],
"max_duration_ms": 15000,
"max_requests_per_minute": 30
}

At execute time the server enforces the strictest of binding-level and agent-level guardrails. Violations are recorded as denied in execution_events.

MCP tools

ToolDescription
execute_httpHTTP request through a binding (binding, method, path, optional body/headers)
execute_intentGeneric execute (binding, intent_type, params) — HTTP, GraphQL, etc.
list_bindingsList bindings for the current agent
create_bindingCreate a binding (human-only; privileged)
test_bindingConnectivity test (same SSRF/allowlist checks as execute)
list_executionsRecent execution events for the agent

CLI

1claw agent binding create <agent-id> --name stripe-api --type http \
--config '{"base_url":"https://api.stripe.com","auth_type":"bearer","allowed_hosts":["api.stripe.com"]}' \
--credential sk_live_...
1claw agent binding list <agent-id>
1claw agent binding test <agent-id> <binding-id>
1claw agent binding rotate-credential <agent-id> <binding-id> --credential sk_live_new_...
1claw agent binding execute <agent-id> --binding stripe-api --intent-type http \
--params '{"method":"GET","path":"/v1/customers?limit=5"}'
1claw agent binding executions <agent-id>

Enable on the agent: 1claw agent update <id> --execution-intents true --execution-guardrails '{"max_requests_per_minute":30}'

Security model

  • Credentials never exposed: Binding credentials are stored in the __agent-keys vault at agents/{id}/bindings/{name}. Agents cannot read them directly. Responses use credential_set, not the secret value.
  • SSRF protection: validate_audience_url blocks requests to cloud metadata endpoints, private CIDRs, and internal hostnames. Connectivity tests use the same checks as execute.
  • Host and path allowlists: Each binding defines allowed_hosts and optional allowed_paths (trailing-* wildcard). Agent execution_guardrails.allowed_hosts can further restrict destinations.
  • Binding type gating: Agent execution_guardrails.allowed_binding_types is enforced at execute time, not only at create.
  • Audit trail: Every execution is recorded in execution_events with sanitized request/response metadata (success / error / denied). Only successful runs count toward the monthly quota.
  • Execution surface: Execute responses include execution_surface: vault (default) or tee when a Shroud execution endpoint is configured and execution_mode: "tee" is requested.
  • TEE mode (Business+): Optional TEE execution inside Shroud's confidential enclave. Set ONECLAW_EXECUTION_TEE_REQUIRE_SHROUD=true to return 501 when TEE is requested but no enclave endpoint is configured (fail-closed).