Describe the outcome
Keep funding and execution separate in the request:tokenRequests are not calldata. Add them when a call needs tokens delivered to the target chain. Omit them for a gas-only call that does not need assets delivered. For a token-only swap with no calls, see Make a swap. Do not add dummy calldata or a self-transfer to a request that does not need a call.
Define the calls
This example sends 100 USDC to a recipient on Arbitrum, funded with USDC from the account on Base. Both wallet types use the same calldata:Send the transaction
- Embedded wallet
- Custom signer
Use the initialized Keep
oneAuth client and authenticated accountAddress from Accounts. sendIntent() prepares the quote, requests passkey approval, and submits the intent:result.intentId for status checks.Embedded wallets use numeric chain IDs and tokenRequests[].token. sourceChainId restricts funding to Base; sourceAssets restricts the input token to USDC. To let the wallet choose across available mainnet balances, omit both source constraints and keep tokenRequests. A call with neither tokenRequests nor sourceAssets defaults to target-chain funding unless you set sourceChainId.The default is sponsorshipMode: "required". See Sponsor fees for user-paid quotes and fallback behavior. Set experimental_clear_signing: true for prepared-action review. The end-to-end flow covers closeOn: "completed" and waitForHash: true without repeating them in every request.Embedded wallets have no separate recipient field for this flow. Encode the payment recipient in the transfer call, as shown above.Batch calls
Pass multiple calls tosendIntent() for an atomic destination batch. They target one chain, execute in order, and all revert when any call fails. Use this for dependent actions such as approve then deposit.sendBatchIntent() instead authorizes several separate intents with one passkey ceremony. Each intent has its own submission and outcome, so they can succeed or fail independently. Do not use it when the operations must be atomic.