Send, Swap, and Receive
Embedded wallet users move funds through treasury wallet endpoints. Every send and swap runs validate_wallet_send() against effective spend policies before signing. Step-up authentication is required: account password (X-Auth-Confirm) or passkey tx token.
These endpoints reject agent JWTs with 403. Your backend should call them with the end-user's JWT, or use the React widget which holds the user session.
Send native currency
- TypeScript
- curl
const { data } = await client.treasuryWallets.sendFromWallet(
"ethereum",
{
to: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
amount: "0.01", // major units (ETH, SOL, BTC, …)
},
userPassword, // X-Auth-Confirm
);
console.log(data.tx_hash, data.status);
curl -X POST "https://api.1claw.xyz/v1/treasury/wallets/ethereum/send" \
-H "Authorization: Bearer $USER_JWT" \
-H "Content-Type: application/json" \
-H "X-Auth-Confirm: $USER_PASSWORD" \
-d '{
"to": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"value_wei": "0.01"
}'
The REST API uses value_wei (major-unit decimal string for non-EVM chains per OpenAPI). The @1claw/sdk sendFromWallet() helper accepts amount and maps it for you.
EVM token transfers
Pass token_contract (ERC-20) or use token_mint on non-EVM chains:
await client.treasuryWallets.sendFromWallet(
"ethereum",
{
to: "0xRecipient...",
amount: "100.0",
token_contract: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
},
userPassword,
);
Chain-specific fields
| Chain | Extra fields |
|---|---|
| Bitcoin | fee_rate_sat_per_vbyte |
| Solana | token_mint, memo |
| XRP | destination_tag, xrpl_tx_json |
| Cardano | token_mint (policy.asset), ttl |
| Tron | token_mint, fee_limit_sun |
Amounts are major-unit decimal strings (e.g. "0.001" BTC, "10.5" SOL).
Gasless sends (ERC-4337)
On EVM chains with Pimlico configured, wrap the send as a sponsored UserOperation:
await client.treasuryWallets.sendFromWallet(
"ethereum",
{
to: "0x...",
amount: "0.01",
gasless: true,
},
userPassword,
);
Response may include user_op_hash. Users do not need native ETH for gas; the paymaster sponsors fees. Supported on Ethereum, Base, Optimism, Arbitrum, and Polygon when RPC + paymaster are configured.
// wallet-react
await send({ chain: "ethereum", to: "0x...", amount: "0.01", gasless: true });
Passkey transaction authorization
Alternative to password re-auth — bind WebAuthn to the transaction digest:
// wallet-react — full flow
await sendWithPasskey({
chain: "ethereum",
to: "0x...",
amount: "1.0",
});
Under the hood:
- Client computes
tx_digest = SHA256(chain|to|value_wei|data) - Passkey ceremony via
/v1/auth/passkeys/tx-assert/begin+.../complete - Send with
X-Passkey-Tokenheader instead ofX-Auth-Confirm
Manual API usage mirrors the widget; see Authentication.
Swap via 0x
Swaps fetch quotes from the 0x aggregator, sign, and broadcast server-side. Requires ZERO_X_API_KEY on Vault.
const { data } = await client.treasuryWallets.swapFromWallet(
"ethereum",
{
sell_token: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", // ETH
buy_token: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC
sell_amount: "0.1",
slippage_percentage: "0.5",
},
userPassword,
);
console.log(data.tx_hash, data.buy_amount);
Spend policies apply to swaps the same as sends (allowed_tokens, daily limits, etc.).
Receive
Receiving is address-based — no dedicated API call:
- List wallets:
GET /v1/treasury/walletsor widget Receive view - Display
address(and chain-specific memo/tag for XRP) - Optionally create deposit destinations for tracked inbound payments + webhooks
The widget's Receive feature shows QR codes and copyable addresses per chain.
Policy violations
When a send or swap violates spend policy, the API returns 403 with a descriptive error (e.g. destination not in allowlist, daily limit exceeded). The React widget surfaces this as a toast — it never attempts to sign blocked transactions.
Users can inspect effective policy:
const { data } = await client.treasuryWallets.getEffectiveSpendPolicy();
console.log(data.source); // e.g. app default vs user override when present
Audit & webhooks
Successful sends emit audit events (treasury_wallet.send) and webhooks when configured:
wallet.transfer.sentwallet.transfer.received(deposit monitoring)
See Platform webhooks.
Related
- Spend policies — guardrail fields
- Multi-chain wallets — balances
- Fiat ramps — on-ramp into receive address
- Account abstraction — ERC-4337 details